Skip to content

Adding a Tradeback NPC

SonicRay100 edited this page Oct 21, 2023 · 9 revisions

First, open up master/main.asm, and find this SECTION `"bank3F", ROMX, INCLUDE the file we're about to make, and save the changes.

SECTION "bank3F", ROMX

INCLUDE "engine/tilesets/tileset_anims.asm"
INCLUDE "engine/events/npc_trade.asm"
INCLUDE "engine/events/mom_phone.asm"
+INCLUDE "engine/events/trader.asm"

Now we make our way to master/data/events/special_pointers.asm, and we scroll all the way to the bottom of the file, and add a new special pointer for the trader. The comment is not needed if you don't want it, but it can be useful to keep track of what you've added to the game.

add_special LoadMapPalettes
add_special UnusedFindItemInPCOrBag

add_special InitialSetDSTFlag
add_special InitialClearDSTFlag
add_special UnusedDummySpecial ; unused

+ add_special trader ; Not part of Crystal originally

Save and continue.

The second part of this step is in master/engine/events/specials.asm, let's go there and scroll to the bottom again. All we're doing here is making a special that hooks the NPC that we'll make in the next step to the file that we'll make in the last step. Anyway, we need to make a label that matches the add_special label we just added. Then we need to farcall the label that will be in the file we make at the end, I've named that label Trader. Finally we return to the place that called us here initially once everything is done. All of that should resemble this, which should now occupy the very bottom of master/engine/events/specials.asm

PrintDiploma:
	call FadeToMenu
	farcall _PrintDiploma
	call ExitAllMenus
	ret

TrainerHouse:
	ld a, BANK(sMysteryGiftTrainerHouseFlag)
	call OpenSRAM
	ld a, [sMysteryGiftTrainerHouseFlag]
	ld [wScriptVar], a
	jp CloseSRAM

+trader:
+     farcall Trader
+	 ret

Again, save your file and continue.

The final step before we add our routine is to make someone who can actually perform it, so pick which map you want your trader to appear in, and open the .asm file for that map. In this example, I'll use Elm's Lab since it's an easy starting location for testing, but you can put the NPC anywhere you like. Open up master/maps/ElmsLab.asm, and add a new const for your NPC.

	object_const_def
	const ELMSLAB_ELM
	const ELMSLAB_ELMS_AIDE
	const ELMSLAB_POKE_BALL1
	const ELMSLAB_POKE_BALL2
	const ELMSLAB_POKE_BALL3
	const ELMSLAB_OFFICER
+	const ELMSLAB_TRADER ; Not from Crystal

Okay, let's add some code that hooks to the special we just added. We want our new NPC to face the player when spoken to, we need to show a text box because the first thing we're going to do in the actual meat of the process is show some text, and we also need to close that textbox when everything's done. We'll also be including a line to make that final textbox wait for a button press to close. Here's what we've added:

+ Trader: ; not from Crystal
+ faceplayer
+ opentext
+ special trader
+ waitbutton
+ closetext
+ end

If you like to keep things neat, you've added this where all the other NPCs were, but if you're a slob, anywhere that's not interrupting other code and is between the constants and the object events is fine. We're almost there.

The last thing we have to do is make the NPC. Go nuts with the customization here you can change the way this guy moves, his appearance, his color, and where he stands(or starts when the map is loaded if you want him to walk around). For the purposes of this tutorial, we're just going to use a duplicate of Professor Elm's NPC type, and use SPRITE_RED for the new NPC's appearance.

	def_object_events
	object_event  5,  2, SPRITE_ELM, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, ProfElmScript, -1
	object_event  2,  9, SPRITE_SCIENTIST, SPRITEMOVEDATA_SPINRANDOM_SLOW, 0, 0, -1, -1, PAL_NPC_BLUE, OBJECTTYPE_SCRIPT, 0, ElmsAideScript, EVENT_ELMS_AIDE_IN_LAB
	object_event  6,  3, SPRITE_POKE_BALL, SPRITEMOVEDATA_STILL, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, CyndaquilPokeBallScript, EVENT_CYNDAQUIL_POKEBALL_IN_ELMS_LAB
	object_event  7,  3, SPRITE_POKE_BALL, SPRITEMOVEDATA_STILL, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, TotodilePokeBallScript, EVENT_TOTODILE_POKEBALL_IN_ELMS_LAB
	object_event  8,  3, SPRITE_POKE_BALL, SPRITEMOVEDATA_STILL, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, ChikoritaPokeBallScript, EVENT_CHIKORITA_POKEBALL_IN_ELMS_LAB
	object_event  5,  3, SPRITE_OFFICER, SPRITEMOVEDATA_STANDING_UP, 0, 0, -1, -1, PAL_NPC_BLUE, OBJECTTYPE_SCRIPT, 0, CopScript, EVENT_COP_IN_ELMS_LAB
+	object_event  4,  1, SPRITE_RED, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, Trader, -1

Now, for all the heavy lifting. Copy and paste the following into a new .asm file, save it as "trader.asm" then put that file in master/engine/events

; Fun fact, the 'trade' part of a trade isn't checked to evolve a Pokemon, It seems that just the trade animation and the link state are enough
; No Pokemon is ever removed from or added to your party using this code because of that fact

Trader::
ld hl, TraderText
call PrintText
call YesNoBox
ld hl, TraderCanceledText
jr c, .done

; Select givemon from party
ld b, PARTYMENUACTION_GIVE_MON
farcall SelectTradeOrDayCareMon
ld a, [wCurPartyMon]
ld hl, TraderCanceledText
jr c, .done

ld hl, NPCTradeCableText
call PrintText

call TradeWithTrader
call RestartMapMusic

ld hl, TraderCompleteText
call PrintText
ret
.done
call PrintText
ret
;Loads the appropriate data to prefor the trade animation,
TradeWithTrader:
;Sets the link state to trading so that evolution is possible.
ld a, LINK_TRADECENTER
ld [wLinkMode], a

;Establish names of trading trainers
ld hl, wPlayerName
ld de, wPlayerTrademonSenderName
ld bc, NAME_LENGTH
call CopyBytes

ld hl, .Trader
ld de, wOTTrademonSenderName
ld bc, NAME_LENGTH
call CopyBytes
.Trader:
db "TRADER@"

;Establish mon's species
ld a, [wCurPartyMon]
ld hl, wPartySpecies
ld b, 0
ld c, a
add hl, bc
ld a, [hl]
ld [wPlayerTrademonSpecies], a
ld [wOTTrademonSpecies], a


;Establish mon's ID number
ld hl, wPartyMon1ID
ld a, [wCurPartyMon]
call GetPartyLocation
ld a, [hli]
ld [wPlayerTrademonID], a
ld [wOTTrademonID], a
ld a, [hl]
ld [wPlayerTrademonID + 1], a
ld [wOTTrademonID + 1], a


; Correctly display Pokemon Shiny Status on the trade screen.
ld hl, wPartyMon1DVs
ld a, [wCurPartyMon]
call GetPartyLocation
ld a, [hli]
ld [wPlayerTrademonDVs], a
ld [wOTTrademonDVs], a
ld a, [hl]
ld [wPlayerTrademonDVs + 1], a
ld [wOTTrademonDVs + 1], a 

;Establish mon's OT's name
ld a, [wCurPartyMon]
ld hl, wPartyMonOT
call SkipNames
ld de, wPlayerTrademonOTName
ld bc, NAME_LENGTH
call CopyBytes

ld hl, wPartyMonOT
ld de, wOTTrademonOTName
ld bc, NAME_LENGTH
call CopyBytes

;Makes it so that pressing B will not cancel the evolution, standard for trade based evolution
ld a, 1
ld [wForceEvolution], a

;run the trade animation/ evolves the mon if applicable
call DisableSpriteUpdates
; wTradeDialog aliases wFrameCounter, which TradeAnimation uses
ld a, [wTradeDialog]
push af
predef TradeAnimation
callfar EvolvePokemon
pop af
ld [wTradeDialog], a
call ReturnToMapWithSpeechTextbox

;Put's the link mode back to not linked, battles don't work right otherwise.
ld a, LINK_NULL
ld [wLinkMode], a
ret

TraderText::
text "Hello there! I'm"
line "the TRADER."

para "I can trade a"
line "#MON of your"
cont "choosing back to"
cont "you."

para "Would you like to"
line "trade?"
done

TraderCanceledText::
text "Oh, ok then."

para "Come back if you"
line "change your mind."
done

TraderCompleteText::
text "And... Done!"

para "I hope that"
line "was helpful!"
done

Congratulations! You now have your very own Tradeback Guy!

Clone this wiki locally