Skip to content

How to Add a New Trainer

RainbowMetalPigeon edited this page Jul 9, 2023 · 4 revisions

In this tutorial we will add a new trainer to the map. Specifically, we will add a YOUNGSTER to ROUTE_1. We start by defining the event for when we beat this trainer so that we cannot fight him again:

...
; Route 1 events
	const_next $3C0
-	const EVENT_GOT_POTION_SAMPLE
+	const_skip 2
+	const EVENT_GOT_POTION_SAMPLE
+	const EVENT_BEAT_ROUTE_1_TRAINER_0

; Route 2 events
...

It's important that the new event EVENT_BEAT_ROUTE_1_TRAINER_0 is placed in the same position of the object we are going to the define in the next step: in this case, it's the 4th event of the route 1 events, which means that is the bit number 3 of the byte in position const_next $3C0, where the first bit is the bit number 0. Note how we needed to add a const_skip 2 to make the code treat the new event as the event number 3.

We now would like to place the character into the game map.

...
	def_bg_events
-	bg_event  9, 27, 3 ; Route1Text3
+	bg_event  9, 27, 4 ; Route1Text3

	def_object_events
	object_event  5, 24, SPRITE_YOUNGSTER, WALK, UP_DOWN, 1 ; person
	object_event 15, 13, SPRITE_YOUNGSTER, WALK, LEFT_RIGHT, 2 ; person
+	object_event 10, 20, SPRITE_YOUNGSTER, STAY, RIGHT, 3, OPP_YOUNGSTER, 1

	def_warps_to ROUTE_1
...

The first two numbers after object_event are the x and y coordinates where the trainer will appear. We count tiles from the top left tile of the map. That is, the top left tile of the map is represented by 0, 0. So this new trainer will appear 10 tiles to the right and 20 tiles down.

SPRITE_YOUNGSTER indicates that the Youngster overworld sprite is used. The overworld sprites graphics are found in gfx\sprites (the graphics itself) and gfx\sprites.asm (the graphics in-game memory), the constants are found in constants\sprite_constants.asm and the SpriteSheetPointerTable are found in data\sprites\sprites.asm.

STAY indicates that the NPC character will not move and RIGHT indicates the direction the trainer faces.

The 3 after RIGHT indicates that this is the third object defined. Important: note how the line about the bg_event has been edited as well: this line refers to the sign present in Route 1. Signs object always come after NPCs objects, and trainers NPCs come after non-trainer NPCs. This is why we need to edit this number for the sign too.

OPP_<trainer class> determines the trainer class, so we use OPP_YOUNGSTER for adding the Youngster.

Lastly, the number after OPP_YOUNGSTER, 1, indicates which team this trainer will use and can be found in data\trainers\parties.asm. Specifically, this will be the team of the first Youngster in that file.

Writing "Challenge to Battle", Defeated and Post Battle texts (note how there is not a text for the opponent's victory; in case the player gets defeated, they black out without any text being written for the opponent):

...
	line "PALLET TOWN -"
	cont "VIRIDIAN CITY"
	done

+_Route1BattleText1::
+	text "Hi! I like shorts!"
+	line "They're comfy and"
+	cont "easy to wear!"
+	done

+_Route1EndBattleText1::
+	text "BEEEH!"
+	line "Wrong!"
+	prompt

+_Route1AfterBattleText1::
+	text "I lost, but I'm"
+	line "training hard to"
+	cont "defeated you in"
+       cont "the next round!"
+	done

Now, add _Route1BattleText1,_Route1EndBattleText1 and _Route1AfterBattleText1 to the game's memory in scripts\Route1.asm.

In case of Route1, also we need to add <map>TrainerHeaders, <map>_ScriptPointers and write a w<map>CurScript in ram\wram.asm.

The number after EVENT_BEAT_ROUTE_1_TRAINER_0 determines the range to trainer see the player. This means that will be 4 the max to UP, DOWN and RIGHT, and 5 the max to LEFT.

Route1_Script:
-	jp EnableAutoTextBoxDrawing
+	call EnableAutoTextBoxDrawing
+	ld hl, Route1TrainerHeaders
+	ld de, Route1_ScriptPointers
+	ld a, [wRoute1CurScript]
+	call ExecuteCurMapScriptInTable
+	ld [wRoute1CurScript], a
+	ret

+Route1_ScriptPointers:
+	dw CheckFightingMapTrainers
+	dw DisplayEnemyTrainerTextAndStartBattle
+	dw EndTrainerBattle

Route1_TextPointers:
	dw Route1Text1
	dw Route1Text2
-	dw Route1Text3
+	dw Route1Text4
+	dw Route1Text3 ; note how text3 is now AFTER text4, because text3 is the one related to the sign, which must be AFTER the trainers' texts

+Route1TrainerHeaders:
+	def_trainers 3
+Route1TrainerHeader0:
+	trainer EVENT_BEAT_ROUTE_1_TRAINER_0, 4, Route1BattleText1, Route1EndBattleText1, Route1AfterBattleText1
+	db -1 ; end

Route1Text1:
	text_asm
...
...
Route1Text3:
	text_far _Route1Text3
	text_end

+Route1Text4:
+	text_asm
+	ld hl, Route1TrainerHeader0
+	call TalkToTrainer
+	jp TextScriptEnd

+Route1BattleText1:
+	text_far _Route1BattleText1
+	text_end

+Route1EndBattleText1:
+	text_far _Route1EndBattleText1
+	text_end

+Route1AfterBattleText1:
+	text_far _Route1AfterBattleText1
+	text_end

Note how text3 is now AFTER text4, because text3 is the one related to the sign, which must be AFTER the trainers' texts. Also, note the def_trainers 3: this has to be 3 because this trainer is the 3rd object defined in the map; the first two objects are the non-trainer NPCs, and the 4th object is the sign. This number 3 has to match the bit number of the event associated with this trainer, in order for the sight of the trainer to work properly.

...
	ds 1
wBluesHouseCurScript:: db
wViridianCityCurScript:: db
-	ds 2
+wRoute1CurScript:: db
+	ds 1
wPewterCityCurScript:: db
wRoute3CurScript:: db
wRoute4CurScript:: db
...

And with this we're done! Enjoy your new trainer and your romhacking :)

Clone this wiki locally