Merge branch 'followers' into lighting

This commit is contained in:
Ariel A 2024-02-17 17:49:14 -05:00
commit 7cf2d1eca0
92 changed files with 2483 additions and 1784 deletions

4
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,4 @@
725252905baf28dbb9298dd5fa0daaf0e804a455
afbb88d77ada8a636a318ec32b61b4ea849d85ab
f861504cfc50941768286c0703d24ab0aaceb88e
ebbcb7d025cff716eec5008b5dd2b7d55aa8c3f3

View File

@ -7,13 +7,21 @@ This fork tries to maintain vanilla compatibility whenever possible. It doesn't
There are several branches, each with one main feature (and sometimes some extra stuff):
**followers** branch:
* [HGSS-style pokémon followers](https://bulbapedia.bulbagarden.net/wiki/Walking_Pok%C3%A9mon#Pok.C3.A9mon_HeartGold_and_SoulSilver) for all 386 pokémon, including emotes, the 28 Unown forms and a majority of follower messages.
* Dynamic overworld palettes & reflections compatible with vanilla berry trees.
* PID (but not legitimacy) preserving Pokémon nature-changing function
* Function to detect modern emulators/GBA hardware.
* [HGSS-style pokémon followers](https://bulbapedia.bulbagarden.net/wiki/Walking_Pok%C3%A9mon#Pok.C3.A9mon_HeartGold_and_SoulSilver) for all 386 pokémon (including forms & shinies)
* Includes follower emotes and a majority of the HGSS messages
* Custom pokeball sprites for Gen 1-7 pokéballs
* Followers can use field moves in the overworld
* Overworld form changes for Ditto, Mew, Castform, etc.
* Asymmetrical & 64x64 OW support
* Dynamic Overworld Palette System (DOWP) & reflections compatible with berry trees, etc.
> Note: Unless you have a specific need for it, you should probably use `followers-expanded-id` over this.
![Pokeball](https://i.imgur.com/OMbS67Q.gif)
![Messages](https://i.imgur.com/sTbGVEY.gif)
![Forms](https://i.imgur.com/wDhFNf4.gif)
![HM](https://i.imgur.com/lnXJGHd.gif)
**icons** branch:
* Everything from the **followers** branch.
* All pokemon icons updated to Gen 6, based on [this repo](https://github.com/msikma/pokesprite/tree/master/icons/pokemon/regular)
@ -32,7 +40,7 @@ There are several branches, each with one main feature (and sometimes some extra
**just-lighting** branch:
* `lighting-expanded-id` but with following pokémon code & assets completely removed. (This allows for more than 255 OW graphics)
* Saves with following pokémon can safely be loaded.
* Saves with following pokémon can still safely be loaded.
**followers-expanded-id** branch:
* Like `followers`, but includes expands OW graphicsIds to 16-bits
@ -45,6 +53,12 @@ Additional branches to mention:
To set up the repository, see [INSTALL.md](INSTALL.md).
**guillotine** branch:
* ~~Decapitates~~ Decapitalizes **all** text at runtime, with some exceptions (see the [FAQ](#guillotine-q-how-can-i-keep-my-strings-from-being-decapped))
* Future-proof, does not require mass-replacing strings
To set up the repository, see [INSTALL.md](INSTALL.md).
## FAQ
### `(followers*)` Q: Where are the config settings?
A: Configuration for the follower system is mostly in [event_objects.h](include/constants/event_objects.h):
@ -57,6 +71,10 @@ A: Configuration for the follower system is mostly in [event_objects.h](include/
// to OW code so that large (48x48, 64x64) OWs
// will display correctly under bridges, etc.
#define LARGE_OW_SUPPORT TRUE
// Followers will emerge from the pokeball they are stored in,
// instead of a normal pokeball
#define OW_MON_POKEBALLS TRUE
```
### `(lighting)` Q: How do I mark certain colors in a palette as light-blended?
@ -76,6 +94,35 @@ on separate lines to mark those colors as being light-blended, i.e:
You might have to `make mostlyclean` or change the `.pal` file to pick up the changes.
### `(guillotine)` Q: How can I keep my string(s) from being decapped?
A: There are a number of ways to make a string "fixed case" so that it will not be decapitalized when displayed:
C strings: Replace the `_` with `_C`:
```c
// _C = fixed (C)ase string!
const u8 gText_IDNumber[] = _C("IDNo.");
```
ASM strings: Replace `.string` with `.fixstr`:
```arm
gText_SavingDontTurnOff::
@ Lasts until the string terminator '$'
.fixstr "SAVING…\n"
.string "DON'T TURN OFF THE POWER.$"
```
You can fix-case/unfix parts of a string like so:
```arm
.string "{FIXED_CASE}WARNING!{UNFIX_CASE}\p"
```
For a placeholder (only the placeholder will be fixed-case):
```arm
.string "{STR_VAR_2_FIXED} was transferred to\n"
.string "BOX “{STR_VAR_1}.”$"
```
See also the configuration in [text.h](gflib/text.h).
There's also special handling for "separated bigrams"; basically, two letter words.
This includes: `"TM01", "PC", "EV"`, any two uppercase characters surrounded by digits, whitespace, or the start/end of a string. These will not be decapped.
## See also
For contacts and other pret projects, see [pret.github.io](https://pret.github.io/).

View File

@ -84,3 +84,4 @@ AncientTomb_EventScript_RanFromRegisteel::
setvar VAR_0x8004, SPECIES_REGISTEEL
goto Common_EventScript_LegendaryFlewAway
end

View File

@ -650,3 +650,4 @@ BattleFrontier_BattlePalaceLobby_Text_ExplainRulesWhenInDanger:
.string "nature when it is in trouble.\p"
.string "If a POKéMON begins behaving oddly\n"
.string "in a pinch, watch it carefully.$"

View File

@ -434,3 +434,4 @@ BattleFrontier_BattlePikeLobby_Text_ExplainMonOrderRules:
.string "changed.\p"
.string "The sequence must be set before\n"
.string "starting your challenge.$"

View File

@ -904,3 +904,4 @@ BattleFrontier_BattlePyramidLobby_Text_ExplainBagRules:
.string "of ten kinds of items.\p"
.string "The contents of the BATTLE BAG are\n"
.string "lost if you fail in your quest.$"

View File

@ -84,3 +84,4 @@ DesertRuins_EventScript_RanFromRegirock::
setvar VAR_0x8004, SPECIES_REGIROCK
goto Common_EventScript_LegendaryFlewAway
end

View File

@ -530,3 +530,4 @@ RusturfTunnel_Text_MikePostBattle:
.string "They halted development here to\n"
.string "protect POKéMON, right?\l"
.string "There's a feel-good story!$"

View File

@ -438,3 +438,4 @@ SlateportCity_OceanicMuseum_2F_Text_SSAnneReplica:
.string "“S.S. ANNE\p"
.string "“A replica of the luxury liner that\n"
.string "circles the globe.”$"

View File

@ -30,17 +30,6 @@ EventScript_Follower::
bufferlivemonnickname 0
playfirstmoncry
callfunc ScrFunc_getfolloweraction
checkpartymove MOVE_FLY
compare VAR_RESULT 6
goto_if_eq EventScript_FollowerEnd
bufferlivemonnickname 0
msgbox gText_WantsToFly, MSGBOX_YESNO
switch VAR_RESULT
case NO, EventScript_FollowerEnd
case YES, EventScript_FollowerFly
case MULTI_B_PRESSED, EventScript_FollowerEnd
EventScript_FollowerFly::
callfunc ScrFunc_followerfly
EventScript_FollowerEnd::
waitfieldeffect FLDEFF_EMOTE
release

View File

@ -56,7 +56,6 @@ static void AddSpritesToOamBuffer(void);
static u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority);
static void ResetOamMatrices(void);
static void ResetSprite(struct Sprite *sprite);
static s16 AllocSpriteTiles(u16 tileCount);
static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images);
static void ResetAllSprites(void);
static void BeginAnim(struct Sprite *sprite);

View File

@ -298,6 +298,7 @@ void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotat
u16 LoadSpriteSheet(const struct SpriteSheet *sheet);
u16 LoadSpriteSheetByTemplate(const struct SpriteTemplate *template, u8 frame);
void LoadSpriteSheets(const struct SpriteSheet *sheets);
s16 AllocSpriteTiles(u16 tileCount);
u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet);
void AllocTilesForSpriteSheets(struct SpriteSheet *sheets);
void LoadTilesForSpriteSheet(const struct SpriteSheet *sheet);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -276,6 +276,11 @@
#define ANIM_RUN_WEST (ANIM_STD_COUNT + 2)
#define ANIM_RUN_EAST (ANIM_STD_COUNT + 3)
#define ANIM_EXIT_POKEBALL_FAST_SOUTH (ANIM_STD_COUNT + 0)
#define ANIM_EXIT_POKEBALL_FAST_NORTH (ANIM_STD_COUNT + 1)
#define ANIM_EXIT_POKEBALL_FAST_WEST (ANIM_STD_COUNT + 2)
#define ANIM_EXIT_POKEBALL_FAST_EAST (ANIM_STD_COUNT + 3)
#define ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH (ANIM_STD_COUNT + 0)
#define ANIM_BUNNY_HOP_BACK_WHEEL_NORTH (ANIM_STD_COUNT + 1)
#define ANIM_BUNNY_HOP_BACK_WHEEL_WEST (ANIM_STD_COUNT + 2)

View File

@ -286,6 +286,10 @@
// will display correctly under bridges, etc.
#define LARGE_OW_SUPPORT TRUE
// Followers will emerge from the pokeball they are stored in,
// instead of a normal pokeball
#define OW_MON_POKEBALLS TRUE
#define SHADOW_SIZE_S 0
#define SHADOW_SIZE_M 1
#define SHADOW_SIZE_L 2

View File

@ -110,7 +110,6 @@
#define FLDEFFOBJ_BUBBLES 34
#define FLDEFFOBJ_SMALL_SPARKLE 35
#define FLDEFFOBJ_RAYQUAZA 36
#define FLDEFFOBJ_TRACKS_SLITHER 37
#define FLDEFFOBJ_TRACKS_SPOT 38
#define FLDEFFOBJ_TRACKS_BUG 39

View File

@ -8,6 +8,8 @@ extern u8 ALIGNED(4) gDecompressionBuffer[0x4000];
void LZDecompressWram(const u32 *src, void *dest);
void LZDecompressVram(const u32 *src, void *dest);
bool32 IsLZ77Data(const void *ptr, u32 minSize, u32 maxSize);
u16 LoadCompressedSpriteSheet(const struct CompressedSpriteSheet *src);
void LoadCompressedSpriteSheetOverrideBuffer(const struct CompressedSpriteSheet *src, void *buffer);
bool8 LoadCompressedSpriteSheetUsingHeap(const struct CompressedSpriteSheet *src);

View File

@ -292,6 +292,7 @@ void MovementType_FollowPlayer(struct Sprite *);
u8 GetSlideMovementAction(u32);
u8 GetJumpMovementAction(u32);
u8 GetJump2MovementAction(u32);
u8 CopySprite(struct Sprite *sprite, s16 x, s16 y, u8 subpriority);
u8 CreateCopySpriteAt(struct Sprite *sprite, s16 x, s16 y, u8 subpriority);
u8 MovementType_WanderAround_Step0(struct ObjectEvent *, struct Sprite *);

View File

@ -16,81 +16,67 @@ enum {
FOLLOWER_EMOTION_LENGTH,
};
// This struct is optimized for size
// Each "section" can be used to combine multiple conditions,
// i.e, species and map
// Just set the flags accordingly and use the right union member
struct __attribute__((packed)) FollowerMsgInfoExtended {
// Can be either 3 bytes, a u16 and a byte, or a 24-bit value
union __attribute__((packed)) MsgConditionData {
u8 bytes[3];
struct __attribute__((packed)) {
u16 hw;
u8 b;
} split;
u32 raw:24;
}; // size = 0x3
struct __attribute__((packed)) MsgCondition {
u32 type:8;
union MsgConditionData data;
}; // size = 0x4
struct 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;
u32 emotion:4;
u32 weight:3;
// if set, `text` is treated as an array of up to 4 texts instead
u16 textSpread:1;
// which one is displayed is chosen at random
u32 textSpread:1;
u32 orFlag:1; // if set, *any* condition can match, rather than all
union __attribute__((packed)) {
struct __attribute__((packed)) {
u16 behavior:8;
u16 distance:6;
} mb;
} near;
u16 nearFlags:2; // 1 = mb within '+'-shaped distance away
};
struct MsgCondition conditions[5];
}; // size = 8 + 4 + 5*4 = 32, 0x20
enum {
ST_FLAGS_SPECIES = 1,
ST_FLAGS_TYPE,
ST_FLAGS_STATUS,
};
// Follower message conditions
#define MSG_COND_NONE 0
#define MSG_COND_SPECIES 1
#define MSG_COND_TYPE 2
#define MSG_COND_STATUS 3
#define MSG_COND_MAPSEC 4
#define MSG_COND_MAP 5
#define MSG_COND_ON_MB 6
#define MSG_COND_WEATHER 7
#define MSG_COND_MUSIC 8
#define MSG_COND_TIME_OF_DAY 9
#define MSG_COND_NEAR_MB 10
enum {
MM_FLAGS_MAPSEC = 1,
MM_FLAGS_MAP,
MM_FLAGS_MB, // (m)etatile (b)ehavior
};
#define MATCH_U24(type, value) {type, {.raw = value}}
#define MATCH_U16(type, value1, value2) {type, {.split = {.hw = value1, .b = value2}}}
#define MATCH_U8(type, v1, v2, v3) {type, {.bytes = {v1, v2, v3}}}
enum {
WT_FLAGS_WEATHER = 1,
WT_FLAGS_MUSIC,
WT_FLAGS_TIME,
};
#define NEAR_FLAGS_MB 1
#define MATCH_SPECIES(species) MATCH_U24(MSG_COND_SPECIES, species)
#define MATCH_TYPES(type1, type2) MATCH_U8(MSG_COND_TYPE, type1, type2, 0)
// Checks that follower has *neither* of the two types
#define MATCH_NOT_TYPES(type1, type2) MATCH_U8(MSG_COND_TYPE, type1, type2, TYPE_NONE)
#define MATCH_STATUS(status) MATCH_U24(MSG_COND_STATUS, status)
#define MATCH_MAPSEC(mapsec) MATCH_U24(MSG_COND_MAPSEC, mapsec)
#define MATCH_MAP_RAW(mapGroup, mapNum) MATCH_U8(MSG_COND_MAP, mapGroup, mapNum, 0)
#define MATCH_MAP(map) MATCH_U8(MSG_COND_MAP, MAP_GROUP(map), MAP_NUM(map), 0)
// Matches one of two metatile behaviors follower is standing on
#define MATCH_ON_MB(mb1, mb2) MATCH_U8(MSG_COND_ON_MB, mb1, mb2, 0)
#define MATCH_WEATHER(weather1, weather2) MATCH_U8(MSG_COND_WEATHER, weather1, weather2, 0)
#define MATCH_MUSIC(song) MATCH_U24(MSG_COND_MUSIC, song)
#define MATCH_TIME_OF_DAY(time) MATCH_U24(MSG_COND_TIME_OF_DAY, time)
// Matches metatile behavior within a '+' shape of size `distance`
#define MATCH_NEAR_MB(mb, distance) MATCH_U8(MSG_COND_NEAR_MB, mb, distance, 0)
enum {
COND_MSG_CELEBI,
@ -127,5 +113,6 @@ enum {
};
extern const struct FollowerMsgInfoExtended gFollowerConditionalMessages[COND_MSG_COUNT];
extern const struct FollowerMessagePool gFollowerBasicMessages[FOLLOWER_EMOTION_LENGTH];
#endif //GUARD_FOLLOWER_HELPER_H

View File

@ -275,6 +275,11 @@ enum {
#define PLAYER_AVATAR_FLAG_FORCED_MOVE (1 << 6)
#define PLAYER_AVATAR_FLAG_DASH (1 << 7)
#define PLAYER_AVATAR_FLAG_BIKE (PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE)
// Player avatar flags for which follower pokemon are hidden
#define FOLLOWER_INVISIBLE_FLAGS (PLAYER_AVATAR_FLAG_SURFING | PLAYER_AVATAR_FLAG_UNDERWATER | \
PLAYER_AVATAR_FLAG_BIKE | PLAYER_AVATAR_FLAG_FORCED_MOVE)
enum
{
ACRO_BIKE_NORMAL,

View File

@ -538,7 +538,6 @@ struct SaveBlock2
extern struct SaveBlock2 *gSaveBlock2Ptr;
extern u8 UpdateSpritePaletteWithTime(u8);
extern bool8 IsAccurateGBA(void);
struct SecretBaseParty
{

View File

@ -11,7 +11,23 @@ remote_path=$(git remote get-url build | sed -nr -e "s/ssh:\/\/\w+@?\w*://p") #
make_cmd=$(git config --local remake.make)
make_product=$(git config --local remake.src)
make_dest=$(git config --local remake.dest)
set -x
old_head=$(git rev-parse --short @)
set +e
# Make a temp commit for unstaged changes
temp_commit_msg="temp build"
git commit -aem "$temp_commit_msg"
retVal=$?
set -e
# set -x
git push build --force-with-lease
ssh $remote_host "cd $remote_path && git reset --hard && git checkout $git_branch && $make_cmd"
scp "$remote_host:$remote_path/$make_product" $make_dest
# { set +x; } 2>/dev/null
# Reset temp commit
if [[ $retVal -eq 0 ]]; then
commit_msg=$(git log -1 --pretty=%B)
if [[ "$commit_msg" == "$temp_commit_msg" ]]; then
git reset "$old_head" &>/dev/null
fi
fi
set -x
ssh -o "VisualHostKey=no" $remote_host "cd $remote_path && git reset --hard && git checkout $git_branch && $make_cmd"
scp -o "VisualHostKey=no" "$remote_host:$remote_path/$make_product" $make_dest

View File

@ -687,6 +687,9 @@ $(FLDEFFGFXDIR)/secret_power_tree.4bpp: %.4bpp: %.png
$(FLDEFFGFXDIR)/record_mix_lights.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 1
$(OBJEVENTGFXDIR)/pokemon/substitute.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
$(OBJEVENTGFXDIR)/pokemon/bulbasaur.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4
@ -1938,5 +1941,8 @@ $(OBJEVENTGFXDIR)/pokemon/deoxys.4bpp: %.4bpp: %.png
$(MISCGFXDIR)/emotes.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 2
# All pokeballs are 16x32
$(OBJEVENTGFXDIR)/misc/ball_%.4bpp: $(OBJEVENTGFXDIR)/misc/ball_%.png ; $(GFX) $< $@ -mwidth 2 -mheight 4
graphics/door_anims/battle_tower_multi_corridor.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4

View File

@ -1053,7 +1053,7 @@ void Bike_HandleBumpySlopeJump(void)
bool32 IsRunningDisallowed(u8 metatile)
{
if (IsRunningDisallowedByMetatile(metatile) == TRUE)
if (!gMapHeader.allowRunning || IsRunningDisallowedByMetatile(metatile) == TRUE)
return TRUE;
else
return FALSE;

View File

@ -217,6 +217,12 @@ static const union AnimCmd sAnim_FaceEast2F[] =
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_FaceEast2F_Asym[] =
{
ANIMCMD_FRAME(6, 16),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_GoSouth[] =
{
ANIMCMD_FRAME(3, 8),
@ -289,6 +295,15 @@ static const union AnimCmd sAnim_GoEast2F[] =
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_GoEast2F_Asym[] =
{
ANIMCMD_FRAME(6, 6),
ANIMCMD_FRAME(7, 6),
ANIMCMD_FRAME(7, 6),
ANIMCMD_FRAME(6, 6),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_GoFastSouth[] =
{
ANIMCMD_FRAME(3, 4),
@ -361,6 +376,15 @@ static const union AnimCmd sAnim_GoFastEast2F[] =
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_GoFastEast2F_Asym[] =
{
ANIMCMD_FRAME(6, 4),
ANIMCMD_FRAME(7, 4),
ANIMCMD_FRAME(7, 4),
ANIMCMD_FRAME(6, 4),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_GoFasterSouth[] =
{
ANIMCMD_FRAME(3, 2),
@ -422,6 +446,19 @@ static const union AnimCmd sAnim_ExitPokeballEast[] =
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_ExitPokeballEast_Asym[] =
{
ANIMCMD_FRAME(0, 1),
ANIMCMD_FRAME(0, 3),
ANIMCMD_FRAME(0, 1),
ANIMCMD_FRAME(1, 1),
ANIMCMD_FRAME(2, 1),
ANIMCMD_FRAME(3, 1),
ANIMCMD_FRAME(4, 1),
ANIMCMD_FRAME(6, 8),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_EnterSouth[] =
{
ANIMCMD_FRAME(0, 8),
@ -497,6 +534,18 @@ static const union AnimCmd sAnim_EnterEast[] =
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_EnterEast_Asym[] =
{
ANIMCMD_FRAME(6, 8),
ANIMCMD_FRAME(4, 1),
ANIMCMD_FRAME(3, 1),
ANIMCMD_FRAME(2, 1),
ANIMCMD_FRAME(1, 1),
ANIMCMD_FRAME(0, 1),
ANIMCMD_FRAME(0, 3),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_GoFastestSouth[] =
{
ANIMCMD_FRAME(3, 1),
@ -554,6 +603,18 @@ static const union AnimCmd sAnim_ExitPokeballFastEast[] =
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_ExitPokeballFastEast_Asym[] =
{
ANIMCMD_FRAME(0, 1),
ANIMCMD_FRAME(1, 1),
ANIMCMD_FRAME(2, 1),
ANIMCMD_FRAME(3, 1),
ANIMCMD_FRAME(4, 1),
ANIMCMD_FRAME(6, 2),
ANIMCMD_FRAME(6, 1),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sAnim_GoFastestNorth[] =
{
ANIMCMD_FRAME(5, 1),
@ -1084,31 +1145,59 @@ static const union AnimCmd *const sAnimTable_Standard[] = {
};
static const union AnimCmd *const sAnimTable_Following[] = {
sAnim_FaceSouth,
sAnim_FaceNorth2F,
sAnim_FaceWest2F,
sAnim_FaceEast2F,
sAnim_GoSouth2F,
sAnim_GoNorth2F,
sAnim_GoWest2F,
sAnim_GoEast2F,
sAnim_GoFastSouth2F,
sAnim_GoFastNorth2F,
sAnim_GoFastWest2F,
sAnim_GoFastEast2F,
sAnim_EnterSouth,
sAnim_EnterNorth,
sAnim_EnterWest,
sAnim_EnterEast,
sAnim_ExitPokeballSouth,
sAnim_ExitPokeballNorth,
sAnim_ExitPokeballWest,
sAnim_ExitPokeballEast,
// ANIM_STD_COUNT =
sAnim_ExitPokeballFastSouth,
sAnim_ExitPokeballFastNorth,
sAnim_ExitPokeballFastWest,
sAnim_ExitPokeballFastEast,
[ANIM_STD_FACE_SOUTH] = sAnim_FaceSouth,
[ANIM_STD_FACE_NORTH] = sAnim_FaceNorth2F,
[ANIM_STD_FACE_WEST] = sAnim_FaceWest2F,
[ANIM_STD_FACE_EAST] = sAnim_FaceEast2F,
[ANIM_STD_GO_SOUTH] = sAnim_GoSouth2F,
[ANIM_STD_GO_NORTH] = sAnim_GoNorth2F,
[ANIM_STD_GO_WEST] = sAnim_GoWest2F,
[ANIM_STD_GO_EAST] = sAnim_GoEast2F,
[ANIM_STD_GO_FAST_SOUTH] = sAnim_GoFastSouth2F,
[ANIM_STD_GO_FAST_NORTH] = sAnim_GoFastNorth2F,
[ANIM_STD_GO_FAST_WEST] = sAnim_GoFastWest2F,
[ANIM_STD_GO_FAST_EAST] = sAnim_GoFastEast2F,
// 'Faster' and above used for entering/exiting pokeball
[ANIM_STD_GO_FASTER_SOUTH] = sAnim_EnterSouth,
[ANIM_STD_GO_FASTER_NORTH] = sAnim_EnterNorth,
[ANIM_STD_GO_FASTER_WEST] = sAnim_EnterWest,
[ANIM_STD_GO_FASTER_EAST] = sAnim_EnterEast,
[ANIM_STD_GO_FASTEST_SOUTH] = sAnim_ExitPokeballSouth,
[ANIM_STD_GO_FASTEST_NORTH] = sAnim_ExitPokeballNorth,
[ANIM_STD_GO_FASTEST_WEST] = sAnim_ExitPokeballWest,
[ANIM_STD_GO_FASTEST_EAST] = sAnim_ExitPokeballEast,
[ANIM_EXIT_POKEBALL_FAST_SOUTH] = sAnim_ExitPokeballFastSouth,
[ANIM_EXIT_POKEBALL_FAST_NORTH] = sAnim_ExitPokeballFastNorth,
[ANIM_EXIT_POKEBALL_FAST_WEST] = sAnim_ExitPokeballFastWest,
[ANIM_EXIT_POKEBALL_FAST_EAST] = sAnim_ExitPokeballFastEast,
};
// Like the above, but has separate frames for facing right
static const union AnimCmd *const sAnimTable_Following_Asym[] = {
[ANIM_STD_FACE_SOUTH] = sAnim_FaceSouth,
[ANIM_STD_FACE_NORTH] = sAnim_FaceNorth2F,
[ANIM_STD_FACE_WEST] = sAnim_FaceWest2F,
[ANIM_STD_FACE_EAST] = sAnim_FaceEast2F_Asym,
[ANIM_STD_GO_SOUTH] = sAnim_GoSouth2F,
[ANIM_STD_GO_NORTH] = sAnim_GoNorth2F,
[ANIM_STD_GO_WEST] = sAnim_GoWest2F,
[ANIM_STD_GO_EAST] = sAnim_GoEast2F_Asym,
[ANIM_STD_GO_FAST_SOUTH] = sAnim_GoFastSouth2F,
[ANIM_STD_GO_FAST_NORTH] = sAnim_GoFastNorth2F,
[ANIM_STD_GO_FAST_WEST] = sAnim_GoFastWest2F,
[ANIM_STD_GO_FAST_EAST] = sAnim_GoFastEast2F_Asym,
[ANIM_STD_GO_FASTER_SOUTH] = sAnim_EnterSouth,
[ANIM_STD_GO_FASTER_NORTH] = sAnim_EnterNorth,
[ANIM_STD_GO_FASTER_WEST] = sAnim_EnterWest,
[ANIM_STD_GO_FASTER_EAST] = sAnim_EnterEast_Asym,
[ANIM_STD_GO_FASTEST_SOUTH] = sAnim_ExitPokeballSouth,
[ANIM_STD_GO_FASTEST_NORTH] = sAnim_ExitPokeballNorth,
[ANIM_STD_GO_FASTEST_WEST] = sAnim_ExitPokeballWest,
[ANIM_STD_GO_FASTEST_EAST] = sAnim_ExitPokeballEast_Asym,
[ANIM_EXIT_POKEBALL_FAST_SOUTH] = sAnim_ExitPokeballFastSouth,
[ANIM_EXIT_POKEBALL_FAST_NORTH] = sAnim_ExitPokeballFastNorth,
[ANIM_EXIT_POKEBALL_FAST_WEST] = sAnim_ExitPokeballFastWest,
[ANIM_EXIT_POKEBALL_FAST_EAST] = sAnim_ExitPokeballFastEast_Asym,
};
static const union AnimCmd *const sAnimTable_HoOh[] = {

View File

@ -346,6 +346,56 @@ const u32 gObjectEventPic_Noland[] = INCBIN_U32("graphics/object_events/pics/peo
const u32 gObjectEventPic_Lucy[] = INCBIN_U32("graphics/object_events/pics/people/frontier_brains/lucy.4bpp");
const u32 gObjectEventPic_Brandon[] = INCBIN_U32("graphics/object_events/pics/people/frontier_brains/brandon.4bpp");
const u32 gObjectEventPic_AnimatedBall[] = INCBIN_U32("graphics/object_events/pics/misc/animated_ball.4bpp");
#if OW_MON_POKEBALLS
// Vanilla
const u32 gObjectEventPic_MasterBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_master.4bpp");
const u32 gObjectEventPic_UltraBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_ultra.4bpp");
const u32 gObjectEventPic_GreatBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_great.4bpp");
const u32 gObjectEventPic_SafariBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_safari.4bpp");
const u32 gObjectEventPic_NetBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_net.4bpp");
const u32 gObjectEventPic_DiveBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_dive.4bpp");
const u32 gObjectEventPic_NestBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_nest.4bpp");
const u32 gObjectEventPic_RepeatBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_repeat.4bpp");
const u32 gObjectEventPic_TimerBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_timer.4bpp");
const u32 gObjectEventPic_LuxuryBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_luxury.4bpp");
const u32 gObjectEventPic_PremierBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_premier.4bpp");
// Gen IV/Sinnoh
#ifdef ITEM_DUSK_BALL
const u32 gObjectEventPic_DuskBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_dusk.4bpp");
const u32 gObjectEventPic_HealBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_heal.4bpp");
const u32 gObjectEventPic_QuickBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_quick.4bpp");
const u32 gObjectEventPic_CherishBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_cherish.4bpp");
#endif
#ifdef ITEM_PARK_BALL
const u32 gObjectEventPic_ParkBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_park.4bpp");
#endif
// Gen II/Johto Apricorns
#ifdef ITEM_FAST_BALL
const u32 gObjectEventPic_FastBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_fast.4bpp");
const u32 gObjectEventPic_LevelBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_level.4bpp");
const u32 gObjectEventPic_LureBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_lure.4bpp");
const u32 gObjectEventPic_HeavyBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_heavy.4bpp");
const u32 gObjectEventPic_LoveBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_love.4bpp");
const u32 gObjectEventPic_FriendBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_friend.4bpp");
const u32 gObjectEventPic_MoonBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_moon.4bpp");
const u32 gObjectEventPic_SportBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_sport.4bpp");
#endif
// Gen V
#ifdef ITEM_DREAM_BALL
const u32 gObjectEventPic_DreamBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_dream.4bpp");
#endif
// Gen VII
#ifdef ITEM_BEAST_BALL
const u32 gObjectEventPic_BeastBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_beast.4bpp");
#endif
// Gen VIII
#ifdef ITEM_STRANGE_BALL
const u32 gObjectEventPic_StrangeBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_strange.4bpp");
#endif
#endif
const u32 gObjectEventPic_Substitute[] = INCBIN_U32("graphics/object_events/pics/pokemon/substitute.4bpp");
const u32 gObjectEventPic_Bulbasaur[] = INCBIN_U32("graphics/object_events/pics/pokemon/bulbasaur.4bpp");
const u32 gObjectEventPic_Ivysaur[] = INCBIN_U32("graphics/object_events/pics/pokemon/ivysaur.4bpp");
const u32 gObjectEventPic_Venusaur[] = INCBIN_U32("graphics/object_events/pics/pokemon/venusaur.4bpp");
@ -792,5 +842,44 @@ const u16 gObjectEventPal_Lugia[] = INCBIN_U16("graphics/object_events/palettes/
const u16 gObjectEventPaletteLight[] = INCBIN_U16("graphics/object_events/palettes/light.gbapal");
const u16 gObjectEventPaletteLight2[] = INCBIN_U16("graphics/object_events/palettes/light2.gbapal");
const u16 gObjectEventPal_Substitute[] = INCBIN_U16("graphics/object_events/pics/pokemon/substitute.gbapal");
const u16 gObjectEventPaletteEmotes[] = INCBIN_U16("graphics/misc/emotes.gbapal");
const u16 gObjectEventPaletteNeonLight[] = INCBIN_U16("graphics/object_events/palettes/neon_light.gbapal");
#if OW_MON_POKEBALLS
// Palettes are small, so always include all of the palettes (no #ifdef)
// Vanilla
const u16 gObjectEventPal_MasterBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_master.gbapal");
const u16 gObjectEventPal_UltraBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_ultra.gbapal");
const u16 gObjectEventPal_GreatBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_great.gbapal");
const u16 gObjectEventPal_SafariBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_safari.gbapal");
const u16 gObjectEventPal_NetBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_net.gbapal");
const u16 gObjectEventPal_DiveBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_dive.gbapal");
const u16 gObjectEventPal_NestBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_nest.gbapal");
const u16 gObjectEventPal_RepeatBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_repeat.gbapal");
const u16 gObjectEventPal_TimerBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_timer.gbapal");
const u16 gObjectEventPal_LuxuryBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_luxury.gbapal");
const u16 gObjectEventPal_PremierBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_premier.gbapal");
// Gen IV/Sinnoh
const u16 gObjectEventPal_DuskBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_dusk.gbapal");
const u16 gObjectEventPal_HealBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_heal.gbapal");
const u16 gObjectEventPal_QuickBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_quick.gbapal");
const u16 gObjectEventPal_CherishBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_cherish.gbapal");
const u16 gObjectEventPal_ParkBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_park.gbapal");
// Gen II/Johto Apricorns
const u16 gObjectEventPal_FastBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_fast.gbapal");
const u16 gObjectEventPal_LevelBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_level.gbapal");
const u16 gObjectEventPal_LureBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_lure.gbapal");
const u16 gObjectEventPal_HeavyBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_heavy.gbapal");
const u16 gObjectEventPal_LoveBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_love.gbapal");
const u16 gObjectEventPal_FriendBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_friend.gbapal");
const u16 gObjectEventPal_MoonBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_moon.gbapal");
const u16 gObjectEventPal_SportBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_sport.gbapal");
// Gen V
const u16 gObjectEventPal_DreamBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_dream.gbapal");
// Gen VII
const u16 gObjectEventPal_BeastBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_beast.gbapal");
// Gen VIII
const u16 gObjectEventPal_StrangeBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_strange.gbapal");
#endif

View File

@ -1,5 +1,7 @@
// Species-indexed pokemon object event table
const struct ObjectEventGraphicsInfo gPokemonObjectGraphics[] = {
// placeholder gfx, used when other gfx aren't found
[SPECIES_NONE] = {0xFFFF, OBJ_EVENT_PAL_TAG_SUBSTITUTE, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_Substitute, gDummySpriteAffineAnimTable},
[SPECIES_BULBASAUR] = {0xFFFF, OBJ_EVENT_PAL_TAG_DYNAMIC, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_Bulbasaur, gDummySpriteAffineAnimTable},
[SPECIES_IVYSAUR] = {0xFFFF, OBJ_EVENT_PAL_TAG_DYNAMIC, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_Ivysaur, gDummySpriteAffineAnimTable},
[SPECIES_VENUSAUR] = {0xFFFF, OBJ_EVENT_PAL_TAG_DYNAMIC, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_Venusaur, gDummySpriteAffineAnimTable},
@ -416,9 +418,89 @@ const struct ObjectEventGraphicsInfo gPokemonObjectGraphics[] = {
};
// Normal, sunny, rainy, snowy
const struct ObjectEventGraphicsInfo gCastformObjectGraphics[] = {
{0xFFFF, OBJ_EVENT_PAL_TAG_DYNAMIC, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_Castform, gDummySpriteAffineAnimTable},
{0xFFFF, OBJ_EVENT_PAL_TAG_CASTFORM_SUNNY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_CastformSunny, gDummySpriteAffineAnimTable},
{0xFFFF, OBJ_EVENT_PAL_TAG_CASTFORM_RAINY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_CastformRainy, gDummySpriteAffineAnimTable},
{0xFFFF, OBJ_EVENT_PAL_TAG_CASTFORM_SNOWY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_CastformSnowy, gDummySpriteAffineAnimTable},
const struct ObjectEventGraphicsInfo gCastformObjectGraphics[] =
{
{TAG_NONE, OBJ_EVENT_PAL_TAG_DYNAMIC, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_Castform, gDummySpriteAffineAnimTable},
{TAG_NONE, OBJ_EVENT_PAL_TAG_CASTFORM_SUNNY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_CastformSunny, gDummySpriteAffineAnimTable},
{TAG_NONE, OBJ_EVENT_PAL_TAG_CASTFORM_RAINY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_CastformRainy, gDummySpriteAffineAnimTable},
{TAG_NONE, OBJ_EVENT_PAL_TAG_CASTFORM_SNOWY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_CastformSnowy, gDummySpriteAffineAnimTable},
};
// Standalone follower palettes
// If not NULL, entries here override the front-sprite-based pals
// used by OBJ_EVENT_PAL_TAG_DYNAMIC
// Palette data may be compressed, or not
const void* const gFollowerPalettes[][2] =
{
// Must have at least one entry, or ARRAY_COUNT comparison fails
// (SPECIES_NONE does not use OBJ_EVENT_PAL_TAG_DYNAMIC anyway)
[SPECIES_NONE] = {gMonPalette_CircledQuestionMark, gMonShinyPalette_CircledQuestionMark},
};
#if OW_MON_POKEBALLS
#define POKEBALL_GFX_INFO(NAME) \
[BALL_##NAME] = { \
.tileTag = TAG_NONE, \
.paletteTag = OBJ_EVENT_PAL_TAG_BALL_##NAME, \
.size = 256, \
.width = 16, \
.height = 32, \
.shadowSize = SHADOW_SIZE_M, \
.inanimate = TRUE, \
.oam = &gObjectEventBaseOam_16x32, \
.subspriteTables = sOamTables_16x32, \
.anims = sAnimTable_Following, \
.images = sPicTable_Ball_##NAME, \
.affineAnims = gDummySpriteAffineAnimTable, \
}
const struct ObjectEventGraphicsInfo gPokeballGraphics[POKEBALL_COUNT] = {
// Vanilla
POKEBALL_GFX_INFO(MASTER),
POKEBALL_GFX_INFO(ULTRA),
POKEBALL_GFX_INFO(GREAT),
POKEBALL_GFX_INFO(SAFARI),
POKEBALL_GFX_INFO(NET),
POKEBALL_GFX_INFO(DIVE),
POKEBALL_GFX_INFO(NEST),
POKEBALL_GFX_INFO(REPEAT),
POKEBALL_GFX_INFO(TIMER),
POKEBALL_GFX_INFO(LUXURY),
POKEBALL_GFX_INFO(PREMIER),
// Gen IV/Sinnoh pokeballs
#ifdef ITEM_DUSK_BALL
POKEBALL_GFX_INFO(DUSK),
POKEBALL_GFX_INFO(HEAL),
POKEBALL_GFX_INFO(QUICK),
POKEBALL_GFX_INFO(CHERISH),
#endif
#ifdef ITEM_PARK_BALL
POKEBALL_GFX_INFO(PARK),
#endif
// Gen II/Johto Apricorn pokeballs
#ifdef ITEM_FAST_BALL
POKEBALL_GFX_INFO(FAST),
POKEBALL_GFX_INFO(LEVEL),
POKEBALL_GFX_INFO(LURE),
POKEBALL_GFX_INFO(HEAVY),
POKEBALL_GFX_INFO(LOVE),
POKEBALL_GFX_INFO(FRIEND),
POKEBALL_GFX_INFO(MOON),
POKEBALL_GFX_INFO(SPORT),
#endif
// Gen V
#ifdef ITEM_DREAM_BALL
POKEBALL_GFX_INFO(DREAM),
#endif
// Gen VII
#ifdef ITEM_BEAST_BALL
POKEBALL_GFX_INFO(BEAST),
#endif
// Gen VIII
#ifdef ITEM_STRANGE_BALL
POKEBALL_GFX_INFO(STRANGE),
#endif
};
#endif

View File

@ -1987,11 +1987,146 @@ static const struct SpriteFrameImage sPicTable_AnimatedBall[] = {
overworld_frame(gObjectEventPic_AnimatedBall, 2, 4, 2),
overworld_frame(gObjectEventPic_AnimatedBall, 2, 4, 3),
overworld_frame(gObjectEventPic_AnimatedBall, 2, 4, 4),
overworld_frame(gObjectEventPic_AnimatedBall, 2, 4, 5),
overworld_frame(gObjectEventPic_AnimatedBall, 2, 4, 0),
};
extern const struct SpriteFrameImage gFieldEffectObjectPicTable_BallLight[];
#if OW_MON_POKEBALLS
#define POKEBALL_PIC_FRAMES(name) \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 0), \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 1), \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 2), \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 3), \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 4), \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 0)
static const struct SpriteFrameImage sPicTable_Ball_MASTER[] = {
POKEBALL_PIC_FRAMES(Master),
};
static const struct SpriteFrameImage sPicTable_Ball_ULTRA[] = {
POKEBALL_PIC_FRAMES(Ultra),
};
static const struct SpriteFrameImage sPicTable_Ball_GREAT[] = {
POKEBALL_PIC_FRAMES(Great),
};
static const struct SpriteFrameImage sPicTable_Ball_SAFARI[] = {
POKEBALL_PIC_FRAMES(Safari),
};
static const struct SpriteFrameImage sPicTable_Ball_NET[] = {
POKEBALL_PIC_FRAMES(Net),
};
static const struct SpriteFrameImage sPicTable_Ball_DIVE[] = {
POKEBALL_PIC_FRAMES(Dive),
};
static const struct SpriteFrameImage sPicTable_Ball_NEST[] = {
POKEBALL_PIC_FRAMES(Nest),
};
static const struct SpriteFrameImage sPicTable_Ball_REPEAT[] = {
POKEBALL_PIC_FRAMES(Repeat),
};
static const struct SpriteFrameImage sPicTable_Ball_TIMER[] = {
POKEBALL_PIC_FRAMES(Timer),
};
static const struct SpriteFrameImage sPicTable_Ball_LUXURY[] = {
POKEBALL_PIC_FRAMES(Luxury),
};
static const struct SpriteFrameImage sPicTable_Ball_PREMIER[] = {
POKEBALL_PIC_FRAMES(Premier),
};
// Gen IV/Sinnoh
#ifdef ITEM_DUSK_BALL
static const struct SpriteFrameImage sPicTable_Ball_DUSK[] = {
POKEBALL_PIC_FRAMES(Dusk),
};
static const struct SpriteFrameImage sPicTable_Ball_HEAL[] = {
POKEBALL_PIC_FRAMES(Heal),
};
static const struct SpriteFrameImage sPicTable_Ball_QUICK[] = {
POKEBALL_PIC_FRAMES(Quick),
};
static const struct SpriteFrameImage sPicTable_Ball_CHERISH[] = {
POKEBALL_PIC_FRAMES(Cherish),
};
#endif
#ifdef ITEM_PARK_BALL
static const struct SpriteFrameImage sPicTable_Ball_PARK[] = {
POKEBALL_PIC_FRAMES(Park),
};
#endif
// Gen II/Johto Apricorns
#ifdef ITEM_FAST_BALL
static const struct SpriteFrameImage sPicTable_Ball_FAST[] = {
POKEBALL_PIC_FRAMES(Fast),
};
static const struct SpriteFrameImage sPicTable_Ball_LEVEL[] = {
POKEBALL_PIC_FRAMES(Level),
};
static const struct SpriteFrameImage sPicTable_Ball_LURE[] = {
POKEBALL_PIC_FRAMES(Lure),
};
static const struct SpriteFrameImage sPicTable_Ball_HEAVY[] = {
POKEBALL_PIC_FRAMES(Heavy),
};
static const struct SpriteFrameImage sPicTable_Ball_LOVE[] = {
POKEBALL_PIC_FRAMES(Love),
};
static const struct SpriteFrameImage sPicTable_Ball_FRIEND[] = {
POKEBALL_PIC_FRAMES(Friend),
};
static const struct SpriteFrameImage sPicTable_Ball_MOON[] = {
POKEBALL_PIC_FRAMES(Moon),
};
static const struct SpriteFrameImage sPicTable_Ball_SPORT[] = {
POKEBALL_PIC_FRAMES(Sport),
};
#endif
// Gen V
#ifdef ITEM_DREAM_BALL
static const struct SpriteFrameImage sPicTable_Ball_DREAM[] = {
POKEBALL_PIC_FRAMES(Dream),
};
#endif
// Gen VII
#ifdef ITEM_BEAST_BALL
static const struct SpriteFrameImage sPicTable_Ball_BEAST[] = {
POKEBALL_PIC_FRAMES(Beast),
};
#endif
// Gen VIII
#ifdef ITEM_STRANGE_BALL
static const struct SpriteFrameImage sPicTable_Ball_STRANGE[] = {
POKEBALL_PIC_FRAMES(Strange),
};
#endif
#endif
static const struct SpriteFrameImage sPicTable_Substitute[] = {
overworld_frame(gObjectEventPic_Substitute, 4, 4, 0),
overworld_frame(gObjectEventPic_Substitute, 4, 4, 1),
overworld_frame(gObjectEventPic_Substitute, 4, 4, 2),
overworld_frame(gObjectEventPic_Substitute, 4, 4, 3),
overworld_frame(gObjectEventPic_Substitute, 4, 4, 4),
overworld_frame(gObjectEventPic_Substitute, 4, 4, 5),
};
static const struct SpriteFrameImage sPicTable_Bulbasaur[] = {
overworld_frame(gObjectEventPic_Bulbasaur, 4, 4, 0),
overworld_frame(gObjectEventPic_Bulbasaur, 4, 4, 1),

View File

@ -19,6 +19,24 @@ void LZDecompressVram(const u32 *src, void *dest)
LZ77UnCompVram(src, dest);
}
// Checks if `ptr` is likely LZ77 data
// Checks word-alignment, min/max size, and header byte
bool32 IsLZ77Data(const void *ptr, u32 minSize, u32 maxSize) {
const u8 *data = ptr;
u32 size;
// Compressed data must be word aligned
if (((u32)ptr) & 3)
return FALSE;
// Check LZ77 header byte
// See https://problemkaputt.de/gbatek.htm#biosdecompressionfunctions
if (data[0] != 0x10)
return FALSE;
// Read 24-bit uncompressed size
size = data[1] | (data[2] << 8) | (data[3] << 16);
return (size >= minSize && size <= maxSize);
}
u16 LoadCompressedSpriteSheet(const struct CompressedSpriteSheet *src)
{
struct SpriteSheet dest;

File diff suppressed because it is too large Load Diff

View File

@ -687,7 +687,8 @@ static void Task_DoDoorWarp(u8 taskId)
FreezeObjectEvents();
PlayerGetDestCoords(x, y);
PlaySE(GetDoorSoundEffect(*x, *y - 1));
if (followerObject) { // Put follower into pokeball
if (followerObject) {
// Put follower into pokeball
ClearObjectEventMovement(followerObject, &gSprites[followerObject->spriteId]);
ObjectEventSetHeldMovement(followerObject, MOVEMENT_ACTION_ENTER_POKEBALL);
}

View File

@ -80,241 +80,236 @@ const struct FollowerMsgInfoExtended gFollowerConditionalMessages[COND_MSG_COUNT
.text = (u8*)sCelebiTexts,
.textSpread = 1,
.script = EventScript_FollowerDance,
.st = {.species = SPECIES_CELEBI},
.stFlags = ST_FLAGS_SPECIES,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
.conditions = {MATCH_SPECIES(SPECIES_CELEBI)},
},
[COND_MSG_FIRE] =
{
.text = (u8*)sFireTexts,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_FIRE}},
.stFlags = ST_FLAGS_TYPE,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
.textSpread = 1,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
.conditions = {MATCH_TYPES(TYPE_FIRE, TYPE_FIRE)},
},
[COND_MSG_EVER_GRANDE] =
{
.text = sCondMsg06,
.script = EventScript_FollowerFaceUp,
.mm = {.map = {.mapNum = MAP_NUM(EVER_GRANDE_CITY), .mapGroup = MAP_GROUP(EVER_GRANDE_CITY)}},
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_HAPPY,
.conditions = {MATCH_MAP(EVER_GRANDE_CITY)},
},
[COND_MSG_ROUTE_112] =
{
.text = sCondMsg07,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE112), .mapGroup = MAP_GROUP(ROUTE112)}},
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_HAPPY,
.conditions = {MATCH_MAP(ROUTE112)},
},
[COND_MSG_DAY_CARE] =
{
.text = sCondMsg08,
.script = EventScript_FollowerNostalgia,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE117_POKEMON_DAY_CARE), .mapGroup = MAP_GROUP(ROUTE117_POKEMON_DAY_CARE)}},
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
.conditions = {MATCH_MAP(ROUTE117_POKEMON_DAY_CARE)},
},
[COND_MSG_MART] =
{
.text = (u8*)sShopTexts,
.textSpread = 1,
.script = EventScript_FollowerLookAround,
.wt = {.song = MUS_POKE_MART},
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
.conditions = {MATCH_MUSIC(MUS_POKE_MART)},
},
[COND_MSG_VICTORY_ROAD] =
{
.text = sCondMsg11,
.wt = {.song = MUS_VICTORY_ROAD},
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_PENSIVE,
.conditions = {MATCH_MUSIC(MUS_VICTORY_ROAD)},
},
[COND_MSG_BIKE_SHOP] =
{
.text = sCondMsg12,
.mm = {.map = {.mapNum = MAP_NUM(MAUVILLE_CITY_BIKE_SHOP), .mapGroup = MAP_GROUP(MAUVILLE_CITY_BIKE_SHOP)}},
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_PENSIVE,
.conditions = {MATCH_MAP(MAUVILLE_CITY_BIKE_SHOP)},
},
[COND_MSG_MACHINES] =
{
.text = (u8*)sMachineTexts,
.mm = {.map = {.mapNum = MAP_NUM(NEW_MAUVILLE_INSIDE), .mapGroup = MAP_GROUP(NEW_MAUVILLE_INSIDE)}},
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_MUSIC,
.textSpread = 1,
.emotion = FOLLOWER_EMOTION_MUSIC,
.orFlag = 1, // match any of these maps
.conditions = {
MATCH_MAP(NEW_MAUVILLE_INSIDE),
MATCH_MAP(SLATEPORT_CITY_STERNS_SHIPYARD_1F),
MATCH_MAP(SLATEPORT_CITY_STERNS_SHIPYARD_2F),
}
},
[COND_MSG_SAILING] =
{
.text = (u8*)sBoatTexts,
.script = EventScript_FollowerLookAround,
.wt = {.song = MUS_SAILING},
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_MUSIC,
.textSpread = 1,
.emotion = FOLLOWER_EMOTION_MUSIC,
.script = EventScript_FollowerLookAround,
.conditions = {MATCH_MUSIC(MUS_SAILING)},
},
[COND_MSG_PUDDLE] =
{
.text = sCondMsg18,
.script = EventScript_FollowerHopping,
.mm = {.mb = {.behavior1 = MB_SHALLOW_WATER, .behavior2 = MB_PUDDLE}},
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_ON_MB(MB_SHALLOW_WATER, MB_PUDDLE)},
},
[COND_MSG_SAND] =
{
.text = sCondMsg19,
.mm = {.mb = {.behavior1 = MB_SAND, .behavior2 = MB_DEEP_SAND}},
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_ON_MB(MB_SAND, MB_DEEP_SAND)},
},
[COND_MSG_GRASS] =
{
.text = sCondMsg20,
.mm = {.mb = {.behavior1 = MB_TALL_GRASS, .behavior2 = MB_LONG_GRASS}},
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_ON_MB(MB_TALL_GRASS, MB_LONG_GRASS)},
},
[COND_MSG_FOOTPRINTS] =
{
.text = sCondMsg21,
.mm = {.mb = {.behavior1 = MB_SAND, .behavior2 = MB_FOOTPRINTS}},
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_ON_MB(MB_SAND, MB_FOOTPRINTS)},
},
[COND_MSG_ELEVATOR] =
{
.text = (u8*)sElevatorTexts,
.textSpread = 1,
.mm = {.map = {.mapNum = MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_ELEVATOR), .mapGroup = MAP_GROUP(LILYCOVE_CITY_DEPARTMENT_STORE_ELEVATOR)}},
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_SURPRISE,
.conditions = {MATCH_MAP(LILYCOVE_CITY_DEPARTMENT_STORE_ELEVATOR)},
},
[COND_MSG_ICE_ROOM] =
{
.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 = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_SURPRISE,
.conditions = {MATCH_MAP(SHOAL_CAVE_LOW_TIDE_ICE_ROOM)},
},
[COND_MSG_ROUTE_117] =
{
.text = sCondMsg27,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE117), .mapGroup = MAP_GROUP(ROUTE117)}},
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_SURPRISE,
.conditions = {MATCH_MAP(ROUTE117)},
},
[COND_MSG_DRAGON_GROWL] =
{
.text = sCondMsg28,
.st = {.types = {.type1 = TYPE_DRAGON, .type2 = TYPE_DRAGON}},
.stFlags = ST_FLAGS_TYPE,
.mm = {.mapSec = {.mapSec = MAPSEC_SKY_PILLAR}},
.mmFlags = MM_FLAGS_MAPSEC,
.emotion = FOLLOWER_EMOTION_UPSET,
.conditions = {
MATCH_TYPES(TYPE_DRAGON, TYPE_DRAGON),
MATCH_MAPSEC(MAPSEC_SKY_PILLAR),
}
},
[COND_MSG_FEAR] =
{
.text = (u8*)sFearTexts,
.textSpread = 1,
.st = {.types = {.type1 = TYPE_GHOST, .type2 = TYPE_NOT_TYPE1}},
.stFlags = ST_FLAGS_TYPE,
.mm = {.mapSec = {.mapSec = MAPSEC_MT_PYRE}},
.mmFlags = MM_FLAGS_MAPSEC,
.wt = {.song = MUS_MT_PYRE},
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_UPSET,
.conditions = {
MATCH_NOT_TYPES(TYPE_GHOST, TYPE_GHOST),
MATCH_MAPSEC(MAPSEC_MT_PYRE),
MATCH_MUSIC(MUS_MT_PYRE),
}
},
[COND_MSG_FIRE_RAIN] =
{
.text = sCondMsg31,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_FIRE}},
.stFlags = ST_FLAGS_TYPE,
.wt = {.weather = {.weather1 = WEATHER_RAIN, .weather2 = WEATHER_RAIN_THUNDERSTORM}},
.wtFlags = WT_FLAGS_WEATHER,
.emotion = FOLLOWER_EMOTION_UPSET,
.conditions = {
MATCH_TYPES(TYPE_FIRE, TYPE_FIRE),
MATCH_WEATHER(WEATHER_RAIN, WEATHER_RAIN_THUNDERSTORM),
}
},
[COND_MSG_FROZEN] =
{
.text = sCondMsg32,
.st = {.status = STATUS1_FREEZE},
.stFlags = ST_FLAGS_STATUS,
.emotion = FOLLOWER_EMOTION_UPSET,
.conditions = {
MATCH_STATUS(STATUS1_FREEZE),
}
},
[COND_MSG_SEASIDE] =
{
.text = (u8*)sSeaTexts,
.textSpread = 1,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_OCEAN_WATER, .distance = 5}},
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_NEAR_MB(MB_OCEAN_WATER, 5)},
},
[COND_MSG_WATERFALL] =
{
.text = sCondMsg36,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_WATERFALL, .distance = 5}},
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_NEAR_MB(MB_WATERFALL, 5)},
},
[COND_MSG_RAIN] =
{
.text = sCondMsg37,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_NOT_TYPE1}},
.stFlags = ST_FLAGS_TYPE,
.wt = {.weather = {.weather1 = WEATHER_RAIN, .weather2 = WEATHER_RAIN_THUNDERSTORM}},
.wtFlags = WT_FLAGS_WEATHER,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {
MATCH_NOT_TYPES(TYPE_FIRE, TYPE_FIRE),
MATCH_WEATHER(WEATHER_RAIN, WEATHER_RAIN_THUNDERSTORM)
}
},
[COND_MSG_REFLECTION] =
{
.text = sCondMsg38,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_POND_WATER, .distance = 1}},
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_PENSIVE,
.conditions = {MATCH_NEAR_MB(MB_POND_WATER, 1)},
},
[COND_MSG_LEAVES] =
{
.text = sCondMsg39,
.mm = {.mapSec = {.mapSec = MAPSEC_PETALBURG_WOODS}},
.mmFlags = MM_FLAGS_MAPSEC,
.emotion = FOLLOWER_EMOTION_PENSIVE,
.conditions = {MATCH_MAPSEC(MAPSEC_PETALBURG_WOODS)},
},
[COND_MSG_ICE] =
{
.text = (u8*)sIceTexts,
.textSpread = 1,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_ICE, .distance = 1}},
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_PENSIVE,
.conditions = {MATCH_NEAR_MB(MB_ICE, 1)},
},
[COND_MSG_BURN] =
{
.text = sCondMsg42,
.st = {.status = STATUS1_BURN},
.stFlags = ST_FLAGS_STATUS,
.emotion = FOLLOWER_EMOTION_SAD,
.conditions = {MATCH_STATUS(STATUS1_BURN)},
},
[COND_MSG_DAY] =
{
.text = (u8*)sDayTexts,
.textSpread = 1,
.wt = {.timeOfDay = TIME_OF_DAY_DAY},
.wtFlags = 3, // time
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_TIME_OF_DAY(TIME_OF_DAY_DAY)},
},
[COND_MSG_NIGHT] =
{
.text = (u8*)sNightTexts,
.textSpread = 1,
.wt = {.timeOfDay = TIME_OF_DAY_NIGHT},
.wtFlags = 3, // time
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions = {MATCH_TIME_OF_DAY(TIME_OF_DAY_NIGHT)},
},
};
// Pool of "unconditional" follower messages
const struct FollowerMessagePool gFollowerBasicMessages[FOLLOWER_EMOTION_LENGTH] = {
[FOLLOWER_EMOTION_HAPPY] = {gFollowerHappyMessages, EventScript_FollowerGeneric, N_FOLLOWER_HAPPY_MESSAGES},
[FOLLOWER_EMOTION_NEUTRAL] = {gFollowerNeutralMessages, EventScript_FollowerGeneric, N_FOLLOWER_NEUTRAL_MESSAGES},
[FOLLOWER_EMOTION_SAD] = {gFollowerSadMessages, EventScript_FollowerGeneric, N_FOLLOWER_SAD_MESSAGES},
[FOLLOWER_EMOTION_UPSET] = {gFollowerUpsetMessages, EventScript_FollowerGeneric, N_FOLLOWER_UPSET_MESSAGES},
[FOLLOWER_EMOTION_ANGRY] = {gFollowerAngryMessages, EventScript_FollowerGeneric, N_FOLLOWER_ANGRY_MESSAGES},
[FOLLOWER_EMOTION_PENSIVE] = {gFollowerPensiveMessages, EventScript_FollowerGeneric, N_FOLLOWER_PENSIVE_MESSAGES},
[FOLLOWER_EMOTION_LOVE] = {gFollowerLoveMessages, EventScript_FollowerGeneric, N_FOLLOWER_LOVE_MESSAGES},
[FOLLOWER_EMOTION_SURPRISE] = {gFollowerSurpriseMessages, EventScript_FollowerGeneric, N_FOLLOWER_SURPRISE_MESSAGES},
[FOLLOWER_EMOTION_CURIOUS] = {gFollowerCuriousMessages, EventScript_FollowerGeneric, N_FOLLOWER_CURIOUS_MESSAGES},
[FOLLOWER_EMOTION_MUSIC] = {gFollowerMusicMessages, EventScript_FollowerGeneric, N_FOLLOWER_MUSIC_MESSAGES},
[FOLLOWER_EMOTION_POISONED] = {gFollowerPoisonedMessages, EventScript_FollowerGeneric, N_FOLLOWER_POISONED_MESSAGES},
};

View File

@ -441,13 +441,3 @@ void ClearPokemonCrySongs(void)
{
CpuFill16(0, gPokemonCrySongs, MAX_POKEMON_CRIES * sizeof(struct PokemonCrySong));
}
// TODO: Needs to be updated if compiling for a different processor than the GBA's
bool8 IsAccurateGBA(void) { // tests to see whether running on either an accurate emulator in >=2020, or real hardware
u32 code[5] = {0xFF1EE12F, 0xE1DF00B0, 0xE12FFF1E, 0xAAAABBBB, 0xCCCCDDDD}; // ARM: _;ldrh r0, [pc];bx lr
u32 func = (u32) &code[0];
if (func & 3) // not word aligned; safer to just return false here
return FALSE;
func = (func & ~3) | 0x2; // misalign PC to test PC-relative loading
return ((u32 (*)(void)) func)() == code[3] >> 16;
}

View File

@ -206,7 +206,6 @@ EWRAM_DATA static u16 sAmbientCrySpecies = 0;
EWRAM_DATA static bool8 sIsAmbientCryWaterMon = FALSE;
EWRAM_DATA struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4] = {0};
static const struct WarpData sDummyWarpData =
{
.mapGroup = MAP_GROUP(UNDEFINED),
@ -2130,6 +2129,7 @@ static bool32 ReturnToFieldLocal(u8 *state)
case 3:
return TRUE;
}
return FALSE;
}

View File

@ -512,13 +512,12 @@ static u8 UpdateTimeOfDayPaletteFade(void)
// First pply TOD blend to relevant subset of palettes
if (gPaletteFade.objPaletteToggle) { // Sprite palettes, don't blend those with tags
u8 i;
u16 j = 1;
u32 i;
u32 j = 1;
for (i = 0; i < 16; i++, j <<= 1) { // Mask out palettes that should not be light blended
if ((selectedPalettes & j) && !(GetSpritePaletteTagByPaletteNum(i) >> 15))
timePalettes |= j;
}
} else { // tile palettes, don't blend [13, 15]
timePalettes = selectedPalettes & 0x1FFF;
}

View File

@ -3360,36 +3360,23 @@ static void PrintRibbonCount(void)
PrintTextOnWindow(AddWindowFromTemplateList(sPageSkillsTemplate, PSS_DATA_WINDOW_SKILLS_RIBBON_COUNT), text, x, 1, 0, 0);
}
// Based on https://www.pokecommunity.com/showpost.php?p=10024409&postcount=21
static void BufferStat(u8 *dst, s8 natureMod, u32 stat, u32 strId, u32 n) {
static const u8 textNatureMinus[] = _("{COLOR_HIGHLIGHT_SHADOW}{BLUE}{TRANSPARENT}{07}"); // Blue
static const u8 textNaturePlus[] = _("{COLOR_HIGHLIGHT_SHADOW}{05}{TRANSPARENT}{06}"); // Red
static const u8 textNatureNone[] = _("{COLOR_HIGHLIGHT_SHADOW}{01}{TRANSPARENT}{DARK_GRAY}"); // Black
u8 *txtPtr;
if (natureMod == 0)
txtPtr = StringCopy(dst, textNatureNone);
else if (natureMod > 0)
txtPtr = StringCopy(dst, textNaturePlus);
else
txtPtr = StringCopy(dst, textNatureMinus);
ConvertIntToDecimalStringN(txtPtr, stat, STR_CONV_MODE_RIGHT_ALIGN, n);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(strId, dst);
}
static void BufferLeftColumnStats(void)
{
u8 *currentHPString = Alloc(20);
u8 *maxHPString = Alloc(20);
u8 *attackString = Alloc(20);
u8 *defenseString = Alloc(20);
const s8 *natureMod = gNatureStatTable[sMonSummaryScreen->summary.nature];
u8 *currentHPString = Alloc(8);
u8 *maxHPString = Alloc(8);
u8 *attackString = Alloc(8);
u8 *defenseString = Alloc(8);
ConvertIntToDecimalStringN(currentHPString, sMonSummaryScreen->summary.currentHP, STR_CONV_MODE_RIGHT_ALIGN, 3);
ConvertIntToDecimalStringN(maxHPString, sMonSummaryScreen->summary.maxHP, STR_CONV_MODE_RIGHT_ALIGN, 3);
ConvertIntToDecimalStringN(attackString, sMonSummaryScreen->summary.atk, STR_CONV_MODE_RIGHT_ALIGN, 7);
ConvertIntToDecimalStringN(defenseString, sMonSummaryScreen->summary.def, STR_CONV_MODE_RIGHT_ALIGN, 7);
DynamicPlaceholderTextUtil_Reset();
BufferStat(currentHPString, 0, sMonSummaryScreen->summary.currentHP, 0, 3);
BufferStat(maxHPString, 0, sMonSummaryScreen->summary.maxHP, 1, 3);
BufferStat(attackString, natureMod[STAT_ATK - 1], sMonSummaryScreen->summary.atk, 2, 7);
BufferStat(defenseString, natureMod[STAT_DEF - 1], sMonSummaryScreen->summary.def, 3, 7);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, currentHPString);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, maxHPString);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(2, attackString);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(3, defenseString);
DynamicPlaceholderTextUtil_ExpandPlaceholders(gStringVar4, sStatsLeftColumnLayout);
Free(currentHPString);
@ -3405,12 +3392,14 @@ static void PrintLeftColumnStats(void)
static void BufferRightColumnStats(void)
{
const s8 *natureMod = gNatureStatTable[sMonSummaryScreen->summary.nature];
ConvertIntToDecimalStringN(gStringVar1, sMonSummaryScreen->summary.spatk, STR_CONV_MODE_RIGHT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar2, sMonSummaryScreen->summary.spdef, STR_CONV_MODE_RIGHT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar3, sMonSummaryScreen->summary.speed, STR_CONV_MODE_RIGHT_ALIGN, 3);
DynamicPlaceholderTextUtil_Reset();
BufferStat(gStringVar1, natureMod[STAT_SPATK - 1], sMonSummaryScreen->summary.spatk, 0, 3);
BufferStat(gStringVar2, natureMod[STAT_SPDEF - 1], sMonSummaryScreen->summary.spdef, 1, 3);
BufferStat(gStringVar3, natureMod[STAT_SPEED - 1], sMonSummaryScreen->summary.speed, 2, 3);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, gStringVar1);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, gStringVar2);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(2, gStringVar3);
DynamicPlaceholderTextUtil_ExpandPlaceholders(gStringVar4, sStatsRightColumnLayout);
}

View File

@ -1019,7 +1019,8 @@ bool8 ScrCmd_applymovement(struct ScriptContext *ctx)
}
ScriptMovement_StartObjectMovementScript(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, movementScript);
sMovingNpcId = localId;
if (localId != OBJ_EVENT_ID_FOLLOWER && !FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT)) { // Force follower into pokeball
// Force follower into pokeball
if (localId != OBJ_EVENT_ID_FOLLOWER && !FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT)) {
objEvent = GetFollowerObject();
// return early if no follower or in shadowing state
if (objEvent == NULL || gSprites[objEvent->spriteId].data[1] == 0)

View File

@ -867,7 +867,10 @@ static void BuyMenuCollectObjectEventData(void)
u8 objEventId = GetObjectEventIdByXY(facingX - 4 + x, facingY - 2 + y);
// skip if invalid or an overworld pokemon that is not following the player
if (objEventId != OBJECT_EVENTS_COUNT && !(gObjectEvents[objEventId].active && gObjectEvents[objEventId].graphicsId == OBJ_EVENT_GFX_OW_MON && gObjectEvents[objEventId].localId != OBJ_EVENT_ID_FOLLOWER))
if (objEventId != OBJECT_EVENTS_COUNT
&& !(gObjectEvents[objEventId].active
&& gObjectEvents[objEventId].graphicsId == OBJ_EVENT_GFX_OW_MON
&& gObjectEvents[objEventId].localId != OBJ_EVENT_ID_FOLLOWER))
{
sShopData->viewportObjects[numObjects][OBJ_EVENT_ID] = objEventId;
sShopData->viewportObjects[numObjects][X_COORD] = x;

View File

@ -152,101 +152,112 @@ static const struct SpriteFrameImage sSpriteImageTable_HeartIcon[] =
static const struct SpriteFrameImage sSpriteImageTable_Emotes[] =
{
{ .data = (u8 *)sEmotion_Gfx+0*0x80, .size = 0x80}, // FOLLOWER_EMOTION_HAPPY
{ .data = (u8 *)sEmotion_Gfx+1*0x80, .size = 0x80}, // FOLLOWER_EMOTION_HAPPY
{ .data = (u8 *)sEmotion_Gfx+2*0x80, .size = 0x80}, // FOLLOWER_EMOTION_NEUTRAL
{ .data = (u8 *)sEmotion_Gfx+3*0x80, .size = 0x80}, // FOLLOWER_EMOTION_NEUTRAL
{ .data = (u8 *)sEmotion_Gfx+4*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SAD
{ .data = (u8 *)sEmotion_Gfx+5*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SAD
{ .data = (u8 *)sEmotion_Gfx+6*0x80, .size = 0x80}, // FOLLOWER_EMOTION_UPSET
{ .data = (u8 *)sEmotion_Gfx+7*0x80, .size = 0x80}, // FOLLOWER_EMOTION_UPSET
{ .data = (u8 *)sEmotion_Gfx+8*0x80, .size = 0x80}, // FOLLOWER_EMOTION_ANGRY
{ .data = (u8 *)sEmotion_Gfx+9*0x80, .size = 0x80}, // FOLLOWER_EMOTION_ANGRY
{ .data = (u8 *)sEmotion_Gfx+10*0x80, .size = 0x80}, // FOLLOWER_EMOTION_PENSIVE
{ .data = (u8 *)sEmotion_Gfx+11*0x80, .size = 0x80}, // FOLLOWER_EMOTION_PENSIVE
{ .data = (u8 *)sEmotion_Gfx+12*0x80, .size = 0x80}, // FOLLOWER_EMOTION_LOVE
{ .data = (u8 *)sEmotion_Gfx+13*0x80, .size = 0x80}, // FOLLOWER_EMOTION_LOVE
{ .data = (u8 *)sEmotion_Gfx+14*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SURPRISE
{ .data = (u8 *)sEmotion_Gfx+15*0x80, .size = 0x80}, // FOLLOWER_EMOTION_SURPRISE
{ .data = (u8 *)sEmotion_Gfx+16*0x80, .size = 0x80}, // FOLLOWER_EMOTION_CURIOUS
{ .data = (u8 *)sEmotion_Gfx+17*0x80, .size = 0x80}, // FOLLOWER_EMOTION_CURIOUS
{ .data = (u8 *)sEmotion_Gfx+18*0x80, .size = 0x80}, // FOLLOWER_EMOTION_MUSIC
{ .data = (u8 *)sEmotion_Gfx+19*0x80, .size = 0x80}, // FOLLOWER_EMOTION_MUSIC
{ .data = (u8 *)sEmotion_Gfx+20*0x80, .size = 0x80}, // FOLLOWER_EMOTION_POISONED
{ .data = (u8 *)sEmotion_Gfx+21*0x80, .size = 0x80}, // FOLLOWER_EMOTION_POISONED
overworld_frame(sEmotion_Gfx, 2, 2, 0), // FOLLOWER_EMOTION_HAPPY
overworld_frame(sEmotion_Gfx, 2, 2, 1), // FOLLOWER_EMOTION_HAPPY
overworld_frame(sEmotion_Gfx, 2, 2, 2), // FOLLOWER_EMOTION_NEUTRAL
overworld_frame(sEmotion_Gfx, 2, 2, 3), // FOLLOWER_EMOTION_NEUTRAL
overworld_frame(sEmotion_Gfx, 2, 2, 4), // FOLLOWER_EMOTION_SAD
overworld_frame(sEmotion_Gfx, 2, 2, 5), // FOLLOWER_EMOTION_SAD
overworld_frame(sEmotion_Gfx, 2, 2, 6), // FOLLOWER_EMOTION_UPSET
overworld_frame(sEmotion_Gfx, 2, 2, 7), // FOLLOWER_EMOTION_UPSET
overworld_frame(sEmotion_Gfx, 2, 2, 8), // FOLLOWER_EMOTION_ANGRY
overworld_frame(sEmotion_Gfx, 2, 2, 9), // FOLLOWER_EMOTION_ANGRY
overworld_frame(sEmotion_Gfx, 2, 2, 10), // FOLLOWER_EMOTION_PENSIVE
overworld_frame(sEmotion_Gfx, 2, 2, 11), // FOLLOWER_EMOTION_PENSIVE
overworld_frame(sEmotion_Gfx, 2, 2, 12), // FOLLOWER_EMOTION_LOVE
overworld_frame(sEmotion_Gfx, 2, 2, 13), // FOLLOWER_EMOTION_LOVE
overworld_frame(sEmotion_Gfx, 2, 2, 14), // FOLLOWER_EMOTION_SURPRISE
overworld_frame(sEmotion_Gfx, 2, 2, 15), // FOLLOWER_EMOTION_SURPRISE
overworld_frame(sEmotion_Gfx, 2, 2, 16), // FOLLOWER_EMOTION_CURIOUS
overworld_frame(sEmotion_Gfx, 2, 2, 17), // FOLLOWER_EMOTION_CURIOUS
overworld_frame(sEmotion_Gfx, 2, 2, 18), // FOLLOWER_EMOTION_MUSIC
overworld_frame(sEmotion_Gfx, 2, 2, 19), // FOLLOWER_EMOTION_MUSIC
overworld_frame(sEmotion_Gfx, 2, 2, 20), // FOLLOWER_EMOTION_POISONED
overworld_frame(sEmotion_Gfx, 2, 2, 21), // FOLLOWER_EMOTION_POISONED
};
static const union AnimCmd sSpriteAnim_Emotes0[] = {
static const union AnimCmd sSpriteAnim_Emotes0[] =
{
ANIMCMD_FRAME(0*2, 30),
ANIMCMD_FRAME(0*2+1, 25),
ANIMCMD_FRAME(0*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes1[] = {
static const union AnimCmd sSpriteAnim_Emotes1[] =
{
ANIMCMD_FRAME(1*2, 30),
ANIMCMD_FRAME(1*2+1, 25),
ANIMCMD_FRAME(1*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes2[] = {
static const union AnimCmd sSpriteAnim_Emotes2[] =
{
ANIMCMD_FRAME(2*2, 30),
ANIMCMD_FRAME(2*2+1, 25),
ANIMCMD_FRAME(2*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes3[] = {
static const union AnimCmd sSpriteAnim_Emotes3[] =
{
ANIMCMD_FRAME(3*2, 30),
ANIMCMD_FRAME(3*2+1, 25),
ANIMCMD_FRAME(3*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes4[] = {
static const union AnimCmd sSpriteAnim_Emotes4[] =
{
ANIMCMD_FRAME(4*2, 30),
ANIMCMD_FRAME(4*2+1, 25),
ANIMCMD_FRAME(4*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes5[] = {
static const union AnimCmd sSpriteAnim_Emotes5[] =
{
ANIMCMD_FRAME(5*2, 30),
ANIMCMD_FRAME(5*2+1, 25),
ANIMCMD_FRAME(5*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes6[] = {
static const union AnimCmd sSpriteAnim_Emotes6[] =
{
ANIMCMD_FRAME(6*2, 30),
ANIMCMD_FRAME(6*2+1, 25),
ANIMCMD_FRAME(6*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes7[] = {
static const union AnimCmd sSpriteAnim_Emotes7[] =
{
ANIMCMD_FRAME(7*2, 30),
ANIMCMD_FRAME(7*2+1, 25),
ANIMCMD_FRAME(7*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes8[] = {
static const union AnimCmd sSpriteAnim_Emotes8[] =
{
ANIMCMD_FRAME(8*2, 30),
ANIMCMD_FRAME(8*2+1, 25),
ANIMCMD_FRAME(8*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes9[] = {
static const union AnimCmd sSpriteAnim_Emotes9[] =
{
ANIMCMD_FRAME(9*2, 30),
ANIMCMD_FRAME(9*2+1, 25),
ANIMCMD_FRAME(9*2, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_Emotes10[] = {
static const union AnimCmd sSpriteAnim_Emotes10[] =
{
ANIMCMD_FRAME(10*2, 30),
ANIMCMD_FRAME(10*2+1, 25),
ANIMCMD_FRAME(10*2, 30),
@ -271,7 +282,8 @@ static const union AnimCmd *const sSpriteAnimTable_Icons[] =
sSpriteAnim_Icons2
};
static const union AnimCmd *const sSpriteAnimTable_Emotes[] = {
static const union AnimCmd *const sSpriteAnimTable_Emotes[] =
{
sSpriteAnim_Emotes0,
sSpriteAnim_Emotes1,
sSpriteAnim_Emotes2,
@ -311,8 +323,9 @@ static const struct SpriteTemplate sSpriteTemplate_HeartIcon =
.callback = SpriteCB_TrainerIcons
};
static const struct SpriteTemplate sSpriteTemplate_Emote = {
.tileTag = 0xffff,
static const struct SpriteTemplate sSpriteTemplate_Emote =
{
.tileTag = TAG_NONE,
.paletteTag = OBJ_EVENT_PAL_TAG_EMOTES,
.oam = &sOamData_Icons,
.anims = sSpriteAnimTable_Emotes,
@ -842,7 +855,8 @@ u8 FldEff_ExclamationMarkIcon(void)
u8 FldEff_QuestionMarkIcon(void)
{
u8 spriteId;
if (gFieldEffectArguments[7] >= 0) { // Use follower emotes
if (gFieldEffectArguments[7] >= 0) {
// Use follower emotes
u8 emotion = gFieldEffectArguments[7];
spriteId = CreateSpriteAtEnd(&sSpriteTemplate_Emote, 0, 0, 0x52);
if (spriteId == MAX_SPRITES)