diff --git a/data/scripts/follower.inc b/data/scripts/follower.inc index f2e8c4ac7e..3e9dc45e69 100644 --- a/data/scripts/follower.inc +++ b/data/scripts/follower.inc @@ -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 diff --git a/emotions.txt b/emotions.txt index 42beb1d593..590be93530 100644 --- a/emotions.txt +++ b/emotions.txt @@ -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! diff --git a/follower_emotions.py b/follower_emotions.py index b16409c100..5226348031 100644 --- a/follower_emotions.py +++ b/follower_emotions.py @@ -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) diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index cb81ad8124..ed6e014841 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -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); diff --git a/include/event_scripts.h b/include/event_scripts.h index 911afa91da..d6bc451209 100644 --- a/include/event_scripts.h +++ b/include/event_scripts.h @@ -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[]; diff --git a/include/follower_helper.h b/include/follower_helper.h new file mode 100644 index 0000000000..54b4d4d164 --- /dev/null +++ b/include/follower_helper.h @@ -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 diff --git a/ld_script.txt b/ld_script.txt index 75b95a5708..9417312e55 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -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); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 391e828502..8d99b4c376 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -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); diff --git a/src/data/text/follower_messages.h b/src/data/text/follower_messages.h index 7dc9a67df4..3fbec109cc 100644 --- a/src/data/text/follower_messages.h +++ b/src/data/text/follower_messages.h @@ -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."); diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 9c7fc56985..431c4a1648 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -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); diff --git a/src/follower_helper.c b/src/follower_helper.c new file mode 100644 index 0000000000..b477f1d1e9 --- /dev/null +++ b/src/follower_helper.c @@ -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, + }, +};