Added system for conditional follower messages.

This commit is contained in:
Ariel A 2022-05-01 17:56:39 -04:00
parent 9993f72186
commit 831c73c18c
11 changed files with 688 additions and 173 deletions

View File

@ -27,7 +27,6 @@ callfunc ScrFunc_emote
EventScript_Follower::
lock
faceplayer
bufferlivemonspeciesname 0
playfirstmoncry
callfunc ScrFunc_getfolloweraction
@ -56,6 +55,8 @@ EventScript_FollowerLovesYou::
@ Message address must be loaded into bank 0
EventScript_FollowerGeneric:: @ similar to Std_MsgboxDefault
faceplayer
EventScript_FollowerGenericSkipFace:
waitfieldeffect FLDEFF_EMOTE
message 0x0
waitmessage
@ -63,6 +64,7 @@ EventScript_FollowerGeneric:: @ similar to Std_MsgboxDefault
return
EventScript_FollowerJump::
faceplayer
applymovement 0xFE FollowerSplashMovement
waitmovement 0xFE
waitfieldeffect FLDEFF_EMOTE
@ -403,6 +405,7 @@ FollowerDance:
@ Movement scripts
EventScript_FollowerIsShivering::
faceplayer
compare VAR_FACING, DIR_NORTH
call_if_eq ShiverVertical
compare VAR_FACING, DIR_SOUTH
@ -429,6 +432,7 @@ EventScript_FollowerNostalgia::
goto EventScript_FollowerGeneric
EventScript_FollowerHopping::
faceplayer
applymovement 0xFE FollowerSkippingMovement
waitmovement 0xFE
goto EventScript_FollowerGeneric
@ -454,6 +458,7 @@ JumpOnW:
return
EventScript_FollowerJumpOnPlayer::
faceplayer
compare VAR_FACING, DIR_NORTH
call_if_eq JumpOnS
compare VAR_FACING, DIR_SOUTH
@ -485,6 +490,7 @@ CuddleW:
return
EventScript_FollowerCuddling:: @ similar to Std_MsgboxDefault
faceplayer
compare VAR_FACING, DIR_NORTH
call_if_eq CuddleS
compare VAR_FACING, DIR_SOUTH
@ -524,6 +530,7 @@ ShCuddleW:
return
EventScript_FollowerShiverCuddling::
faceplayer
compare VAR_FACING, DIR_NORTH
call_if_eq ShCuddleS
compare VAR_FACING, DIR_SOUTH
@ -555,6 +562,7 @@ CreepCloserW:
return
EventScript_FollowerGetCloser::
faceplayer
compare VAR_FACING, DIR_NORTH
call_if_eq CreepCloserS
compare VAR_FACING, DIR_SOUTH
@ -586,6 +594,7 @@ PokePlayerW:
return
EventScript_FollowerPokingPlayer::
faceplayer
compare VAR_FACING, DIR_NORTH
call_if_eq PokePlayerS
compare VAR_FACING, DIR_SOUTH
@ -604,19 +613,20 @@ EventScript_FollowerLookAround::
EventScript_FollowerLookAway::
applymovement 0xFE FollowerLookAway
waitmovement 0xFE
goto EventScript_FollowerGeneric
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerLookAwayBark::
applymovement 0xFE FollowerLookAwayBark
waitmovement 0xFE
goto EventScript_FollowerGeneric
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerLookAwayPoke::
applymovement 0xFE FollowerLookAwayPokeG
waitmovement 0xFE
goto EventScript_FollowerGeneric
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerPokeGround::
faceplayer
applymovement 0xFE FollowerPokeGround
waitmovement 0xFE
goto EventScript_FollowerGeneric
@ -624,17 +634,17 @@ EventScript_FollowerPokeGround::
EventScript_FollowerStartled::
applymovement 0xFE FollowerStartled
waitmovement 0xFE
goto EventScript_FollowerGeneric
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerFastHopping::
applymovement 0xFE FollowerHopFast
waitmovement 0xFE
goto EventScript_FollowerGeneric
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerDizzy::
applymovement 0xFE FollowerDizzy
waitmovement 0
goto EventScript_FollowerGeneric
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerLookAroundScared::
applymovement 0xFE FollowerLookAroundScared
@ -642,6 +652,35 @@ EventScript_FollowerLookAroundScared::
goto EventScript_FollowerGeneric
EventScript_FollowerDance::
faceplayer
applymovement 0xFE FollowerDance
waitmovement 0
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerFaceUp::
applymovement 0xFE Common_Movement_FaceUp
waitmovement 0xFE
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerFaceResult:: @ Face towards direction in VAR_RESULT
switch VAR_RESULT
case DIR_SOUTH, EventScript_FollowerFaceDown
case DIR_NORTH, EventScript_FollowerFaceUp
case DIR_WEST, EventScript_FollowerFaceLeft
case DIR_EAST, EventScript_FollowerFaceRight
goto EventScript_FollowerGeneric
EventScript_FollowerFaceDown:
applymovement 0xFE Common_Movement_FaceDown
waitmovement 0xFE
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerFaceLeft:
applymovement 0xFE Common_Movement_FaceLeft
waitmovement 0xFE
goto EventScript_FollowerGenericSkipFace
EventScript_FollowerFaceRight:
applymovement 0xFE Common_Movement_FaceRight
waitmovement 0xFE
goto EventScript_FollowerGenericSkipFace

View File

@ -1,102 +1,94 @@
Happy (Special):
Specific map:
{STR_VAR_1} greeted your mom.
Your pokemon is staring intently at the mountain peak.
{STR_VAR_1} is staring straight at the pokemon league.
{STR_VAR_1} is staring at the sea.
Landscape/map feature:
{STR_VAR_1} greeted everyone!
{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):
(CELEBI) danced happily ( Pokemon Exclusive ).
(CELEBI) danced beautiful ( Pokemon Exclusive ).
Sniff sniff, something smells good! ( Day care center ).
{STR_VAR_1} seems dazzled after seeing the sky.
Your pokemon is surveying the shelves restlessly ( In pokemart ).
Your pokemon is smelling the scent of the flowers. (When next to flowers in Cherrygrove City).
Your pokemon is staring intently at the sea! (On the beach).
Specific map:
Why is it doing warm-up exercises? (Cerulean Gym).
{STR_VAR_1} is running along the side of the pool! (Cerulean Gym).
{STR_VAR_1} is vigorously producing fire (must be a fire type).
{STR_VAR_1} spat fire (must be a fire type).
{STR_VAR_1} is staring intently at the shelves.
(TYPHLOSION) emitted fire and shouted ( Pokemon Exclusive ).
{STR_VAR_1} is vigorously breathing fire ( must be fire type).
(MAGIKARP) is leaping around more than usual (lake of rage, During team rockets broadcast) ( Pokemon Exclusive ).
Map feature:
Your pokemon is smelling the scent of the flowers. (When next to flowers in Cherrygrove City).
{STR_VAR_1} Greeted Slowbro (Cerulean city, in front of Slowbro).
{STR_VAR_1} seems happy to have taken a shower! (Celadon gym) (Grass,Water type).
{STR_VAR_1} is fidgeting in front of everyone (maybe baby pokemon).
{STR_VAR_1} roared!
Your pokemon is staring intently at the sea!
{STR_VAR_1} is looking at the surging sea.
{STR_VAR_1} is playing on the sand.
{STR_VAR_1} is staring fixedly at the sea.
{STR_VAR_1} Cried out, looking at the tall mountain!
{STR_VAR_1} is stomping on the grass!
{STR_VAR_1} seems highly interested in the tree.
{STR_VAR_1} is playing around, Picking bits of grass.
{STR_VAR_1} seems highly interested in the tree.
{STR_VAR_1} is looking outside and frolicking!
Pokemon exclusive:
(MAGIKARP) is leaping around more than usual (lake of rage, During team rockets broadcast) ( Pokemon Exclusive ).
Pokemon feature:
{STR_VAR_1} seems happy to have taken a shower! (Celadon gym) (Grass,Water type).
Misc:
{STR_VAR_1} seems dazzled after seeing the sky.
{STR_VAR_1} is fidgeting in front of everyone (maybe baby pokemon).
{STR_VAR_1} roared!
{STR_VAR_1} spun around in a circle!
Sad (Special):
{STR_VAR_1}'s burn looks painful! (when burnt).
Pokemon feature:
Upset (Special):
{STR_VAR_1} is taking shelter in the grass from the rain.
{STR_VAR_1} is splashing around in the wet grass.
Specific map(s):
It seems to have eaten something strange. It's making an odd face... (Olivine Cafe).
{STR_VAR_1} is staring at the crumbling floor (burnt tower).
{STR_VAR_1} seems to think that (Player) has disappeared! ( Morty's Gym ).
{STR_VAR_1} seems to feel a little claustrophobic.
{STR_VAR_1} is a bit nervous about the narrow space!
{STR_VAR_1} is splashing around in the grass (must be fire type).
Map feature:
{STR_VAR_1} is splashing around in the wet grass.
Pokemon feature:
Your pokemon doesn't like splashing around on the ground (must be fire type).
{STR_VAR_1} seems very cold (when frozen).
Misc:
{STR_VAR_1} seems to feel a little claustrophobic.
{STR_VAR_1} is a bit nervous about the narrow space!
{STR_VAR_1} seems uneasy and is poking (PLAYER).
{STR_VAR_1} is trembling with fear (Cemetery).
{STR_VAR_1} seems somehow sad... (Cemetery).
{STR_VAR_1} is growling softly (Dragon type in Dragons Den).
Angry (Special):
Map feature:
{STR_VAR_1} is staring at the Persian statue and glaring.
{STR_VAR_1} is glaring at the PERSIAN statue!
{STR_VAR_1} is glaring at your foe!
{STR_VAR_1} is intimidating your foe!
Pensive (Special):
{STR_VAR_1} is staring intently at the goods on display!
{STR_VAR_1} is staring at its reflection in the water.
{STR_VAR_1} is staring intently at the reflection of its face.
{STR_VAR_1} is gnawing at the ice.
{STR_VAR_1} seems interested in Amphy...
{STR_VAR_1} has a sleepy look on its face... (Near Jigglypuff in Radio Tower.).
{STR_VAR_1} seems to relax as it hears the sound of rustling leaves...
Specific map(s):
{STR_VAR_1} seems to be listening to the sound of rustling leaves.
Your pokemon turned to face the other way, showing a defiant expression.
{STR_VAR_1} is preoccupied by the ceiling, which seems like it may collapse (burnt tower).
{STR_VAR_1} focused with a sharp gaze! (On the way to Victory Road.).
{STR_VAR_1} emitted fire and shouted! (must be a fire type).
{STR_VAR_1} is concerned about the swaying pillar (sprout tower).
Your pokemon is drooling a little (Olivine Cafe).
{STR_VAR_1} seems very interested in the bicycles (bike shop).
{STR_VAR_1} is preoccupied by the floor, which seems like it may collapse (burnt tower).
{STR_VAR_1} is nervous ( in a gym before beating gym leader ) ( must have type disadvantage ).
Map feature:
{STR_VAR_1} is staring intently at the reflection of its face.
{STR_VAR_1} seems interested in Amphy...
{STR_VAR_1} has a sleepy look on its face... (Near Jigglypuff in Radio Tower.).
Misc:
Your pokemon turned to face the other way, showing a defiant expression.
Music (Special):
Map feature:
{STR_VAR_1} is pulling out the grass.
Waah! your pokemon suddenly splashed water! (on a shore).
{STR_VAR_1} is happy to see what's out doors!
{STR_VAR_1} seems to want to touch the machine! (Power plant).
{STR_VAR_1} is listening intently to the sound of the waves.
{STR_VAR_1} is swaying with the boat!
{STR_VAR_1} is dancing along with the rolling of the ship.
{STR_VAR_1} doesn't want to get off the boat yet!
{STR_VAR_1} is listening to the sound of the machine.
{STR_VAR_1} seems happy at the sight of water on the window!
Your pokemon is blowing sand in the air!
Your pokemon is staring spellbound at the night sky!
Your pokemon seems to be enjoying sliding around!
{STR_VAR_1} is touching the ice.
{STR_VAR_1} is steadily observing the flow of the river.
{STR_VAR_1} is noticing the scent of the grass.
{STR_VAR_1} is playing around, plucking bits of grass.
Misc:
{STR_VAR_1} seems happy at the sight of water on the window!
{STR_VAR_1} is looking up at the ceiling.
{STR_VAR_1} seems to be enjoying this a little bit!
{STR_VAR_1} is wandering around enjoying the forest scenery.
@ -104,25 +96,20 @@ Your pokemon seems to be enjoying sliding around!
{STR_VAR_1} is playing around with a leaf.
{STR_VAR_1} is playing around, touching the leaves.
Your pokemon is happily gazing at the beautiful, starry sky!
{STR_VAR_1} is pulling out the grass.
{STR_VAR_1} is rolling around in the grass.
{STR_VAR_1} seems to want to return to the lab (after you receive the Mystery egg).
Your pokemon is staring at the various items.
{STR_VAR_1} is listening to the sound of the waterfall ( Mt. Mortar).
{STR_VAR_1} is looking up the tall mountain... (Mt. Mortar).
{STR_VAR_1} seems concerned about the waterfall.
{STR_VAR_1} is sniffing around the room. (Inside Hero's Room).
{STR_VAR_1} is dancing around the pillar! (Seems to occur more for Bellsprout)(sprout tower).
{STR_VAR_1} swayed around, dancing in a strange manner.(Seems to occur more for Bellsprout)(sprout tower).
{STR_VAR_1} swayed and danced around as it pleased (Seems to occur more for Bellsprout)(sprout tower).
Your Pokemon is happily looking at (Player)'s footprints! (Sandy area).
Your Pokemon is playing around and splashing in the water! (Water's edge).
Your Pokemon is blowing sand in the air! (Sandy area).
{STR_VAR_1} is looking up at the sky.
{STR_VAR_1} is poking at garbage (Goldenrods underground path).
Your pokemon is rolling a screw from a bicycle around.
{STR_VAR_1} is looking up at the sky.
{STR_VAR_1} seems to be happy about the rain! ( during rain, must not have type disadvantage to water).
{STR_VAR_1} is clawing the grass!
{STR_VAR_1} is looking around restlessly at the Forest.
{STR_VAR_1} is playfully nibbling at the ground.
@ -136,7 +123,6 @@ Your pokemon is rolling a screw from a bicycle around.
{STR_VAR_1} is gazing restlessly at the building ( in goldenrod).
Surprised (Special):
Your pokemon has a flower petal on its face! (Newbark Town).
{STR_VAR_1} seems to have gotten caught in the clumps of grass.
{STR_VAR_1} slipped on the floor and seems likely to fall!
Your pokemon is very concerned about the room below ( Burnt tower ).
@ -144,19 +130,14 @@ Careful! seems like the floor could collapse, and it might fall.
{STR_VAR_1} seems to think that (Player) has disappeared! ( Morty's Gym ).
{STR_VAR_1} gazed surprisingly at the rock!
Huh? your pokemon found something in top of the mountain ( outside Mt. Mortar) (!).
{STR_VAR_1} is cautious about the confined area!
{STR_VAR_1} got tangled up in the branches and almost fell down!
{STR_VAR_1} looked up at the sky and shouted loudly.
{STR_VAR_1} seems to have found something!
{STR_VAR_1} is feeling nervous and a touch claustrophobic. (while inside an elevator).
{STR_VAR_1} almost forgot it was holding that (Held item).
{STR_VAR_1} is happy at the sight of the water on the window!
{STR_VAR_1} was surprised by the sounds in the thicket!
Seems the breeze is coming from here.
Oh! its slipping and came over here for support (on ice).
Your pokemon almost slipped and fell over! (on ice).
A cold wind suddenly blew by!
Your pokemon seems surprised to touch ice. (TODO: Regice)
{STR_VAR_1} seems to have gotten a bit of zap! (Power plant).
{STR_VAR_1} is dazzled by the shiny brightness of the bridge! (Standing on Nugget Bridge).
{STR_VAR_1} is slipping on the water and almost fell over!

View File

@ -34,17 +34,17 @@ def prepare_string(s):
# Exports up to n messages in C format to outfile
def export_messages(infile, outfile, n=None, indent=2):
def export_messages(infile, outfile, n=None, indent=0, start=0):
with open(infile, 'r') as f_in:
lines = f_in.readlines()
if n is not None:
lines = lines[:n]
with open(outfile, 'w') as f_out:
codelines = [' '*indent + f'(const char []) _("{prepare_string(s)}"),' for s in lines]
codelines = [' '*indent + f'static const u8 sCondMsg{start+i:02d}[] = _("{prepare_string(s)}");' for i, s in enumerate(lines)]
f_out.write('\n'.join(codelines))
print(f'{len(lines)} lines written')
return len(lines)
if __name__ == '__main__':
export_messages('emotions.txt', 'emotions.h', n=15)
export_messages('emotions.txt', 'emotions.h', n=1, start=7)

View File

@ -9,6 +9,7 @@
#define WINDOW_BG1 (1 << 7)
void AI_CalcDmg(u8 battlerIdAtk, u8 battlerIdDef);
s32 GetTypeEffectiveness(struct Pokemon *mon, u8 moveType);
u8 TypeCalc(u16 move, u8 battlerIdAtk, u8 battlerIdDef);
u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility);
u8 GetBattlerTurnOrderNum(u8 battlerId);

View File

@ -24,6 +24,8 @@ extern const u8 EventScript_FollowerFastHopping[];
extern const u8 EventScript_FollowerDizzy[];
extern const u8 EventScript_FollowerLookAroundScared[];
extern const u8 EventScript_FollowerDance[];
extern const u8 EventScript_FollowerFaceUp[];
extern const u8 EventScript_FollowerFaceResult[];
extern const u8 EnterPokeballMovement[];
extern const u8 EventScript_TestSignpostMsg[];

71
include/follower_helper.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef GUARD_FOLLOWER_HELPER_H
#define GUARD_FOLLOWER_HELPER_H
enum {
FOLLOWER_EMOTION_HAPPY = 0,
FOLLOWER_EMOTION_NEUTRAL, // Also called "No emotion"
FOLLOWER_EMOTION_SAD,
FOLLOWER_EMOTION_UPSET,
FOLLOWER_EMOTION_ANGRY,
FOLLOWER_EMOTION_PENSIVE,
FOLLOWER_EMOTION_LOVE,
FOLLOWER_EMOTION_SURPRISE,
FOLLOWER_EMOTION_CURIOUS,
FOLLOWER_EMOTION_MUSIC,
FOLLOWER_EMOTION_POISONED,
FOLLOWER_EMOTION_LENGTH,
};
struct __attribute__((packed)) FollowerMsgInfoExtended {
const u8 *text;
const u8 *script;
union __attribute__((packed)) {
u16 species:10;
struct __attribute__((packed)) {
u16 type1:5;
u16 type2:5; // if >= NUMBER_OF_MON_TYPES, inverts checking for type1
} types;
u16 status:10;
} st;
u16 stFlags:2; // 0 = no matching, 1 = species matching, 2 = type matching, 3 = status
u16 emotion:4; // emotion for this message
union __attribute__((packed)) {
struct __attribute__((packed)) {
u16 mapSec:8;
} mapSec;
struct __attribute__((packed)) {
u16 mapNum:8;
u16 mapGroup:6;
} map;
struct __attribute__((packed)) {
u16 behavior1:8;
u16 behavior2:6; // not full; only goes up to 0x3F
} mb;
} mm;
u16 mmFlags:2; // 1 = map sec, 2 = map, 3 = metatile behavior
union __attribute__((packed)) {
struct __attribute__((packed)) {
u16 weather1:5;
u16 weather2:5;
} weather;
u16 song:10;
u16 timeOfDay:10;
} wt;
u16 wtFlags:2; // 1 = weather matching, 2 = song, 3 = time
u16 weight:3;
u16 textSpread:1; // if set, `text` is an array of texts instead
union __attribute__((packed)) {
struct __attribute__((packed)) {
u16 behavior:8;
u16 distance:6;
} mb;
} near;
u16 nearFlags:2; // 1 = mb within '+' shape distance away
};
extern const struct FollowerMsgInfoExtended gFollowerConditionalMessages[];
#endif //GUARD_FOLLOWER_HELPER_H

View File

@ -114,6 +114,7 @@ SECTIONS {
src/field_door.o(.text);
src/field_player_avatar.o(.text);
src/event_object_movement.o(.text);
src/follower_helper.o(.text);
src/field_message_box.o(.text);
src/event_object_lock.o(.text);
src/text_window.o(.text);
@ -498,6 +499,7 @@ SECTIONS {
src/field_door.o(.rodata);
src/field_player_avatar.o(.rodata);
src/event_object_movement.o(.rodata);
src/follower_helper.o(.rodata);
src/text_window.o(.rodata);
src/scrcmd.o(.rodata);
src/field_control_avatar.o(.rodata);

View File

@ -1350,6 +1350,62 @@ static void ModulateDmgByType(u8 multiplier)
}
}
s32 GetTypeEffectiveness(struct Pokemon *mon, u8 moveType) {
u16 species = GetMonData(mon, MON_DATA_SPECIES);
u8 type1 = gBaseStats[species].type1;
u8 type2 = gBaseStats[species].type2;
s32 i = 0;
u8 multiplier;
s32 flags = 0;
if (GetMonAbility(mon) == ABILITY_LEVITATE && moveType == TYPE_GROUND)
return MOVE_RESULT_NOT_VERY_EFFECTIVE;
while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) {
if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) {
i += 3;
continue;
}
else if (TYPE_EFFECT_ATK_TYPE(i) == moveType) {
// check type1
if (TYPE_EFFECT_DEF_TYPE(i) == type1)
multiplier = TYPE_EFFECT_MULTIPLIER(i);
else if (TYPE_EFFECT_DEF_TYPE(i) == type2 && type1 != type2)
multiplier = TYPE_EFFECT_MULTIPLIER(i);
else {
i += 3;
continue;
}
switch (multiplier)
{
case TYPE_MUL_NO_EFFECT:
flags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE;
flags &= ~MOVE_RESULT_SUPER_EFFECTIVE;
break;
case TYPE_MUL_NOT_EFFECTIVE:
if (!(flags & MOVE_RESULT_NO_EFFECT))
{
if (flags & MOVE_RESULT_SUPER_EFFECTIVE)
flags &= ~MOVE_RESULT_SUPER_EFFECTIVE;
else
flags |= MOVE_RESULT_NOT_VERY_EFFECTIVE;
}
break;
case TYPE_MUL_SUPER_EFFECTIVE:
if (!(flags & MOVE_RESULT_NO_EFFECT))
{
if (flags & MOVE_RESULT_NOT_VERY_EFFECTIVE)
flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE;
else
flags |= MOVE_RESULT_SUPER_EFFECTIVE;
}
break;
}
}
i += 3;
}
return flags;
}
static void Cmd_typecalc(void)
{
s32 i = 0;
@ -9466,7 +9522,7 @@ static void Cmd_switchoutabilities(void)
{
case ABILITY_NATURAL_CURE:
gBattleMons[gActiveBattler].status1 = 0;
BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE,
BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE,
gBitTable[*(gBattleStruct->battlerPartyIndexes + gActiveBattler)],
sizeof(gBattleMons[gActiveBattler].status1),
&gBattleMons[gActiveBattler].status1);

View File

@ -16,6 +16,7 @@ extern const u8 EventScript_FollowerFastHopping[];
extern const u8 EventScript_FollowerDizzy[];
extern const u8 EventScript_FollowerLookAroundScared[];
extern const u8 EventScript_FollowerDance[];
extern const u8 EventScript_FollowerLookUp[];
// 'Generic', unconditional happy messages
static const u8 sHappyMsg00[] = _("{STR_VAR_1} began poking you in the\nstomach.");
@ -29,9 +30,9 @@ static const u8 sHappyMsg07[] = _("{STR_VAR_1} put in extra effort.");
static const u8 sHappyMsg08[] = _("{STR_VAR_1} is smelling the scents\nof the surrounding air.");
static const u8 sHappyMsg09[] = _("{STR_VAR_1} is jumping for joy!");
static const u8 sHappyMsg10[] = _("{STR_VAR_1} is still feeling great!");
static const u8 sHappyMsg11[] = _("Your pokemon has caught the scent of\nsmoke.");
static const u8 sHappyMsg11[] = _("Your POKéMON has caught the scent of\nsmoke.");
static const u8 sHappyMsg12[] = _("{STR_VAR_1} is poking at your belly.");
static const u8 sHappyMsg13[] = _("Your pokemon stretched out its body\nand is relaxing.");
static const u8 sHappyMsg13[] = _("Your POKéMON stretched out its body\nand is relaxing.");
static const u8 sHappyMsg14[] = _("{STR_VAR_1} looks like it wants to\nlead!");
static const u8 sHappyMsg15[] = _("{STR_VAR_1} is doing it's best to\nkeep up with you.");
static const u8 sHappyMsg16[] = _("{STR_VAR_1} is happily cuddling up\nto you!");
@ -45,12 +46,13 @@ static const u8 sHappyMsg23[] = _("{STR_VAR_1} looks very interested.");
static const u8 sHappyMsg24[] = _("{STR_VAR_1} is somehow forcing\nitself to keep going.");
static const u8 sHappyMsg25[] = _("{STR_VAR_1} gave you a sunny look!");
static const u8 sHappyMsg26[] = _("{STR_VAR_1} gives you a happy look\nand a smile.");
static const u8 sHappyMsg27[] = _("Your pokemon is smelling the scent\nof flowers.");
static const u8 sHappyMsg27[] = _("Your POKéMON is smelling the scent\nof flowers.");
static const u8 sHappyMsg28[] = _("{STR_VAR_1} seems very happy to see\nyou!");
static const u8 sHappyMsg29[] = _("{STR_VAR_1} faced this way and\ngrinned.");
static const u8 sHappyMsg30[] = _("{STR_VAR_1} happily cuddled up to\nyou!");
// Conditional messages begin here, index 31
static const u8 sHappyMsg31[] = _("Your pokemon seems happy about the\ngreat weather.");
static const u8 sHappyMsg31[] = _("Your POKéMON seems happy about the\ngreat weather.");
static const u8 sHappyMsg32[] = _("{STR_VAR_1} is very composed and\nsure of itself!");
const struct FollowerMsgInfo gFollowerHappyMessages[] = {
{sHappyMsg00, EventScript_FollowerPokingPlayer},
@ -66,7 +68,7 @@ const struct FollowerMsgInfo gFollowerHappyMessages[] = {
{sHappyMsg19, EventScript_FollowerFastHopping},
{sHappyMsg20}, {sHappyMsg21}, {sHappyMsg22}, {sHappyMsg23}, {sHappyMsg24}, {sHappyMsg25}, {sHappyMsg26}, {sHappyMsg27}, {sHappyMsg28}, {sHappyMsg29},
{sHappyMsg30, EventScript_FollowerCuddling},
{sHappyMsg31},
{sHappyMsg31}, {sHappyMsg32},
};
// Unconditional neutral messages
@ -74,8 +76,8 @@ static const u8 sNeutralMsg00[] = _("{STR_VAR_1} is steadily poking at\nthe grou
static const u8 sNeutralMsg01[] = _("{STR_VAR_1} is standing guard.");
static const u8 sNeutralMsg02[] = _("{STR_VAR_1} is staring patiently at\nnothing at all.");
static const u8 sNeutralMsg03[] = _("{STR_VAR_1} is wandering around.");
static const u8 sNeutralMsg04[] = _("Your pokemon yawned loudly!");
static const u8 sNeutralMsg05[] = _("Your pokemon is looking around\nrestlessly.");
static const u8 sNeutralMsg04[] = _("Your POKéMON yawned loudly!");
static const u8 sNeutralMsg05[] = _("Your POKéMON is looking around\nrestlessly.");
static const u8 sNeutralMsg06[] = _("{STR_VAR_1} is looking this way and\nsmiling.");
static const u8 sNeutralMsg07[] = _("{STR_VAR_1} is gazing around\nrestlessly.");
static const u8 sNeutralMsg08[] = _("{STR_VAR_1} let out a battle cry.");
@ -108,18 +110,19 @@ static const u8 sSadMsg02[] = _("{STR_VAR_1} seems a little tired.");
static const u8 sSadMsg03[] = _("{STR_VAR_1} is not happy.");
static const u8 sSadMsg04[] = _("{STR_VAR_1} is going to fall down!\n");
static const u8 sSadMsg05[] = _("{STR_VAR_1} seems to be about to\nfall over!");
static const u8 sSadMsg06[] = _("{STR_VAR_1} is trying very hard to\nkeep up with you...");
static const u8 sSadMsg06[] = _("{STR_VAR_1} is trying very hard to\nkeep up with you…");
static const u8 sSadMsg07[] = _("{STR_VAR_1} is nervous.");
const struct FollowerMsgInfo gFollowerSadMessages[] = {
{sSadMsg00, EventScript_FollowerDizzy},
{sSadMsg01}, {sSadMsg02},
{sSadMsg03}, {sSadMsg04}, {sSadMsg05}, {sSadMsg06},
{sSadMsg03}, {sSadMsg04}, {sSadMsg05}, {sSadMsg06}, {sSadMsg07},
};
// Unconditional upset messages
static const u8 sUpsetMsg00[] = _("{STR_VAR_1} seems unhappy somehow...");
static const u8 sUpsetMsg00[] = _("{STR_VAR_1} seems unhappy somehow");
static const u8 sUpsetMsg01[] = _("{STR_VAR_1} is making an unhappy\nface.");
static const u8 sUpsetMsg02[] = _(".....Your pokemon seems a little\ncold.");
static const u8 sUpsetMsg02[] = _("…Your POKéMON seems a little\ncold.");
// Conditional messages, index 3
static const u8 sUpsetMsg03[] = _("{STR_VAR_1} is taking shelter in the\ngrass from the rain.");
@ -133,7 +136,7 @@ const struct FollowerMsgInfo gFollowerUpsetMessages[] = {
static const u8 sAngryMsg00[] = _("{STR_VAR_1} let out a roar!");
static const u8 sAngryMsg01[] = _("{STR_VAR_1} is making a face like\nits angry!");
static const u8 sAngryMsg02[] = _("{STR_VAR_1} seems to be angry for\nsome reason.");
static const u8 sAngryMsg03[] = _("Your pokemon turned to face the\nother way, showing a defiant\pexpression.");
static const u8 sAngryMsg03[] = _("Your POKéMON turned to face the\nother way, showing a defiant face.");
static const u8 sAngryMsg04[] = _("{STR_VAR_1} cried out.");
const struct FollowerMsgInfo gFollowerAngryMessages[] = {
@ -146,7 +149,7 @@ const struct FollowerMsgInfo gFollowerAngryMessages[] = {
static const u8 sPensiveMsg00[] = _("{STR_VAR_1} is looking down\nsteadily.");
static const u8 sPensiveMsg01[] = _("{STR_VAR_1} is surveying the area.");
static const u8 sPensiveMsg02[] = _("{STR_VAR_1} is peering down.");
static const u8 sPensiveMsg03[] = _("{STR_VAR_1} is somehow fighting off\nsleep...");
static const u8 sPensiveMsg03[] = _("{STR_VAR_1} is somehow fighting off\nsleep");
static const u8 sPensiveMsg04[] = _("{STR_VAR_1} seems to be wandering\naround.");
static const u8 sPensiveMsg05[] = _("{STR_VAR_1} is looking around\nabsentmindedly.");
static const u8 sPensiveMsg06[] = _("{STR_VAR_1} yawned very loudly!");
@ -156,11 +159,11 @@ static const u8 sPensiveMsg09[] = _("{STR_VAR_1} is staring intently at\nyour fa
static const u8 sPensiveMsg10[] = _("{STR_VAR_1} is focusing its\nattention on you.");
static const u8 sPensiveMsg11[] = _("{STR_VAR_1} is staring into the\ndepths.");
static const u8 sPensiveMsg12[] = _("{STR_VAR_1} is sniffing at the\nground.");
static const u8 sPensiveMsg13[] = _("Your pokemon is staring intently at\nnothing.");
static const u8 sPensiveMsg13[] = _("Your POKéMON is staring intently at\nnothing.");
static const u8 sPensiveMsg14[] = _("{STR_VAR_1} focused with a sharp\ngaze!");
static const u8 sPensiveMsg15[] = _("{STR_VAR_1} is concentrating.");
static const u8 sPensiveMsg16[] = _("{STR_VAR_1} faced this way and\nnodded.");
static const u8 sPensiveMsg17[] = _("{STR_VAR_1} seems a bit nervous...");
static const u8 sPensiveMsg17[] = _("{STR_VAR_1} seems a bit nervous");
static const u8 sPensiveMsg18[] = _("{STR_VAR_1} is looking at your\nfootprints.");
static const u8 sPensiveMsg19[] = _("{STR_VAR_1} is staring straight into\nyour eyes.");
@ -206,12 +209,12 @@ static const u8 sSurpriseMsg00[] = _("{STR_VAR_1} is in danger of falling\nover!
static const u8 sSurpriseMsg01[] = _("{STR_VAR_1} bumped into you!");
static const u8 sSurpriseMsg02[] = _("{STR_VAR_1} doesn't seem to be used\nto its own name yet.");
static const u8 sSurpriseMsg03[] = _("{STR_VAR_1} is peering down.");
static const u8 sSurpriseMsg04[] = _("Your pokemon stumbled and nearly\nfell!");
static const u8 sSurpriseMsg04[] = _("Your POKéMON stumbled and nearly\nfell!");
static const u8 sSurpriseMsg05[] = _("{STR_VAR_1} feels something and is\nhowling!");
static const u8 sSurpriseMsg06[] = _("{STR_VAR_1} seems refreshed!");
static const u8 sSurpriseMsg07[] = _("{STR_VAR_1} suddenly turned around\nand started barking!");
static const u8 sSurpriseMsg08[] = _("{STR_VAR_1} suddenly turned around!");
static const u8 sSurpriseMsg09[] = _("Your pokemon was surprised that you\nsuddenly spoke to it!");
static const u8 sSurpriseMsg09[] = _("Your POKéMON was surprised that you\nsuddenly spoke to it!");
static const u8 sSurpriseMsg10[] = _("Sniff sniff, something smells really\ngood!");
static const u8 sSurpriseMsg11[] = _("{STR_VAR_1} feels refreshed.");
static const u8 sSurpriseMsg12[] = _("{STR_VAR_1} is wobbling and seems\nabout to fall over.");
@ -220,7 +223,7 @@ static const u8 sSurpriseMsg14[] = _("{STR_VAR_1} is walking along\ncautiously."
static const u8 sSurpriseMsg15[] = _("{STR_VAR_1} is getting tense with\nnervous energy.");
static const u8 sSurpriseMsg16[] = _("{STR_VAR_1} sensed something strange\nand was surprised!");
static const u8 sSurpriseMsg17[] = _("{STR_VAR_1} is scared and snuggled\nup to you!");
static const u8 sSurpriseMsg18[] = _("{STR_VAR_1} is feeling an unusual\npresence...");
static const u8 sSurpriseMsg18[] = _("{STR_VAR_1} is feeling an unusual\npresence");
static const u8 sSurpriseMsg19[] = _("{STR_VAR_1} is getting tense with\nnervous energy.");
// Conditional messages, index 20
static const u8 sSurpriseMsg20[] = _("{STR_VAR_1} seems to be very\nsurprised that it is raining!");
@ -241,13 +244,13 @@ const struct FollowerMsgInfo gFollowerSurpriseMessages[] = {
};
// Unconditional curious messages
static const u8 sCuriousMsg00[] = _("Your pokemon is looking around\nrestlessly for something.");
static const u8 sCuriousMsg01[] = _("Your pokemon wasn't watching where\nit was going and ran into you!");
static const u8 sCuriousMsg00[] = _("Your POKéMON is looking around\nrestlessly for something.");
static const u8 sCuriousMsg01[] = _("Your POKéMON wasn't watching where\nit was going and ran into you!");
static const u8 sCuriousMsg02[] = _("Sniff, sniff! Is there something\nnearby?");
static const u8 sCuriousMsg03[] = _("{STR_VAR_1} is rolling a pebble\naround playfully.");
static const u8 sCuriousMsg04[] = _("{STR_VAR_1} is wandering around and\nsearching for something.");
static const u8 sCuriousMsg05[] = _("{STR_VAR_1} is sniffing at you.");
static const u8 sCuriousMsg06[] = _("{STR_VAR_1} seems to be a little\nhesitant...");
static const u8 sCuriousMsg06[] = _("{STR_VAR_1} seems to be a little\nhesitant");
const struct FollowerMsgInfo gFollowerCuriousMessages[] = {
{sCuriousMsg00, EventScript_FollowerLookAround},
@ -271,7 +274,7 @@ static const u8 sMusicMsg09[] = _("{STR_VAR_1} is working hard to show\noff its
static const u8 sMusicMsg10[] = _("Whoa! {STR_VAR_1} suddenly danced in\nhappiness!");
static const u8 sMusicMsg11[] = _("{STR_VAR_1} is cheerful!");
static const u8 sMusicMsg12[] = _("{STR_VAR_1} is jumping around in a\ncarefree way!");
static const u8 sMusicMsg13[] = _("Your pokemon seems to be smelling a\nnostalgically familiar scent...");
static const u8 sMusicMsg13[] = _("Your POKéMON seems to be smelling a\nnostalgically familiar scent…");
// Conditional music messages, index 14
static const u8 sMusicMsg14[] = _("{STR_VAR_1} is very happy about the\nrain.");

View File

@ -1,6 +1,7 @@
#include "global.h"
#include "malloc.h"
#include "battle_pyramid.h"
#include "battle_script_commands.h"
#include "berry.h"
#include "data.h"
#include "decoration.h"
@ -15,6 +16,7 @@
#include "field_player_avatar.h"
#include "field_weather.h"
#include "fieldmap.h"
#include "follower_helper.h"
#include "mauville_old_man.h"
#include "metatile_behavior.h"
#include "overworld.h"
@ -23,18 +25,22 @@
#include "random.h"
#include "region_map.h"
#include "script.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
#include "trainer_see.h"
#include "trainer_hill.h"
#include "util.h"
#include "constants/event_object_movement.h"
#include "constants/battle.h"
#include "constants/event_objects.h"
#include "constants/field_effects.h"
#include "constants/items.h"
#include "constants/map_types.h"
#include "constants/mauville_old_man.h"
#include "constants/rgb.h"
#include "constants/region_map_sections.h"
#include "constants/songs.h"
#include "constants/species.h"
#include "constants/trainer_types.h"
#include "constants/union_room.h"
@ -1823,21 +1829,6 @@ static u8 RandomWeightedIndex(u8 *weights, u8 length) {
}
}
enum {
FOLLOWER_EMOTION_HAPPY = 0,
FOLLOWER_EMOTION_NEUTRAL, // Also called "No emotion"
FOLLOWER_EMOTION_SAD,
FOLLOWER_EMOTION_UPSET,
FOLLOWER_EMOTION_ANGRY,
FOLLOWER_EMOTION_PENSIVE,
FOLLOWER_EMOTION_LOVE,
FOLLOWER_EMOTION_SURPRISE,
FOLLOWER_EMOTION_CURIOUS,
FOLLOWER_EMOTION_MUSIC,
FOLLOWER_EMOTION_POISONED,
FOLLOWER_EMOTION_LENGTH,
};
// Pool of "unconditional" follower messages TODO: Should this be elsewhere ?
static const struct FollowerMessagePool followerBasicMessages[] = {
[FOLLOWER_EMOTION_HAPPY] = {gFollowerHappyMessages, EventScript_FollowerGeneric, N_FOLLOWER_HAPPY_MESSAGES},
@ -1877,19 +1868,47 @@ struct SpecialEmote { // Used for storing conditional emotes
u8 emotion;
};
// Find and return direction of metatile behavior within distance
static u32 FindMetatileBehaviorWithinRange(s32 x, s32 y, u32 mb, u8 distance) {
s32 i;
for (i = y+1; i <= y + distance; i++)
if (MapGridGetMetatileBehaviorAt(x, i) == mb)
return DIR_SOUTH;
for (i = y-1; i >= y - distance; i--)
if (MapGridGetMetatileBehaviorAt(x, i) == mb)
return DIR_NORTH;
for (i = x+1; i <= x + distance; i++)
if (MapGridGetMetatileBehaviorAt(i, y) == mb)
return DIR_EAST;
for (i = x-1; i >= x - distance; i--)
if (MapGridGetMetatileBehaviorAt(i, y) == mb)
return DIR_WEST;
return DIR_NONE;
}
// Call an applicable follower message script
bool8 ScrFunc_getfolloweraction(struct ScriptContext *ctx) // Essentially a big switch for follower messages
{
u16 species;
s32 multi;
s16 health_percent;
u8 friendship;
s32 multi, multi2;
struct SpecialEmote cond_emotes[16] = {0};
u8 n_choices = 0;
u8 emotion, n_choices = 0;
struct ObjectEvent *objEvent = GetFollowerObject();
struct Pokemon *mon = GetFirstLiveMon();
u8 emotion;
u8 emotion_weight[FOLLOWER_EMOTION_LENGTH] = {0};
u8 emotion_weight[FOLLOWER_EMOTION_LENGTH] = {
[FOLLOWER_EMOTION_HAPPY] = 10,
[FOLLOWER_EMOTION_NEUTRAL] = 15,
[FOLLOWER_EMOTION_SAD] = 5,
[FOLLOWER_EMOTION_UPSET] = 15,
[FOLLOWER_EMOTION_ANGRY] = 15,
[FOLLOWER_EMOTION_PENSIVE] = 15,
[FOLLOWER_EMOTION_SURPRISE] = 10, // TODO: Scale this with how long the follower has been out?
[FOLLOWER_EMOTION_CURIOUS] = 10, // TODO: Increase this if there is an item nearby?
[FOLLOWER_EMOTION_MUSIC] = 15,
};
u32 i, j;
bool32 pickedCondition = FALSE;
if (mon == NULL) {
ScriptCall(ctx, EventScript_FollowerLovesYou);
return FALSE;
@ -1897,77 +1916,149 @@ bool8 ScrFunc_getfolloweraction(struct ScriptContext *ctx) // Essentially a big
// If map is not flyable, set the script to jump past the fly check TODO: Should followers ask to fly?
if (TRUE || !Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType))
ScriptJump(ctx, EventScript_FollowerEnd);
multi = MapGridGetMetatileBehaviorAt(objEvent->currentCoords.x, objEvent->currentCoords.y);
species = GetMonData(mon, MON_DATA_SPECIES);
friendship = GetMonData(mon, MON_DATA_FRIENDSHIP);
// Happy weights
emotion_weight[FOLLOWER_EMOTION_HAPPY] = 10;
if (friendship > 170)
emotion_weight[FOLLOWER_EMOTION_HAPPY] = 30;
else if (friendship > 80)
multi = GetMonData(mon, MON_DATA_FRIENDSHIP);
if (multi > 80) {
emotion_weight[FOLLOWER_EMOTION_HAPPY] = 20;
// Neutral weights
emotion_weight[FOLLOWER_EMOTION_NEUTRAL] = 15;
// Sad weights
emotion_weight[FOLLOWER_EMOTION_SAD] = 5;
// Upset weights
emotion_weight[FOLLOWER_EMOTION_UPSET] = friendship < 80 ? 15 : 5;
// Angry weights
emotion_weight[FOLLOWER_EMOTION_ANGRY] = friendship < 80 ? 15 : 5;
// Pensive weights
emotion_weight[FOLLOWER_EMOTION_PENSIVE] = 15;
// Love weights
if (friendship > 170)
emotion_weight[FOLLOWER_EMOTION_LOVE] = 30;
else if (friendship > 80)
emotion_weight[FOLLOWER_EMOTION_UPSET] = 5;
emotion_weight[FOLLOWER_EMOTION_ANGRY] = 5;
emotion_weight[FOLLOWER_EMOTION_LOVE] = 20;
// Surprise weights TODO: Scale this with how long the follower has been out
emotion_weight[FOLLOWER_EMOTION_SURPRISE] = 10;
// Curious weights TODO: Increase this if there is an item nearby, or if the pokemon has pickup
emotion_weight[FOLLOWER_EMOTION_CURIOUS] = 10;
// Music weights TODO: Change this depending on music ?
emotion_weight[FOLLOWER_EMOTION_MUSIC] = friendship > 80 ? 20 : 15;
emotion_weight[FOLLOWER_EMOTION_MUSIC] = 20;
}
if (multi > 170) {
emotion_weight[FOLLOWER_EMOTION_HAPPY] = 30;
emotion_weight[FOLLOWER_EMOTION_LOVE] = 30;
}
// Conditional messages follow
// Weather-related
if (GetCurrentWeather() == WEATHER_SUNNY || GetCurrentWeather() == WEATHER_SUNNY_CLOUDS)
if (GetCurrentWeather() == WEATHER_SUNNY_CLOUDS)
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_HAPPY, .index=31};
else if (GetCurrentWeather() == WEATHER_RAIN || GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM) {
if (SpeciesHasType(species, TYPE_FIRE)) {
emotion_weight[FOLLOWER_EMOTION_SAD] = 30;
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_SAD, .index=3};
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_UPSET, .index=3};
} else
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion = FOLLOWER_EMOTION_MUSIC, .index=14};
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_SURPRISE, .index=20};
}
// Health & status-related
health_percent = mon->hp * 100 / mon->maxHP;
if (health_percent < 20) {
multi = mon->hp * 100 / mon->maxHP;
if (multi < 20) {
emotion_weight[FOLLOWER_EMOTION_SAD] = 30;
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_SAD, .index=4};
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_SAD, .index=5};
}
if (health_percent < 50 || mon->status & 0x40) { // STATUS1_PARALYSIS
if (multi < 50 || mon->status & STATUS1_PARALYSIS) {
emotion_weight[FOLLOWER_EMOTION_SAD] = 30;
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_SAD, .index=6};
}
// Gym type advantage/disadvantage scripts
if (GetCurrentMapMusic() == MUS_GYM || GetCurrentMapMusic() == MUS_RG_GYM) {
switch (gMapHeader.regionMapSectionId)
{
case MAPSEC_RUSTBORO_CITY:
case MAPSEC_PEWTER_CITY:
multi = TYPE_ROCK;
break;
case MAPSEC_DEWFORD_TOWN:
multi = TYPE_FIGHTING;
break;
case MAPSEC_MAUVILLE_CITY:
case MAPSEC_VERMILION_CITY:
multi = TYPE_ELECTRIC;
break;
case MAPSEC_LAVARIDGE_TOWN:
case MAPSEC_CINNABAR_ISLAND:
multi = TYPE_FIRE;
break;
case MAPSEC_PETALBURG_CITY:
multi = TYPE_NORMAL;
break;
case MAPSEC_FORTREE_CITY:
multi = TYPE_FLYING;
break;
case MAPSEC_MOSSDEEP_CITY:
case MAPSEC_SAFFRON_CITY:
multi = TYPE_PSYCHIC;
break;
case MAPSEC_SOOTOPOLIS_CITY:
case MAPSEC_CERULEAN_CITY:
multi = TYPE_WATER;
break;
case MAPSEC_CELADON_CITY:
multi = TYPE_GRASS;
break;
case MAPSEC_FUCHSIA_CITY:
multi = TYPE_POISON;
break;
case MAPSEC_VIRIDIAN_CITY:
multi = TYPE_GROUND;
break;
default:
multi = NUMBER_OF_MON_TYPES;
}
if (multi < NUMBER_OF_MON_TYPES) {
multi = GetTypeEffectiveness(mon, multi);
if (multi & (MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_NO_EFFECT))
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_HAPPY, .index=32};
else if (multi & MOVE_RESULT_SUPER_EFFECTIVE)
cond_emotes[n_choices++] = (struct SpecialEmote) {.emotion=FOLLOWER_EMOTION_SAD, .index=7};
}
}
emotion = RandomWeightedIndex(emotion_weight, FOLLOWER_EMOTION_LENGTH);
if (mon->status & 0x8) // STATUS1_POISON
#ifdef BATTLE_ENGINE
if ((mon->status & STATUS1_PSN_ANY) && GetMonAbility(mon) != ABILITY_POISON_HEAL)
#else
if (mon->status & STATUS1_PSN_ANY)
#endif
emotion = FOLLOWER_EMOTION_POISONED;
ObjectEventEmote(objEvent, emotion);
multi = Random() % followerBasicMessages[emotion].length;
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 && (Random() < 0x10000 / (j++))) // Replace item with 1/j chance
choice = &cond_emotes[i];
}
if (choice)
multi = choice->index;
// With 50% chance, select special message using reservoir sampling
for (i = (Random() & 1) ? n_choices : 0, j = 1; i < n_choices; i++) {
if (cond_emotes[i].emotion == emotion && (Random() < 0x10000 / (j++))) // Replace item with 1/j chance
multi = cond_emotes[i].index;
}
// Match scripted conditional messages
// With 50% chance, try to match scripted conditional messages
for (i = (Random() & 1) ? 28 : 0, j = 1; i < 28; i++) {
const struct FollowerMsgInfoExtended *info = &gFollowerConditionalMessages[i];
if (info->stFlags == 1 && species != info->st.species)
continue;
if (info->stFlags == 2 && (info->st.types.type2 >= NUMBER_OF_MON_TYPES ? SpeciesHasType(species, info->st.types.type1) : !(SpeciesHasType(species, info->st.types.type1) || SpeciesHasType(species, info->st.types.type2))))
continue;
if (info->stFlags == 3 && !(mon->status & info->st.status))
continue;
if (info->mmFlags == 1 && gMapHeader.regionMapSectionId != info->mm.mapSec.mapSec)
continue;
if (info->mmFlags == 2 && !(gSaveBlock1Ptr->location.mapNum == info->mm.map.mapNum && gSaveBlock1Ptr->location.mapGroup == info->mm.map.mapGroup))
continue;
if (info->mmFlags == 3 && !(objEvent->currentMetatileBehavior == info->mm.mb.behavior1 || objEvent->currentMetatileBehavior == info->mm.mb.behavior2))
continue;
if (info->wtFlags == 1 && !(GetCurrentWeather() == info->wt.weather.weather1 || GetCurrentWeather() == info->wt.weather.weather2))
continue;
if (info->wtFlags == 2 && GetCurrentMapMusic() != info->wt.song)
continue;
if (info->nearFlags == 1) {
if ((multi2 = FindMetatileBehaviorWithinRange(objEvent->currentCoords.x, objEvent->currentCoords.y, info->near.mb.behavior, info->near.mb.distance)))
gSpecialVar_Result = multi2;
else
continue;
}
// replace choice with weight/j chance
if (Random() < (0x10000 / (j++)) * (info->weight ? info->weight : 1)) {
multi = i;
pickedCondition = TRUE;
}
}
if (pickedCondition) { // conditional message was chosen
emotion = gFollowerConditionalMessages[multi].emotion;
ObjectEventEmote(objEvent, emotion);
ctx->data[0] = (u32) gFollowerConditionalMessages[multi].text;
// text choices are spread across array; pick a random one
if (gFollowerConditionalMessages[multi].textSpread) {
for (i = 0; i < 4; i++)
if (!((u32*)gFollowerConditionalMessages[multi].text)[i])
break;
ctx->data[0] = i ? ((u32*)gFollowerConditionalMessages[multi].text)[Random() % i] : 0;
}
ScriptCall(ctx, gFollowerConditionalMessages[multi].script ? gFollowerConditionalMessages[multi].script : followerBasicMessages[emotion].script);
return FALSE;
}
ObjectEventEmote(objEvent, emotion);
ctx->data[0] = (u32) followerBasicMessages[emotion].messages[multi].text; // Load message text
ScriptCall(ctx, followerBasicMessages[emotion].messages[multi].script ?
followerBasicMessages[emotion].messages[multi].script : followerBasicMessages[emotion].script);

269
src/follower_helper.c Normal file
View File

@ -0,0 +1,269 @@
#include "global.h"
#include "data.h"
#include "event_scripts.h"
#include "follower_helper.h"
#include "constants/battle.h"
#include "constants/metatile_behaviors.h"
#include "constants/pokemon.h"
#include "constants/region_map_sections.h"
#include "constants/songs.h"
#include "constants/weather.h"
#define TYPE_NOT_TYPE1 NUMBER_OF_MON_TYPES
// difficult conditional messages follow
static const u8 sCondMsg00[] = _("{STR_VAR_1} danced happily.");
static const u8 sCondMsg01[] = _("{STR_VAR_1} danced beautifully.");
static const u8* const sCelebiTexts[] = {sCondMsg00, sCondMsg01, NULL};
static const u8 sCondMsg02[] = _("{STR_VAR_1} emitted fire and shouted.");
static const u8 sCondMsg03[] = _("{STR_VAR_1} is vigorously producing\nfire!");
static const u8 sCondMsg04[] = _("{STR_VAR_1} spat fire!");
static const u8 sCondMsg05[] = _("{STR_VAR_1} is vigorously breathing\nfire!");
static const u8* const sFireTexts[] = {sCondMsg02, sCondMsg03, sCondMsg04, sCondMsg05, NULL};
static const u8 sCondMsg06[] = _("{STR_VAR_1} is staring straight at\nthe POKéMON LEAGUE.");
static const u8 sCondMsg07[] = _("Your POKéMON is staring intently at\nthe mountain peak.");
static const u8 sCondMsg08[] = _("Sniff sniff, something smells good!");
static const u8 sCondMsg09[] = _("Your POKéMON is surveying the\nshelves restlessly.");
static const u8 sCondMsg10[] = _("{STR_VAR_1} is staring intently at\nthe shelves.");
static const u8* const sShopTexts[] = {sCondMsg09, sCondMsg10, NULL};
static const u8 sCondMsg11[] = _("{STR_VAR_1} focused with a sharp\ngaze!");
static const u8 sCondMsg12[] = _("{STR_VAR_1} seems very interested in\nthe bicycles.");
static const u8 sCondMsg13[] = _("{STR_VAR_1} seems to want to touch\nthe machines!");
static const u8 sCondMsg14[] = _("{STR_VAR_1} is swaying with the\nboat!");
static const u8 sCondMsg15[] = _("{STR_VAR_1} is dancing along with\nthe rolling of the ship.");
static const u8 sCondMsg16[] = _("{STR_VAR_1} doesn't want to get off\nthe boat yet!");
static const u8* const sBoatTexts[] = {sCondMsg14, sCondMsg15, sCondMsg16, NULL};
static const u8 sCondMsg17[] = _("{STR_VAR_1} is listening to the\nsound of the machines.");
static const u8* const sMachineTexts[] = {sCondMsg13, sCondMsg17, NULL};
static const u8 sCondMsg18[] = _("Waah! your POKéMON suddenly splashed\nwater!");
static const u8 sCondMsg19[] = _("Your POKéMON is blowing sand in the\nair!");
static const u8 sCondMsg20[] = _("{STR_VAR_1} is playing around,\nplucking bits of grass.");
static const u8 sCondMsg21[] = _("Your POKéMON is happily looking at\nyour footprints!");
static const u8 sCondMsg22[] = _("{STR_VAR_1} is feeling nervous and a\ntouch claustrophobic.");
static const u8 sCondMsg23[] = _("{STR_VAR_1} is cautious about the\nconfined area!");
static const u8* const sElevatorTexts[] = {sCondMsg22, sCondMsg23, NULL};
static const u8 sCondMsg24[] = _("A cold wind suddenly blew by!");
static const u8 sCondMsg25[] = _("Your POKéMON almost slipped and fell\nover!");
static const u8 sCondMsg26[] = _("Your POKéMON seems surprised to\ntouch ice.");
static const u8* const sColdTexts[] = {sCondMsg24, sCondMsg25, sCondMsg26, NULL};
static const u8 sCondMsg27[] = _("Your POKéMON has a flower petal on\nits face!");
static const u8 sCondMsg28[] = _("{STR_VAR_1} is growling softly.");
static const u8 sCondMsg29[] = _("{STR_VAR_1} is trembling with fear.");
static const u8 sCondMsg30[] = _("{STR_VAR_1} seems somehow sad…");
static const u8* const sFearTexts[] = {sCondMsg29, sCondMsg30, NULL};
static const u8 sCondMsg31[] = _("{STR_VAR_1} is taking shelter in the\ngrass from the rain.");
static const u8 sCondMsg32[] = _("{STR_VAR_1} seems very cold.");
static const u8 sCondMsg33[] = _("{STR_VAR_1} is staring at the sea.");
static const u8 sCondMsg34[] = _("Your pokemon is staring intently at\nthe sea!");
static const u8 sCondMsg35[] = _("{STR_VAR_1} is looking at the\nsurging sea.");
static const u8* const sSeaTexts[] = {sCondMsg33, sCondMsg34, sCondMsg35, NULL};
static const u8 sCondMsg36[] = _("{STR_VAR_1} is listening to the\nsound of the waterfall.");
static const u8 sCondMsg37[] = _("{STR_VAR_1} seems to be happy about\nthe rain!");
static const u8 sCondMsg38[] = _("{STR_VAR_1} is staring at its\nreflection in the water.");
static const u8 sCondMsg39[] = _("{STR_VAR_1} seems to relax as it\nhears the sound of rustling leaves…");
static const u8 sCondMsg40[] = _("{STR_VAR_1} is gnawing at the ice.");
static const u8 sCondMsg41[] = _("{STR_VAR_1} is touching the ice.");
static const u8* const sIceTexts[] = {sCondMsg26, sCondMsg40, sCondMsg41, NULL};
static const u8 sCondMsg42[] = _("{STR_VAR_1}'s burn looks painful!");
// Note that the size of this array must also be correct in event_object_movement
const struct FollowerMsgInfoExtended gFollowerConditionalMessages[28] = {
{
.text = (u8*)sCelebiTexts,
.textSpread = 1,
.script = EventScript_FollowerDance,
.st = {.species = SPECIES_CELEBI},
.stFlags = 1, // MATCH_SPECIES
.emotion = FOLLOWER_EMOTION_NEUTRAL,
},
{
.text = (u8*)sFireTexts,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_FIRE}},
.stFlags = 2, // MATCH_TYPES
.emotion = FOLLOWER_EMOTION_NEUTRAL,
.textSpread = 1,
},
{
.text = sCondMsg06,
.script = EventScript_FollowerFaceUp,
.mm = {.map = {.mapNum = MAP_NUM(EVER_GRANDE_CITY), .mapGroup = MAP_GROUP(EVER_GRANDE_CITY)}},
.mmFlags = 2, // MATCH_MAP
.emotion = FOLLOWER_EMOTION_HAPPY,
},
{
.text = sCondMsg07,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE112), .mapGroup = MAP_GROUP(ROUTE112)}},
.mmFlags = 2, // MATCH_MAP
.emotion = FOLLOWER_EMOTION_HAPPY,
},
{
.text = sCondMsg08,
.script = EventScript_FollowerNostalgia,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE117_POKEMON_DAY_CARE), .mapGroup = MAP_GROUP(ROUTE117_POKEMON_DAY_CARE)}},
.mmFlags = 2, // MATCH_MAP
.emotion = FOLLOWER_EMOTION_NEUTRAL,
},
{
.text = (u8*)sShopTexts,
.textSpread = 1,
.script = EventScript_FollowerLookAround,
.wt = {.song = MUS_POKE_MART},
.wtFlags = 2, // MATCH_SONG
.emotion = FOLLOWER_EMOTION_NEUTRAL,
},
{
.text = sCondMsg11,
.wt = {.song = MUS_VICTORY_ROAD},
.wtFlags = 2, // MATCH_SONG
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
{
.text = sCondMsg12,
.mm = {.map = {.mapNum = MAP_NUM(MAUVILLE_CITY_BIKE_SHOP), .mapGroup = MAP_GROUP(MAUVILLE_CITY_BIKE_SHOP)}},
.mmFlags = 2, // MATCH_MAP
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
{
.text = (u8*)sMachineTexts,
.mm = {.map = {.mapNum = MAP_NUM(NEW_MAUVILLE_INSIDE), .mapGroup = MAP_GROUP(NEW_MAUVILLE_INSIDE)}},
.mmFlags = 2, // MAP
.emotion = FOLLOWER_EMOTION_MUSIC,
.textSpread = 1,
},
{
.text = (u8*)sBoatTexts,
.script = EventScript_FollowerLookAround,
.wt = {.song = MUS_SAILING},
.wtFlags = 2, // MATCH_SONG
.emotion = FOLLOWER_EMOTION_MUSIC,
.textSpread = 1,
},
{
.text = sCondMsg18,
.script = EventScript_FollowerHopping,
.mm = {.mb = {.behavior1 = MB_SHALLOW_WATER, .behavior2 = MB_PUDDLE}},
.mmFlags = 3, // MB
.emotion = FOLLOWER_EMOTION_MUSIC,
},
{
.text = sCondMsg19,
.mm = {.mb = {.behavior1 = MB_SAND, .behavior2 = MB_DEEP_SAND}},
.mmFlags = 3, // MB
.emotion = FOLLOWER_EMOTION_MUSIC,
},
{
.text = sCondMsg20,
.mm = {.mb = {.behavior1 = MB_TALL_GRASS, .behavior2 = MB_LONG_GRASS}},
.mmFlags = 3, // MB
.emotion = FOLLOWER_EMOTION_MUSIC,
},
{
.text = sCondMsg21,
.mm = {.mb = {.behavior1 = MB_SAND, .behavior2 = MB_FOOTPRINTS}},
.mmFlags = 3, // MB
.emotion = FOLLOWER_EMOTION_MUSIC,
},
{
.text = (u8*)sElevatorTexts,
.textSpread = 1,
.mm = {.map = {.mapNum = MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_ELEVATOR), .mapGroup = MAP_GROUP(LILYCOVE_CITY_DEPARTMENT_STORE_ELEVATOR)}},
.mmFlags = 2, // MAP
.emotion = FOLLOWER_EMOTION_SURPRISE,
},
{
.text = (u8*)sColdTexts,
.textSpread = 1,
.mm = {.map = {.mapNum = MAP_NUM(SHOAL_CAVE_LOW_TIDE_ICE_ROOM), .mapGroup = MAP_GROUP(SHOAL_CAVE_LOW_TIDE_ICE_ROOM)}},
.mmFlags = 2, // MAP
.emotion = FOLLOWER_EMOTION_SURPRISE,
},
{
.text = sCondMsg27,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE117), .mapGroup = MAP_GROUP(ROUTE117)}},
.mmFlags = 2, // MAP
.emotion = FOLLOWER_EMOTION_SURPRISE,
},
{
.text = sCondMsg28,
.st = {.types = {.type1 = TYPE_DRAGON, .type2 = TYPE_DRAGON}},
.stFlags = 2, // MATCH_TYPES
.mm = {.mapSec = {.mapSec = MAPSEC_SKY_PILLAR}},
.mmFlags = 1, // MAP_SEC
.emotion = FOLLOWER_EMOTION_UPSET,
},
{
.text = (u8*)sFearTexts,
.textSpread = 1,
.st = {.types = {.type1 = TYPE_GHOST, .type2 = TYPE_NOT_TYPE1}},
.stFlags = 2, // TYPE
.mm = {.mapSec = {.mapSec = MAPSEC_MT_PYRE}},
.mmFlags = 1, // MAP_SEC
.wt = {.song = MUS_MT_PYRE},
.wtFlags = 2, // SONG
.emotion = FOLLOWER_EMOTION_UPSET,
},
{
.text = sCondMsg31,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_FIRE}},
.stFlags = 2, // TYPE
.wt = {.weather = {.weather1 = WEATHER_RAIN, .weather2 = WEATHER_RAIN_THUNDERSTORM}},
.wtFlags = 1, // WEATHER
.emotion = FOLLOWER_EMOTION_UPSET,
},
{
.text = sCondMsg32,
.st = {.status = STATUS1_FREEZE},
.stFlags = 3, // STATUS
.emotion = FOLLOWER_EMOTION_UPSET,
},
{
.text = (u8*)sSeaTexts,
.textSpread = 1,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_OCEAN_WATER, .distance = 5}},
.nearFlags = 1, // mb
.emotion = FOLLOWER_EMOTION_MUSIC,
},
{
.text = sCondMsg36,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_WATERFALL, .distance = 5}},
.nearFlags = 1, // mb
.emotion = FOLLOWER_EMOTION_MUSIC,
},
{
.text = sCondMsg37,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_NOT_TYPE1}},
.stFlags = 2, // TYPE
.wt = {.weather = {.weather1 = WEATHER_RAIN, .weather2 = WEATHER_RAIN_THUNDERSTORM}},
.wtFlags = 1, // WEATHER
.emotion = FOLLOWER_EMOTION_MUSIC,
},
{
.text = sCondMsg38,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_POND_WATER, .distance = 1}},
.nearFlags = 1, // mb
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
{
.text = sCondMsg39,
.mm = {.mapSec = {.mapSec = MAPSEC_PETALBURG_WOODS}},
.mmFlags = 1, // MAP_SEC
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
{
.text = (u8*)sIceTexts,
.textSpread = 1,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_ICE, .distance = 1}},
.nearFlags = 1, // mb
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
{
.text = sCondMsg42,
.st = {.status STATUS1_BURN},
.stFlags 3, // STATUS
.emotion = FOLLOWER_EMOTION_SAD,
},
};