Skip to content

Add New Partner Battle

judicornadamsfoster edited this page Jun 20, 2026 · 2 revisions

Want to add another Partner Battle like how you team up with Steven in Mossdeep to defeat Team Magma and use the correct backsprite for your partner?

This example adds Leaf as the partner against the placeholder Brendan and May but any of this can be customised to other trainers.
doublebattle_leaf

Check the compare here or the branch here


include/constants/battle_frontier.h

add after the last entry under // Special trainer battles. (line 35)

#define SPECIAL_BATTLE_LEAF 11

include/constants/flags.h

rename 3 unused flags:

#define FLAG_INTERACTED_WITH_LEAF_BEFORE_BATTLE
#define FLAG_PARTNER_HIDE_ENEMY_TRAINERS
#define FLAG_LEAF_PARTNER_BATTLE

include/constants/trainers.h

add after #define TRAINER_STEVEN_PARTNER 3075

#define TRAINER_LEAF_PARTNER                3076

src/battle_tower.c

after the #include section near the top, add after extern const u8 MossdeepCity_SpaceCenter_2F_EventScript_TabithaTrainer[];

extern const u8 PartnerBattle_EventScript_EnemyTrainer1[];
extern const u8 PartnerBattle_EventScript_EnemyTrainer2[];

__

this is where you select your partner's pokemon

after the section that begins struct then continues to } static const sStevenMons[MULTI_PARTY_SIZE] =
add on line 801 (after the final }; (line 800) but before #include "data/battle_frontier/battle_tent.h" (line 802) )


struct
{
    u16 species;
    u8 fixedIV;
    u8 level;
    u8 nature;
    u8 evs[NUM_STATS];
    u16 moves[MAX_MON_MOVES];
} static const sLeafMons[MULTI_PARTY_SIZE] =
{
    {
        .species = SPECIES_EXEGGUTOR,
        .fixedIV = MAX_PER_STAT_IVS,
        .level = 42,
        .nature = NATURE_BRAVE,
        .evs = {0, 252, 252, 0, 6, 0},
        .moves = {MOVE_EGG_BOMB, MOVE_STOMP, MOVE_POISON_POWDER, MOVE_SOLAR_BEAM}
    },
    {
        .species = SPECIES_ARCANINE,
        .fixedIV = MAX_PER_STAT_IVS,
        .level = 43,
        .nature = NATURE_IMPISH,
        .evs = {252, 0, 0, 0, 6, 252},
        .moves = {MOVE_FLAMETHROWER, MOVE_EXTREME_SPEED, MOVE_AGILITY, MOVE_TAKE_DOWN}
    },
    {
        .species = SPECIES_SEADRA,
        .fixedIV = MAX_PER_STAT_IVS,
        .level = 44,
        .nature = NATURE_ADAMANT,
        .evs = {0, 252, 0, 0, 252, 6},
        .moves = {MOVE_LEER, MOVE_DRAGON_DANCE, MOVE_WATER_GUN, MOVE_TWISTER}
    }
};

__

in section u8 GetFrontierOpponentClass(u16 trainerId)

around line 1490 after
else if (trainerId == TRAINER_STEVEN_PARTNER)
{
trainerClass = gTrainers[TRAINER_STEVEN].trainerClass;
}

add

    else if (trainerId == TRAINER_LEAF_PARTNER)
    {
        trainerClass = gTrainers[TRAINER_LEAF].trainerClass;
    }

__

in section void GetFrontierTrainerName(u8 *dst, u16 trainerId) (line 1556)

around line 1575 after
else if (trainerId == TRAINER_STEVEN_PARTNER)
{
for (i = 0; i < PLAYER_NAME_LENGTH; i++)
dst[i] = gTrainers[TRAINER_STEVEN].trainerName[i];
}

add

	else if (trainerId == TRAINER_LEAF_PARTNER)
    {
        for (i = 0; i < PLAYER_NAME_LENGTH; i++)
            dst[i] = gTrainers[TRAINER_LEAF].trainerName[i];
    }

__

in section void DoSpecialTrainerBattle(void)
after section case SPECIAL_BATTLE_STEVEN: (lines 2169 to 2180)
add

    case SPECIAL_BATTLE_LEAF:
        gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER;
        FillPartnerParty(TRAINER_LEAF_PARTNER);
        gApproachingTrainerId = 0;
		BattleSetup_ConfigureTrainerBattle(PartnerBattle_EventScript_EnemyTrainer1 + 1);
        gApproachingTrainerId = 1;
        BattleSetup_ConfigureTrainerBattle(PartnerBattle_EventScript_EnemyTrainer2 + 1);
        gPartnerTrainerId = TRAINER_LEAF_PARTNER;
        CreateTask(Task_StartBattleAfterTransition, 1);
        PlayMapChosenOrBattleBGM(0);
        BattleTransition_StartOnField(B_TRANSITION_BLUR);
        break;

to customise:
Partner - replace TRAINER_LEAF_PARTNER with chosen partner
Battle transition - replace B_TRANSITION_MAGMA with chosen transition
Enemy trainer 1 - replace PartnerBattle_EventScript_EnemyTrainer1_PartnerBattle with first enemy trainer from your map script
Enemy trainer 2 - replace PartnerBattle_EventScript_EnemyTrainer2_PartnerBattle with second enemy trainer from your map script

__

just above section static void FillPartnerParty(u16 trainerId) (line 3018)
under #define STEVEN_OTID 61226
add

#define LEAF_OTID 24601

__

in section static void FillPartnerParty(u16 trainerId)
after section if (trainerId == TRAINER_STEVEN_PARTNER) (lines 3029 to 3057)
add

    else if (trainerId == TRAINER_LEAF_PARTNER)
    {
        for (i = 0; i < MULTI_PARTY_SIZE; i++)
        {
            do
            {
                j = Random32();
            } while (IsShinyOtIdPersonality(LEAF_OTID, j) || sLeafMons[i].nature != GetNatureFromPersonality(j));
            CreateMon(&gPlayerParty[MULTI_PARTY_SIZE + i],
                      sLeafMons[i].species,
                      sLeafMons[i].level,
                      sLeafMons[i].fixedIV,
                      TRUE,
                      j,
                      OT_ID_PRESET, LEAF_OTID);
            for (j = 0; j < PARTY_SIZE; j++)
                SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_HP_EV + j, &sLeafMons[i].evs[j]);
            for (j = 0; j < MAX_MON_MOVES; j++)
                SetMonMoveSlot(&gPlayerParty[MULTI_PARTY_SIZE + i], sLeafMons[i].moves[j], j);
            SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_NAME, gTrainers[TRAINER_LEAF].trainerName);
            j = FEMALE;
            SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_GENDER, &j);
            CalculateMonStats(&gPlayerParty[MULTI_PARTY_SIZE + i]);
        }
    }

src/pokemon.c

in section const u8 *GetTrainerPartnerName(void) (line 6735) after Steven's section (lines 6739 to 6742)
add

        else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
        {
            return gTrainers[TRAINER_LEAF].trainerName;
		}

src/battle_controller_player_partner.c

in section static void PlayerPartnerHandleDrawTrainerPic(void) (line 1296)

add after section if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER) (lines 1303 to 1306)

	else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
    {
        trainerPicId = TRAINER_BACK_PIC_LEAF;
        xPos = 90;
        yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
    }

__ a few lines down, in the section // Use back pic only if the partner is Steven (line 1320)
after section if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER) (lines 1321 to 1331)
add

	else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
    {
        DecompressTrainerBackPic(trainerPicId, gActiveBattler);
        SetMultiuseSpriteTemplateToTrainerBack(trainerPicId, GetBattlerPosition(gActiveBattler));
        gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, xPos, yPos, GetBattlerSpriteSubpriority(gActiveBattler));

        gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
        gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
        gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
        gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
    }

__

in section static void PlayerPartnerHandleIntroTrainerBallThrow(void) (line 1794)
after section if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER) (lines 1811 to 1815)
add

	else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
    {
        u8 spriteId = TRAINER_BACK_PIC_LEAF;
        LoadCompressedPalette(gTrainerBackPicPaletteTable[spriteId].data, OBJ_PLTT_ID(paletteNum), PLTT_SIZE_4BPP);
    }

src/battle_intro.c

in section void HandleIntroSlide(u8 environment) (line 105)
replace all lines (lines 106 to 138) with:

{
    u8 taskId;

    if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
    {
        taskId = CreateTask(sBattleIntroSlideFuncs[environment], 0);
    }
    else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
    {
        taskId = CreateTask(sBattleIntroSlideFuncs[environment], 0);
    }
    else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
    {
        taskId = CreateTask(BattleIntroSlidePartner, 0);
    }
    else if (gBattleTypeFlags & BATTLE_TYPE_LINK)
    {
        taskId = CreateTask(BattleIntroSlideLink, 0);
    }
    else if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
    {
        taskId = CreateTask(BattleIntroSlide3, 0);
    }
    else if ((gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) && gGameVersion != VERSION_RUBY)
    {
        environment = BATTLE_ENVIRONMENT_UNDERWATER;
        taskId = CreateTask(BattleIntroSlide2, 0);
    }
    else
    {
        taskId = CreateTask(sBattleIntroSlideFuncs[environment], 0);
    }

    gTasks[taskId].tState = 0;
    gTasks[taskId].tEnvironment = environment;
    gTasks[taskId].data[2] = 0;
    gTasks[taskId].data[3] = 0;
    gTasks[taskId].data[4] = 0;
    gTasks[taskId].data[5] = 0;
    gTasks[taskId].data[6] = 0;
}

src/battle_main.c

in section static void CB2_InitBattleInternal(void) (line 619)
replace all lines (620 to 710) with:

{
    s32 i;

    SetHBlankCallback(NULL);
    SetVBlankCallback(NULL);

    CpuFill32(0, (void *)(VRAM), VRAM_SIZE);

    SetGpuReg(REG_OFFSET_MOSAIC, 0);
    SetGpuReg(REG_OFFSET_WIN0H, DISPLAY_WIDTH);
    SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1));
    SetGpuReg(REG_OFFSET_WININ, 0);
    SetGpuReg(REG_OFFSET_WINOUT, 0);

    gBattle_WIN0H = DISPLAY_WIDTH;

    if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
    {
        gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1);
        ScanlineEffect_Clear();

        for (i = 0; i < DISPLAY_HEIGHT / 2; i++)
        {
            gScanlineEffectRegBuffers[0][i] = 0xF0;
            gScanlineEffectRegBuffers[1][i] = 0xF0;
        }

        for (; i < DISPLAY_HEIGHT; i++)
        {
            gScanlineEffectRegBuffers[0][i] = 0xFF10;
            gScanlineEffectRegBuffers[1][i] = 0xFF10;
        }

        ScanlineEffect_SetParams(sIntroScanlineParams16Bit);
    }	
    else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
    {
        gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1);
        ScanlineEffect_Clear();

        for (i = 0; i < DISPLAY_HEIGHT / 2; i++)
        {
            gScanlineEffectRegBuffers[0][i] = 0xF0;
            gScanlineEffectRegBuffers[1][i] = 0xF0;
        }

        for (; i < DISPLAY_HEIGHT; i++)
        {
            gScanlineEffectRegBuffers[0][i] = 0xFF10;
            gScanlineEffectRegBuffers[1][i] = 0xFF10;
        }

        ScanlineEffect_SetParams(sIntroScanlineParams16Bit);
    }
    else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
    {
        gBattle_WIN0V = DISPLAY_HEIGHT - 1;
        gBattle_WIN1H = DISPLAY_WIDTH;
        gBattle_WIN1V = 32;
    }
    else
    {
        gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1);
        ScanlineEffect_Clear();

        for (i = 0; i < DISPLAY_HEIGHT / 2; i++)
        {
            gScanlineEffectRegBuffers[0][i] = 0xF0;
            gScanlineEffectRegBuffers[1][i] = 0xF0;
        }

        for (; i < DISPLAY_HEIGHT; i++)
        {
            gScanlineEffectRegBuffers[0][i] = 0xFF10;
            gScanlineEffectRegBuffers[1][i] = 0xFF10;
        }

        ScanlineEffect_SetParams(sIntroScanlineParams16Bit);
    }

    ResetPaletteFade();
    gBattle_BG0_X = 0;
    gBattle_BG0_Y = 0;
    gBattle_BG1_X = 0;
    gBattle_BG1_Y = 0;
    gBattle_BG2_X = 0;
    gBattle_BG2_Y = 0;
    gBattle_BG3_X = 0;
    gBattle_BG3_Y = 0;

    gBattleEnvironment = BattleSetup_GetEnvironmentId();
    if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
        gBattleEnvironment = BATTLE_ENVIRONMENT_BUILDING;

    InitBattleBgsVideo();
    LoadBattleTextboxAndBackground();
    ResetSpriteData();
    ResetTasks();
    DrawBattleEntryBackground();
    FreeAllSpritePalettes();
    gReservedSpritePaletteCount = MAX_BATTLERS_COUNT;
    SetVBlankCallback(VBlankCB_Battle);
    SetUpBattleVarsAndBirchZigzagoon();

    if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
        SetMainCallback2(CB2_HandleStartMultiPartnerBattle);
    else if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
        SetMainCallback2(CB2_HandleStartMultiPartnerBattle);
    else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
        SetMainCallback2(CB2_HandleStartMultiBattle);
    else
        SetMainCallback2(CB2_HandleStartBattle);

    if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED)))
    {
        CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A, TRUE);
        if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
            CreateNPCTrainerParty(&gEnemyParty[PARTY_SIZE / 2], gTrainerBattleOpponent_B, FALSE);
        SetWildMonHeldItem();
    }

    gMain.inBattle = TRUE;
    gSaveBlock2Ptr->frontier.disableRecordBattle = FALSE;

    for (i = 0; i < PARTY_SIZE; i++)
        AdjustFriendship(&gPlayerParty[i], FRIENDSHIP_EVENT_LEAGUE_BATTLE);

    gBattleCommunication[MULTIUSE_STATE] = 0;
}

src/battle_controller_player.c

in section static void PlayerHandleDrawTrainerPic(void) (line 2270)
replace all lines (2271 to 2351) with:

{
    s16 xPos, yPos;
    u32 trainerPicId;

    if (gBattleTypeFlags & BATTLE_TYPE_LINK)
    {
        if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_FIRE_RED
            || (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_LEAF_GREEN)
        {
            trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_RED;
        }
        else if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_RUBY
                 || (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_SAPPHIRE)
        {
            trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN;
        }
        else
        {
            trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_BRENDAN;
        }
    }
    else
    {
        trainerPicId = gSaveBlock2Ptr->playerGender;
    }

    if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
    {
        if ((GetBattlerPosition(gActiveBattler) & BIT_FLANK) != B_FLANK_LEFT) // Second mon, on the right.
            xPos = 90;
        else // First mon, on the left.
            xPos = 32;

        if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
        {
            yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
        }
        else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
        {
            yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
        }
        else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
        {
            xPos = 90;
            yPos = (8 - gTrainerFrontPicCoords[trainerPicId].size) * 4 + 80;
        }
        else
        {
            yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
        }

    }
    else
    {
        xPos = 80;
        yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
    }

    // Use front pic table for any tag battles unless your partner is Steven.
    if (gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
    {
        DecompressTrainerBackPic(trainerPicId, gActiveBattler);
        SetMultiuseSpriteTemplateToTrainerBack(trainerPicId, GetBattlerPosition(gActiveBattler));
        gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, xPos, yPos, GetBattlerSpriteSubpriority(gActiveBattler));

        gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
        gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
        gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
        gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
    }
    else if (gPartnerTrainerId == TRAINER_LEAF_PARTNER)
    {
        DecompressTrainerBackPic(trainerPicId, gActiveBattler);
        SetMultiuseSpriteTemplateToTrainerBack(trainerPicId, GetBattlerPosition(gActiveBattler));
        gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, xPos, yPos, GetBattlerSpriteSubpriority(gActiveBattler));

        gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
        gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
        gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
        gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
    }
	else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
    {
        trainerPicId = PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender);
        DecompressTrainerFrontPic(trainerPicId, gActiveBattler);
        SetMultiuseSpriteTemplateToTrainerFront(trainerPicId, GetBattlerPosition(gActiveBattler));
        gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, xPos, yPos, GetBattlerSpriteSubpriority(gActiveBattler));

        gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
        gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
        gSprites[gBattlerSpriteIds[gActiveBattler]].y2 = 48;
        gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
        gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
        gSprites[gBattlerSpriteIds[gActiveBattler]].oam.affineMode = ST_OAM_AFFINE_OFF;
        gSprites[gBattlerSpriteIds[gActiveBattler]].hFlip = 1;
    }
    // Use the back pic in any other scenario.
    else
    {
        DecompressTrainerBackPic(trainerPicId, gActiveBattler);
        SetMultiuseSpriteTemplateToTrainerBack(trainerPicId, GetBattlerPosition(gActiveBattler));
        gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, xPos, yPos, GetBattlerSpriteSubpriority(gActiveBattler));

        gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
        gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
        gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
        gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
    }

    gBattlerControllerFuncs[gActiveBattler] = CompleteOnBattlerSpriteCallbackDummy;
}

src/data/trainers.h

-- depending how you want the battles to be, change the details in both [TRAINER_BRENDAN_PLACEHOLDER] and [TRAINER_MAY_PLACEHOLDER] to however you want the battles.

see "how to repurpose placeholder battles" for more info.


src/data/trainer_parties.h

replace the sParty_Brandan and sParty_MayLinkPartnerBattleholder sections for which Pokemon you want in their party. (legendary birds and beasts used for this example)

static const struct TrainerMonNoItemDefaultMoves sParty_BrendanLinkPlaceholder[] = {
    {
    .iv = 0,
    .lvl = 20,
    .species = SPECIES_ARTICUNO,
    },
    {
    .iv = 0,
    .lvl = 20,
    .species = SPECIES_ZAPDOS,
    },
    {
    .iv = 0,
    .lvl = 20,
    .species = SPECIES_MOLTRES,
    }
};

static const struct TrainerMonNoItemDefaultMoves sParty_MayLinkPlaceholder[] = {
    {
    .iv = 0,
    .lvl = 20,
    .species = SPECIES_ENTEI,
    },
    {
    .iv = 0,
    .lvl = 20,
    .species = SPECIES_SUICUNE,
    },
    {
    .iv = 0,
    .lvl = 20,
    .species = SPECIES_RAIKOU,
    }
};

map/scripts.inc

choose a map where you want the partner battle to take place.

for this tutorial, the code has been added to LittlerootTown/scripts.inc

in porymap, add 3 sprites to the location, name them, give them a script and the flag for hiding them you defined back in step 1.

name: LOCALID_BATTLEPARTNER_LEAF
script: PartnerBattle_EventScript_PartnerBattle_Start
flag: FLAG_LEAF_PARTNER_BATTLE

name: LOCALID_ENEMYTRAINER1 (uses Placeholder Brendan's pokemon data)
script: (not used for this example but would be the speech when you talk to them before battle)
flag: FLAG_PARTNER_HIDE_ENEMY_TRAINERS

name: LOCALID_ENEMYTRAINER2 (uses placeholder May's pokemon data)
script: (not used for this example but would be the speech when you talk to them before battle)
flag: FLAG_PARTNER_HIDE_ENEMY_TRAINERS

-- note 1: both enemy trainers use the same hide flag as they both get removed at the same time.
for this example tutorial, the lines to remove the objects are commented out so that the code can compile.
// removeobject LOCALID_ENEMYTRAINER1
// removeobject LOCALID_ENEMYTRAINER2
// removeobject LOCALID_BATTLEPARTNER_LEAF
remove the "//" in your final code

-- note 2: if you use an older version of pret pokeemerald that doesn't use the updated specials that automatically add "waitstate", remove the "//" from the 3 "waitstate" lines below

add the below to your map scripts.inc file or whereever you store your custom scripts.

// partner battle start
PartnerBattle_EventScript_PartnerBattle_Start::
	lockall
	goto_if_set FLAG_INTERACTED_WITH_LEAF_BEFORE_BATTLE, PartnerBattle_EventScript_ReadyForBattle_AskAgain
	setflag FLAG_INTERACTED_WITH_LEAF_BEFORE_BATTLE
	msgbox PartnerBattle_Text_LeafAsksBattle, MSGBOX_YESNO
	goto_if_eq VAR_RESULT, YES, PartnerBattle_EventScript_ChoosePartyForMultiBattle
	msgbox PartnerBattle_Text_AnsweredNoToBattle, MSGBOX_DEFAULT
	releaseall
	end

PartnerBattle_Text_LeafAsksBattle:
	.string "There's some bad people around.\n"
	.string "Can you help me get rid of them?$"

PartnerBattle_EventScript_ReadyForBattle_AskAgain::
	lockall
	faceplayer
	msgbox PartnerBattle_Text_ReadyForBattle, MSGBOX_YESNO
	goto_if_eq VAR_RESULT, YES, PartnerBattle_EventScript_ChoosePartyForMultiBattle
	msgbox PartnerBattle_Text_AnsweredNoToBattle, MSGBOX_DEFAULT
	closemessage
	releaseall
	end

PartnerBattle_Text_ReadyForBattle:
	.string "So will you help me?$"

PartnerBattle_Text_AnsweredNoToBattle:
	.string "You can't help me?\p"
	.string "Or won't?$"

// remove the comments from "waitstate" below if you use an older version
PartnerBattle_EventScript_ChoosePartyForMultiBattle::
	special SavePlayerParty
	fadescreen FADE_TO_BLACK
	special ChooseHalfPartyForBattle
//	waitstate
//if yes
	goto_if_eq VAR_RESULT, YES, PartnerBattle_EventScript_DoLeafMultiBattle
//if no
	special LoadPlayerParty
	msgbox PartnerBattle_Text_AnsweredNoToBattle, MSGBOX_DEFAULT
	releaseall
	end

// remove the comments from "waitstate" below if you use an older version
PartnerBattle_EventScript_DoLeafMultiBattle::
	special ReducePlayerPartyToSelectedMons
	frontier_set FRONTIER_DATA_SELECTED_MON_ORDER
	setvar VAR_0x8004, SPECIAL_BATTLE_LEAF
	setvar VAR_0x8005, 0
	special DoSpecialTrainerBattle
//	waitstate
	frontier_saveparty
	special LoadPlayerParty
	switch VAR_RESULT
	case 1, PartnerBattle_EventScript_DefeatedEnemyTrainers
//if lose	
	fadescreen FADE_TO_BLACK
	special SetCB2WhiteOut
//	waitstate
	releaseall
	end

// remove the comments from "removeobject" below before compiling
PartnerBattle_EventScript_DefeatedEnemyTrainers::
	msgbox PartnerBattle_Text_EnemyTrainer1Defeated, MSGBOX_DEFAULT
	closemessage
	delay 20
	msgbox PartnerBattle_Text_EnemyTrainer2Defeated, MSGBOX_DEFAULT
	closemessage
	fadescreen FADE_TO_BLACK
//	removeobject LOCALID_ENEMYTRAINER1
//	removeobject LOCALID_ENEMYTRAINER2
	setflag FLAG_PARTNER_HIDE_ENEMY_TRAINERS
	fadescreen FADE_FROM_BLACK
	msgbox PartnerBattle_Text_PartnerHealMon, MSGBOX_DEFAULT
	special HealPlayerParty
	closemessage
	msgbox PartnerBattle_Text_PartnerThankYou, MSGBOX_DEFAULT
	fadescreen FADE_TO_BLACK
//	removeobject LOCALID_BATTLEPARTNER_LEAF
	setflag FLAG_LEAF_PARTNER_BATTLE
	fadescreen FADE_FROM_BLACK
	releaseall
	end

PartnerBattle_Text_EnemyTrainer1Defeated:
	.string "I can't believe we lost.$"
PartnerBattle_Text_EnemyTrainer2Defeated:
	.string "This is the last time I work with you.$"
PartnerBattle_Text_PartnerHealMon:
	.string "{PLAYER}, let me heal your POKéMON.$"
PartnerBattle_Text_PartnerThankYou:
	.string "Thank you for helping me.\p"
	.string "I hope to meet you again somewhere.$"


//battle information
PartnerBattle_EventScript_EnemyTrainer1::
	trainerbattle TRAINER_BATTLE_SET_TRAINER_A, TRAINER_BRENDAN_PLACEHOLDER, LOCALID_NONE, PartnerBattle_Text_EnemyTrainer1Defeat, PartnerBattle_Text_EnemyTrainer1DefeatAfter
	end

PartnerBattle_EventScript_EnemyTrainer2::
	trainerbattle TRAINER_BATTLE_SET_TRAINER_B, TRAINER_MAY_PLACEHOLDER, LOCALID_NONE, PartnerBattle_Text_EnemyTrainer2Defeat, PartnerBattle_Text_EnemyTrainer2DefeatAfter
	end

PartnerBattle_Text_EnemyTrainer1Defeat:
	.string "I'm done.$"

PartnerBattle_Text_EnemyTrainer2Defeat:
	.string "I'm beat.$"

PartnerBattle_Text_EnemyTrainer1DefeatAfter:
	.string "I'm done.$"

PartnerBattle_Text_EnemyTrainer2DefeatAfter:
	.string "I'm beat.$"
//end

Clone this wiki locally