- 1,591
- Posts
- 11
- Years
- Seen Mar 20, 2024
![[PokeCommunity.com] Move Tutor Expansion [PokeCommunity.com] Move Tutor Expansion](https://i.imgur.com/pIT3aHl.gif)
Step One: Define more Tutor moves
Spoiler:
Open src/data/pokemon/tutor_learnsets.h. At the top of the file you'll see two lists of moves, which look something like this:
Code:
#define TUTOR_MOVE_MEGA_PUNCH 0
#define TUTOR_MOVE_SWORDS_DANCE 1
#define TUTOR_MOVE_MEGA_KICK 2
#define TUTOR_MOVE_BODY_SLAM 3
#define TUTOR_MOVE_DOUBLE_EDGE 4
#define TUTOR_MOVE_COUNTER 5
#define TUTOR_MOVE_SEISMIC_TOSS 6
#define TUTOR_MOVE_MIMIC 7
#define TUTOR_MOVE_METRONOME 8
#define TUTOR_MOVE_SOFT_BOILED 9
#define TUTOR_MOVE_DREAM_EATER 10
#define TUTOR_MOVE_THUNDER_WAVE 11
#define TUTOR_MOVE_EXPLOSION 12
#define TUTOR_MOVE_ROCK_SLIDE 13
#define TUTOR_MOVE_SUBSTITUTE 14
...
Code:
const u16 gTutorMoves[] =
{
[TUTOR_MOVE_MEGA_PUNCH] = MOVE_MEGA_PUNCH,
[TUTOR_MOVE_SWORDS_DANCE] = MOVE_SWORDS_DANCE,
[TUTOR_MOVE_MEGA_KICK] = MOVE_MEGA_KICK,
[TUTOR_MOVE_BODY_SLAM] = MOVE_BODY_SLAM,
[TUTOR_MOVE_DOUBLE_EDGE] = MOVE_DOUBLE_EDGE,
[TUTOR_MOVE_COUNTER] = MOVE_COUNTER,
[TUTOR_MOVE_SEISMIC_TOSS] = MOVE_SEISMIC_TOSS,
[TUTOR_MOVE_MIMIC] = MOVE_MIMIC,
[TUTOR_MOVE_METRONOME] = MOVE_METRONOME,
[TUTOR_MOVE_SOFT_BOILED] = MOVE_SOFT_BOILED,
[TUTOR_MOVE_DREAM_EATER] = MOVE_DREAM_EATER,
[TUTOR_MOVE_THUNDER_WAVE] = MOVE_THUNDER_WAVE,
[TUTOR_MOVE_EXPLOSION] = MOVE_EXPLOSION,
[TUTOR_MOVE_ROCK_SLIDE] = MOVE_ROCK_SLIDE,
[TUTOR_MOVE_SUBSTITUTE] = MOVE_SUBSTITUTE,
...
Spoiler:
Code:
#define TUTOR_MOVE_GRASS_PLEDGE 1
#define TUTOR_MOVE_FIRE_PLEDGE 2
#define TUTOR_MOVE_WATER_PLEDGE 3
#define TUTOR_MOVE_FRENZY_PLANT 4
#define TUTOR_MOVE_BLAST_BURN 5
#define TUTOR_MOVE_HYDRO_CANNON 6
#define TUTOR_MOVE_DRACO_METEOR 7
#define TUTOR_MOVE_DRAGON_ASCENT 8
#define TUTOR_MOVE_SECRET_SWORD 9
#define TUTOR_MOVE_RELIC_SONG 10
#define TUTOR_MOVE_FURY_CUTTER 11
#define TUTOR_MOVE_ROLLOUT 12
#define TUTOR_MOVE_SEISMIC_TOSS 13
#define TUTOR_MOVE_COVET 14
#define TUTOR_MOVE_VACUUM_WAVE 15
#define TUTOR_MOVE_SHOCK_WAVE 16
#define TUTOR_MOVE_BUG_BITE 17
#define TUTOR_MOVE_AIR_CUTTER 18
#define TUTOR_MOVE_SWIFT 19
#define TUTOR_MOVE_SNATCH 20
#define TUTOR_MOVE_MIMIC 21
#define TUTOR_MOVE_MUD_SLAP 22
#define TUTOR_MOVE_METRONOME 23
#define TUTOR_MOVE_OMINOUS_WIND 24
#define TUTOR_MOVE_SUPER_FANG 25
#define TUTOR_MOVE_COUNTER 26
#define TUTOR_MOVE_SIGNAL_BEAM 27
#define TUTOR_MOVE_DEFOG 28
#define TUTOR_MOVE_MAGIC_COAT 29
#define TUTOR_MOVE_GRAVITY 30
#define TUTOR_MOVE_SEED_BOMB 31
#define TUTOR_MOVE_DYNAMIC_PUNCH 32
#define TUTOR_MOVE_SYNTHESIS 33
#define TUTOR_MOVE_PAIN_SPLIT 34
#define TUTOR_MOVE_UPROAR 35
#define TUTOR_MOVE_HONE_CLAWS 36
#define TUTOR_MOVE_ENDEAVOR 37
#define TUTOR_MOVE_WORRY_SEED 38
#define TUTOR_MOVE_PSYCH_UP 39
#define TUTOR_MOVE_THUNDER_PUNCH 40
#define TUTOR_MOVE_FIRE_PUNCH 41
#define TUTOR_MOVE_ICE_PUNCH 42
#define TUTOR_MOVE_ICY_WIND 43
#define TUTOR_MOVE_ELECTROWEB 44
#define TUTOR_MOVE_LOW_KICK 45
#define TUTOR_MOVE_IRON_DEFENSE 46
#define TUTOR_MOVE_MAGNET_RISE 47
#define TUTOR_MOVE_TAILWIND 48
#define TUTOR_MOVE_ZEN_HEADBUTT 49
#define TUTOR_MOVE_DUAL_CHOP 50
#define TUTOR_MOVE_BODY_SLAM 51
#define TUTOR_MOVE_BRINE 52
#define TUTOR_MOVE_SWAGGER 53
#define TUTOR_MOVE_IRON_HEAD 54
#define TUTOR_MOVE_SOFT_BOILED 55
#define TUTOR_MOVE_LAST_RESORT 56
#define TUTOR_MOVE_ROLE_PLAY 57
#define TUTOR_MOVE_DRILL_RUN 58
#define TUTOR_MOVE_TRICK 59
#define TUTOR_MOVE_AQUA_TAIL 60
#define TUTOR_MOVE_SKY_ATTACK 61
#define TUTOR_MOVE_FOUL_PLAY 62
#define TUTOR_MOVE_DOUBLE_EDGE 63
#define TUTOR_MOVE_BOUNCE 64
#define TUTOR_MOVE_HEAL_BELL 65
#define TUTOR_MOVE_SUPERPOWER 66
#define TUTOR_MOVE_HELPING_HAND 67
#define TUTOR_MOVE_HEAT_WAVE 68
#define TUTOR_MOVE_OUTRAGE 69
#define TUTOR_MOVE_KNOCK_OFF 70
#define TUTOR_MOVE_LIQUIDATION 71
#define TUTOR_MOVE_HYPER_VOICE 72
#define TUTOR_MOVE_EARTH_POWER 73
#define TUTOR_MOVE_GUNK_SHOT 74
#define TUTOR_MOVE_AURA_SPHERE 75
#define TUTOR_MOVE_THROAT_CHOP 76
#define TUTOR_MOVE_GASTRO_ACID 77
#define TUTOR_MOVE_POWER_GEM 78
#define TUTOR_MOVE_HURRICANE 79
const u16 gTutorMoves[] =
{
[TUTOR_MOVE_GRASS_PLEDGE] = MOVE_GRASS_PLEDGE,
[TUTOR_MOVE_FIRE_PLEDGE] = MOVE_FIRE_PLEDGE,
[TUTOR_MOVE_WATER_PLEDGE] = MOVE_WATER_PLEDGE,
[TUTOR_MOVE_FRENZY_PLANT] = MOVE_FRENZY_PLANT,
[TUTOR_MOVE_BLAST_BURN] = MOVE_BLAST_BURN,
[TUTOR_MOVE_HYDRO_CANNON] = MOVE_HYDRO_CANNON,
[TUTOR_MOVE_DRACO_METEOR] = MOVE_DRACO_METEOR,
[TUTOR_MOVE_DRAGON_ASCENT] = MOVE_DRAGON_ASCENT,
[TUTOR_MOVE_SECRET_SWORD] = MOVE_SECRET_SWORD,
[TUTOR_MOVE_RELIC_SONG] = MOVE_RELIC_SONG,
[TUTOR_MOVE_FURY_CUTTER] = MOVE_FURY_CUTTER,
[TUTOR_MOVE_ROLLOUT] = MOVE_ROLLOUT,
[TUTOR_MOVE_SEISMIC_TOSS] = MOVE_SEISMIC_TOSS,
[TUTOR_MOVE_COVET] = MOVE_COVET,
[TUTOR_MOVE_VACUUM_WAVE] = MOVE_VACUUM_WAVE,
[TUTOR_MOVE_SHOCK_WAVE] = MOVE_SHOCK_WAVE,
[TUTOR_MOVE_BUG_BITE] = MOVE_BUG_BITE,
[TUTOR_MOVE_AIR_CUTTER] = MOVE_AIR_CUTTER,
[TUTOR_MOVE_SWIFT] = MOVE_SWIFT,
[TUTOR_MOVE_SNATCH] = MOVE_SNATCH,
[TUTOR_MOVE_MIMIC] = MOVE_MIMIC,
[TUTOR_MOVE_MUD_SLAP] = MOVE_MUD_SLAP,
[TUTOR_MOVE_METRONOME] = MOVE_METRONOME,
[TUTOR_MOVE_OMINOUS_WIND] = MOVE_OMINOUS_WIND,
[TUTOR_MOVE_SUPER_FANG] = MOVE_SUPER_FANG,
[TUTOR_MOVE_COUNTER] = MOVE_COUNTER,
[TUTOR_MOVE_SIGNAL_BEAM] = MOVE_SIGNAL_BEAM,
[TUTOR_MOVE_DEFOG] = MOVE_DEFOG,
[TUTOR_MOVE_MAGIC_COAT] = MOVE_MAGIC_COAT,
[TUTOR_MOVE_GRAVITY] = MOVE_GRAVITY,
[TUTOR_MOVE_SEED_BOMB] = MOVE_SEED_BOMB,
[TUTOR_MOVE_DYNAMIC_PUNCH] = MOVE_DYNAMIC_PUNCH,
[TUTOR_MOVE_SYNTHESIS] = MOVE_SYNTHESIS,
[TUTOR_MOVE_PAIN_SPLIT] = MOVE_PAIN_SPLIT,
[TUTOR_MOVE_UPROAR] = MOVE_UPROAR,
[TUTOR_MOVE_HONE_CLAWS] = MOVE_HONE_CLAWS,
[TUTOR_MOVE_ENDEAVOR] = MOVE_ENDEAVOR,
[TUTOR_MOVE_WORRY_SEED] = MOVE_WORRY_SEED,
[TUTOR_MOVE_PSYCH_UP] = MOVE_PSYCH_UP,
[TUTOR_MOVE_THUNDER_PUNCH] = MOVE_THUNDER_PUNCH,
[TUTOR_MOVE_FIRE_PUNCH] = MOVE_FIRE_PUNCH,
[TUTOR_MOVE_ICE_PUNCH] = MOVE_ICE_PUNCH,
[TUTOR_MOVE_ICY_WIND] = MOVE_ICY_WIND,
[TUTOR_MOVE_ELECTROWEB] = MOVE_ELECTROWEB,
[TUTOR_MOVE_LOW_KICK] = MOVE_LOW_KICK,
[TUTOR_MOVE_IRON_DEFENSE] = MOVE_IRON_DEFENSE,
[TUTOR_MOVE_MAGNET_RISE] = MOVE_MAGNET_RISE,
[TUTOR_MOVE_TAILWIND] = MOVE_TAILWIND,
[TUTOR_MOVE_ZEN_HEADBUTT] = MOVE_ZEN_HEADBUTT,
[TUTOR_MOVE_DUAL_CHOP] = MOVE_DUAL_CHOP,
[TUTOR_MOVE_BODY_SLAM] = MOVE_BODY_SLAM,
[TUTOR_MOVE_BRINE] = MOVE_BRINE,
[TUTOR_MOVE_SWAGGER] = MOVE_SWAGGER,
[TUTOR_MOVE_IRON_HEAD] = MOVE_IRON_HEAD,
[TUTOR_MOVE_SOFT_BOILED] = MOVE_SOFT_BOILED,
[TUTOR_MOVE_LAST_RESORT] = MOVE_LAST_RESORT,
[TUTOR_MOVE_ROLE_PLAY] = MOVE_ROLE_PLAY,
[TUTOR_MOVE_DRILL_RUN] = MOVE_DRILL_RUN,
[TUTOR_MOVE_TRICK] = MOVE_TRICK,
[TUTOR_MOVE_AQUA_TAIL] = MOVE_AQUA_TAIL,
[TUTOR_MOVE_SKY_ATTACK] = MOVE_SKY_ATTACK,
[TUTOR_MOVE_FOUL_PLAY] = MOVE_FOUL_PLAY,
[TUTOR_MOVE_DOUBLE_EDGE] = MOVE_DOUBLE_EDGE,
[TUTOR_MOVE_BOUNCE] = MOVE_BOUNCE,
[TUTOR_MOVE_HEAL_BELL] = MOVE_HEAL_BELL,
[TUTOR_MOVE_SUPERPOWER] = MOVE_SUPERPOWER,
[TUTOR_MOVE_HELPING_HAND] = MOVE_HELPING_HAND,
[TUTOR_MOVE_HEAT_WAVE] = MOVE_HEAT_WAVE,
[TUTOR_MOVE_OUTRAGE] = MOVE_OUTRAGE,
[TUTOR_MOVE_KNOCK_OFF] = MOVE_KNOCK_OFF,
[TUTOR_MOVE_LIQUIDATION] = MOVE_LIQUIDATION,
[TUTOR_MOVE_HYPER_VOICE] = MOVE_HYPER_VOICE,
[TUTOR_MOVE_EARTH_POWER] = MOVE_EARTH_POWER,
[TUTOR_MOVE_GUNK_SHOT] = MOVE_GUNK_SHOT,
[TUTOR_MOVE_AURA_SPHERE] = MOVE_AURA_SPHERE,
[TUTOR_MOVE_THROAT_CHOP] = MOVE_THROAT_CHOP,
[TUTOR_MOVE_GASTRO_ACID] = MOVE_GASTRO_ACID,
[TUTOR_MOVE_POWER_GEM] = MOVE_POWER_GEM,
[TUTOR_MOVE_HURRICANE] = MOVE_HURRICANE,
};
Step Two: Edit/create a compatibility table
Spoiler:
This is the hard/tedious part, especially if you've got expanded Pokemon. Tutor compatibility is stored as an array of bit fields; each bit corresponds to a tutor move, as you defined in step one, and you'll need to generate these for each Pokemon and Tutor move in your game. There are a few ways to do this; personally I chose to sacrifice readable code for an easy way to generate a compatibility table, so that's what I'll be covering here. I'll be storing each Pokemon's list of learnable moves in a multi-dimensional array of 32-bit bit fields, which looks like this:
Code:
static const u32 sTutorLearnsets[][3] = {
[SPECIES_NONE] = {0x40300401, 0x40140021, 0x00000020},
[SPECIES_BULBASAUR] = {0x80600802, 0x80280042, 0x00000040},
[SPECIES_IVYSAUR] = {0x80600802, 0x80280042, 0x00000040},
[SPECIES_VENUSAUR] = {0x80600812, 0x80280042, 0x00000060},
[SPECIES_CHARMANDER] = {0x04682804, 0x80280311, 0x00000030},
[SPECIES_CHARMELEON] = {0x04682804, 0x80280311, 0x00000030},
[SPECIES_CHARIZARD] = {0x156C2824, 0x80290311, 0x00008810},
...
If you're using the spreadsheet's format, note that you should delete or comment out these lines of code, as they won't be needed:
Code:
#define TUTOR_LEARNSET(moves) ((u32)(moves))
#define TUTOR(move) ((u64)1 << (TUTOR_##move))
Step Three: Update the compatibility check code
Spoiler:
Open src/party_menu.c and navigate to the following function:
Code:
static bool8 CanLearnTutorMove(u16 species, u8 tutor)
{
if (sTutorLearnsets[species] & (1 << tutor))
return TRUE;
else
return FALSE;
}
Replace it with something like this:
Code:
static bool32 CanLearnTutorMove(u16 species, u8 tutor) // note the change to bool32
{
if (tutor < 32)
{
u32 mask = 1 << tutor;
return sTutorLearnsets[species][0] & mask;
}
else if (tutor < 64)
{
u32 mask = 1 << (tutor - 32);
return sTutorLearnsets[species][1] & mask;
}
else // thanks to BluRose for suggesting this
{
u32 mask = 1 << (tutor - 64);
return sTutorLearnsets[species][2] & mask;
}
}
}
Note that if you've got more than 96 tutor moves you'll need at least one more conditional (else if) branch to handle them.
And that's it! To see how to use a new tutor in a script, take a look at one of the existing ones in data/event_scripts.s (hint: change the setvar VAR_0x8005, <number> to the number of your newly defined tutor)
Also, thanks to Dizzy Egg for the awesome scrolling multichoice code used in the gif above!
Last edited: