• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Our weekly protagonist poll is now up! Vote for your favorite Conquest protagonist in the poll by clicking here.
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

[SOLVED] Adding custom pokeballs to pokeemerald, game softlocks after using ball in battle

  • 23
    Posts
    7
    Years
    • Seen Nov 28, 2023
    EDIT: The problem was solved. I'm not exactly sure where it was, but I started over with a clean copy of my working directory and the problem disappeared.

    Hi all!

    I've been trying to add a new pokeball into pokeemerald, but I haven't been able to make it work. As background information, I'm using Dizzy's battle engine + item expansion + pokemon expansion (as of 3rd October, 2020).

    I've studied all the places that Dizzy has modified to make new pokeballs, but mine is not working quite right. The rom compiles without errors, I can pick up the new ball in overworld and it is properly visible in bag. However, when I try to use the ball in battle, the text "Player used New Ball!" appears, after which the game softlocks (music plays, but no ball throw animation or anything else happens from that point onward). I just can't find what I'm missing at this point, and I would hugely appreciate any help on this!

    I have placed the required indexed sprites and palettes in their proper folders. Here are the file modifications I've made:

    data/battle_scripts_2.s
    Code:
    	.align 2
    gBattlescriptsForBallThrow:: @ 82DBD08
    	.4byte BattleScript_BallThrow @ ITEM_NONE
    	.4byte BattleScript_BallThrow @ ITEM_MASTER_BALL
    ...
    	.4byte BattleScript_BallThrow @ ITEM_BEAST_BALL
    	.4byte BattleScript_BallThrow @ ITEM_PREMIER_BALL
    +	.4byte BattleScript_BallThrow @ ITEM_NEW_BALL
    
    	.align 2
    gBattlescriptsForUsingItem:: @ 82DBD3C


    include/constants/items.h
    Code:
    #define ITEM_MASTER_BALL 1
    ...
    #define ITEM_PREMIER_BALL 27
    +#define ITEM_NEW_BALL 28
    
    #define LAST_BALL ITEM_NEW_BALL


    include/data/graphics.h
    Code:
    extern const u32 gInterfaceGfx_BeastBall[];
    extern const u32 gInterfacePal_BeastBall[];
    +extern const u32 gInterfaceGfx_NewBall[];
    +extern const u32 gInterfacePal_NewBall[];
    extern const u32 gOpenPokeballGfx[];
    
    extern const u32 gItemIcon_BeastBall[];
    extern const u32 gItemIconPalette_BeastBall[];
    +extern const u32 gItemIcon_NewBall[];
    +extern const u32 gItemIconPalette_NewBall[];
    // Medicine
    extern const u32 gItemIcon_Potion[];


    include/pokeball.h
    Code:
    enum
    {
        BALL_POKE,
    ...
        BALL_BEAST,
    +    BALL_NEW,
        POKEBALL_COUNT
    };


    src/battle_anim_throw.c
    Code:
    #define TAG_PARTICLES_BEASTBALL   65056
    +#define TAG_PARTICLES_NEWBALL   65057
    
    static const struct CompressedSpriteSheet sBallParticleSpriteSheets[] =
    {
        [BALL_POKE]     = {gBattleAnimSpriteGfx_Particles,      0x100, TAG_PARTICLES_POKEBALL},
    ...
        [BALL_BEAST]    = {gBattleAnimSpriteGfx_Particles,      0x100, TAG_PARTICLES_BEASTBALL},
    +    [BALL_NEW]    = {gBattleAnimSpriteGfx_Particles,      0x100, TAG_PARTICLES_NEWBALL},
    };
    
    static const struct CompressedSpritePalette sBallParticlePalettes[] =
    {
        [BALL_POKE]     = {gBattleAnimSpritePal_CircleImpact,   TAG_PARTICLES_POKEBALL},
    ...
        [BALL_BEAST]    = {gBattleAnimSpritePal_CircleImpact,   TAG_PARTICLES_BEASTBALL},
    +    [BALL_NEW]    = {gBattleAnimSpritePal_CircleImpact,   TAG_PARTICLES_NEWBALL},
    };
    
    
    static const u8 sBallParticleAnimNums[POKEBALL_COUNT] =
    {
        [BALL_POKE]    = 0,
    ...
        [BALL_BEAST] = 5,
    +    [BALL_NEW] = 0,
    };
    
    static const TaskFunc sBallParticleAnimationFuncs[] =
    {
        [BALL_POKE] = PokeBallOpenParticleAnimation,
    ...
        [BALL_BEAST] = UltraBallOpenParticleAnimation,
    +    [BALL_NEW] = MasterBallOpenParticleAnimation
    };
    
    const u16 gBallOpenFadeColors[] =
    {
        [BALL_POKE] = RGB(31, 22, 30),
    ...
        [BALL_BEAST] = RGB(31, 31, 15),
    +    [BALL_NEW] = RGB(31, 31, 15),
    };
    
    u8 ItemIdToBallId(u16 ballItem)
    {
        switch (ballItem)
        {
        case ITEM_MASTER_BALL:
            return BALL_MASTER;
    ...
        case ITEM_BEAST_BALL:
            return BALL_BEAST;
    +    case ITEM_NEW_BALL:
    +        return BALL_NEW;
        default:
            return BALL_POKE;
        }
    }


    src/battle_script_commands.c
    Code:
    static void Cmd_handleballthrow(void)
    {
    ...
                case ITEM_QUICK_BALL:
                    if (gBattleResults.battleTurnCounter == 0)
                        ballMultiplier = 40;
                    break;
    +            case ITEM_NEW_BALL:
    +                if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_FIRE))
    +                    ballMultiplier = 30;
    +                break;
                case ITEM_DUSK_BALL:
    ...


    src/data/graphics/interface_pokeballs.h
    Code:
    const u32 gInterfaceGfx_BeastBall[] = INCBIN_U32("graphics/interface/ball/beast.4bpp.lz");
    const u32 gInterfacePal_BeastBall[] = INCBIN_U32("graphics/interface/ball/beast.gbapal.lz");
    
    +const u32 gInterfaceGfx_NewBall[] = INCBIN_U32("graphics/interface/ball/new.4bpp.lz");
    +const u32 gInterfacePal_NewBall[] = INCBIN_U32("graphics/interface/ball/new.gbapal.lz");
    
    const u32 gOpenPokeballGfx[] = INCBIN_U32("graphics/interface/ball_open.4bpp.lz");

    src/data/graphics/items.h
    Code:
    const u32 gItemIcon_LureBall[] = INCBIN_U32("graphics/items/icons/lure_ball.4bpp.lz");
    const u32 gItemIconPalette_LureBall[] = INCBIN_U32("graphics/items/icon_palettes/lure_ball.gbapal.lz");
    
    +const u32 gItemIcon_NewBall[] = INCBIN_U32("graphics/items/icons/new_ball.4bpp.lz");
    +const u32 gItemIconPalette_NewBall[] = INCBIN_U32("graphics/items/icon_palettes/new_ball.gbapal.lz");
    
    const u32 gItemIcon_MoonBall[] = INCBIN_U32("graphics/items/icons/moon_ball.4bpp.lz");
    const u32 gItemIconPalette_MoonBall[] = INCBIN_U32("graphics/items/icon_palettes/moon_ball.gbapal.lz");


    src/data/items.h
    Code:
        [ITEM_BEAST_BALL] =
        {
            .name = _("Beast Ball"),
            .itemId = ITEM_BEAST_BALL,
            .price = 10,
            .description = sBeastBallDesc,
            .pocket = POCKET_POKE_BALLS,
            .type = 11,
            .fieldUseFunc = NULL,
            .battleUsage = 2,
            .battleUseFunc = ItemUseInBattle_PokeBall,
            .secondaryId = 26, // To Do
        },
    
    +    [ITEM_NEW_BALL] =
    +    {
    +        .name = _("New Ball"),
    +        .itemId = ITEM_NEW_BALL,
    +        .price = 2000,
    +        .description = sNewBallDesc,
    +        .pocket = POCKET_POKE_BALLS,
    +        .type = 11,
    +        .fieldUseFunc = NULL,
    +        .battleUsage = 2,
    +        .battleUseFunc = ItemUseInBattle_PokeBall,
    +        .secondaryId = 27,
    +    },
    	
    // Medicine
    
        [ITEM_POTION] =


    src/data/item_icon_table.h
    Code:
    const u32 *const gItemIconTable[][2] =
    {
    ...
        [ITEM_WATER_MEMORY] = {gItemIcon_WaterMemory, gItemIconPalette_WaterMemory},
    +    [ITEM_NEW_BALL] = {gItemIcon_NewBall, gItemIconPalette_NewBall},
    };


    src/data/text/item_descriptions.h
    Code:
    static const u8 sShinyCharmDesc[] = _(
    	"A charm that will\n"
        "raise the chance\n"
        "of Shiny Pokémon.");
    
    	
    +static const u8 sNewBallDesc[] = _(
    +    "A BALL that works\n"
    +    "well on FIRE-type"
    +    "POKéMON.");


    src/pokeball.c
    Code:
    #define GFX_TAG_BEASTBALL   55026
    +#define GFX_TAG_NEWBALL   55027
    
    const struct CompressedSpriteSheet gBallSpriteSheets[POKEBALL_COUNT] =
    {
        {gInterfaceGfx_PokeBall,    384, GFX_TAG_POKEBALL},
    ...
        {gInterfaceGfx_BeastBall,   384, GFX_TAG_BEASTBALL},
    +    {gInterfaceGfx_NewBall,   384, GFX_TAG_NEWBALL},
    };
    
    const struct CompressedSpritePalette gBallSpritePalettes[POKEBALL_COUNT] =
    {
        {gInterfacePal_PokeBall,    GFX_TAG_POKEBALL},
    ...
        {gInterfacePal_BeastBall,   GFX_TAG_BEASTBALL},
    +    {gInterfacePal_NewBall,   GFX_TAG_NEWBALL},
    };
    
    const struct SpriteTemplate gBallSpriteTemplates[POKEBALL_COUNT] =
    {
        {
            .tileTag = GFX_TAG_POKEBALL,
            .paletteTag = GFX_TAG_POKEBALL,
            .oam = &sBallOamData,
            .anims = sBallAnimSequences,
            .images = NULL,
            .affineAnims = sAffineAnim_BallRotate,
            .callback = SpriteCB_TestBallThrow,
        },
    ...
        {
            .tileTag = GFX_TAG_BEASTBALL,
            .paletteTag = GFX_TAG_BEASTBALL,
            .oam = &sBallOamData,
            .anims = sBallAnimSequences,
            .images = NULL,
            .affineAnims = sAffineAnim_BallRotate,
            .callback = SpriteCB_TestBallThrow,
        },
    +    {
    +        .tileTag = GFX_TAG_NEWBALL,
    +        .paletteTag = GFX_TAG_NEWBALL,
    +        .oam = &sBallOamData,
    +        .anims = sBallAnimSequences,
    +        .images = NULL,
    +        .affineAnims = sAffineAnim_BallRotate,
    +        .callback = SpriteCB_TestBallThrow,
    +    },
    };
     
    Last edited:
    Back
    Top