Add a new Mart - pret/pokecrystal GitHub Wiki

This tutorial is for how to add a new Poké Mart. As an example, we'll add an evolution stone merchant to Goldenrod Dept. Store.

Contents

  1. Define a mart constant
  2. Give it an inventory
  3. Use it in a map script
  4. Add a new type of Mart
  5. Sell more than 10 items per Mart

1. Define a mart constant

Edit constants/mart_constants.asm (or constants/item_data_constants.asm in older versions of pokecrystal):

; Marts indexes (see data/items/marts.asm)
	const_def
	const MART_CHERRYGROVE
	const MART_CHERRYGROVE_DEX
	const MART_VIOLET
	const MART_AZALEA
	const MART_CIANWOOD
	const MART_GOLDENROD_2F_1
	const MART_GOLDENROD_2F_2
	const MART_GOLDENROD_3F
+	const MART_GOLDENROD_3F_2
	const MART_GOLDENROD_4F
	const MART_GOLDENROD_5F_1
	const MART_GOLDENROD_5F_2
	const MART_GOLDENROD_5F_3
	const MART_GOLDENROD_5F_4
	...

2. Give it an inventory

Edit data/items/marts.asm:

 Marts:
 ; entries correspond to MART_* constants
 	dw MartCherrygrove
 	dw MartCherrygroveDex
 	dw MartViolet
 	dw MartAzalea
 	dw MartCianwood
 	dw MartGoldenrod2F1
 	dw MartGoldenrod2F2
 	dw MartGoldenrod3F
+	dw MartGoldenrod3F2
 	dw MartGoldenrod4F
 	dw MartGoldenrod5F1
 	dw MartGoldenrod5F2
 	dw MartGoldenrod5F3
 	dw MartGoldenrod5F4
 	...
 .End

 ...

 MartGoldenrod3F:
 	db 7 ; # items
 	db X_SPEED
 	db X_SPECIAL
 	db X_DEFEND
 	db X_ATTACK
 	db DIRE_HIT
 	db GUARD_SPEC
 	db X_ACCURACY
 	db -1 ; end
+
+MartGoldenrod3F2:
+	db 6 ; # items
+	db FIRE_STONE
+	db THUNDERSTONE
+	db WATER_STONE
+	db LEAF_STONE
+	db MOON_STONE
+	db SUN_STONE
+	db -1 ; end

A Mart can sell up to 10 items.

3. Use it in a map script

The core idea here is to use the pokemart script command, passing it a mart type and the new MART_GOLDENROD_3F_2 inventory constant.

Edit maps/GoldenrodDeptStore3F.asm:

 	object_const_def
 	const GOLDENRODDEPTSTORE3F_CLERK
+	const GOLDENRODDEPTSTORE3F_CLERK2
 	const GOLDENRODDEPTSTORE3F_SUPER_NERD
 	const GOLDENRODDEPTSTORE3F_ROCKER

 ...

 GoldenrodDeptStore3FClerkScript:
 	faceplayer
 	opentext
 	pokemart MARTTYPE_STANDARD, MART_GOLDENROD_3F
 	closetext
 	end
+
+GoldenrodDeptStore3FClerk2Script:
+	faceplayer
+	opentext
+	pokemart MARTTYPE_STANDARD, MART_GOLDENROD_3F_2
+	closetext
+	end

 ...

 	def_object_events
 	object_event  6,  1, SPRITE_CLERK, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, GoldenrodDeptStore3FClerkScript, -1
+	object_event  7,  1, SPRITE_CLERK, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, GoldenrodDeptStore3FClerk2Script, -1
 	object_event 12,  5, SPRITE_SUPER_NERD, SPRITEMOVEDATA_SPINRANDOM_FAST, 0, 1, -1, -1, PAL_NPC_RED, OBJECTTYPE_SCRIPT, 0, GoldenrodDeptStore3FSuperNerdScript, -1
 	object_event  2,  5, SPRITE_ROCKER, SPRITEMOVEDATA_WALK_UP_DOWN, 0, 1, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, GoldenrodDeptStore3FRockerScript, -1

That's it!

Screenshot

4. Add a new type of Mart

We used MARTTYPE_STANDARD before because that's what typical Mart clerks use. But there are other types:

  • MARTTYPE_BITTER: Uses unique phrases for the bitter herb merchant in Goldenrod Underground.
  • MARTTYPE_PHARMACY: Uses unique phrases for the pharmacist in Cianwood City.
  • MARTTYPE_BARGAIN: Has a special inventory and behavior for the bargain merchant in Goldenrod Underground. (Items are half-price but only sells one of each; see data/items/bargain_shop.asm.)
  • MARTTYPE_ROOFTOP: Has a special inventory and behavior for the rooftop sale merchant in Goldenrod Dept. Store. (Items are low-price; see data/items/rooftop_sale.asm.)

Adding custom behavior like MARTTYPE_BARGAIN or MARTTYPE_ROOFTOP is beyond the scope of this tutorial, but it isn't hard to add a type that just has different phrases. We'll add a "shady" mart that sells suspicious items.

Edit constants/mart_constants.asm:

 ; mart types (see engine/items/mart.asm)
 	const_def
 	const MARTTYPE_STANDARD
 	const MARTTYPE_BITTER
 	const MARTTYPE_BARGAIN
 	const MARTTYPE_PHARMACY
 	const MARTTYPE_ROOFTOP
+	const MARTTYPE_SHADY

Edit engine/items/mart.asm:

 OpenMartDialog::
 	...
 
 .dialogs
 	dw MartDialog
 	dw HerbShop
 	dw BargainShop
 	dw Pharmacist
 	dw RooftopSale
+	dw ShadyShop
 
 ...
 
 Pharmacist:
 	call FarReadMart
 	call LoadStandardMenuHeader
 	ld hl, Text_Pharmacist_Intro
 	call MartTextbox
 	call BuyMenu
 	ld hl, Text_Pharmacist_ComeAgain
 	call MartTextbox
 	ret
+
+ShadyShop:
+	call FarReadMart
+	call LoadStandardMenuHeader
+	ld hl, Text_ShadyShop_Intro
+	call MartTextbox
+	call BuyMenu
+	ld hl, Text_ShadyShop_ComeAgain
+	jp MartTextbox

 ...

 GetMartDialogGroup:
 	...
 
 .MartTextFunctionPointers:
 	dwb .StandardMartPointers, 0
 	dwb .HerbShopPointers, 0
 	dwb .BargainShopPointers, 1
 	dwb .PharmacyPointers, 0
 	dwb .StandardMartPointers, 2
+	dwb .ShadyPointers, 0

 ...

 .PharmacyPointers:
 	dw Text_Pharmacy_HowMany
 	dw Text_Pharmacy_CostsThisMuch
 	dw Text_Pharmacy_InsufficientFunds
 	dw Text_Pharmacy_BagFull
 	dw Text_Pharmacy_HereYouGo
 	dw BuyMenuLoop
+
+.ShadyPointers:
+	dw Text_ShadyShop_HowMany
+	dw Text_ShadyShop_CostsThisMuch
+	dw Text_ShadyShop_InsufficientFunds
+	dw Text_ShadyShop_BagFull
+	dw Text_ShadyShop_HereYouGo
+	dw BuyMenuLoop

 ...
+
+Text_ShadyShop_Intro:
+	text_far ShadyShop_IntroText
+	text_end
+
+Text_ShadyShop_ComeAgain:
+	text_far ShadyShop_ComeAgainText
+	text_end
+
+Text_ShadyShop_HowMany:
+	text_far ShadyShop_HowManyText
+	text_end
+
+Text_ShadyShop_CostsThisMuch:
+	text_far ShadyShop_CostsThisMuchText
+	text_end
+
+Text_ShadyShop_InsufficientFunds:
+	text_far ShadyShop_InsufficientFundsText
+	text_end
+
+Text_ShadyShop_BagFull:
+	text_far ShadyShop_BagFullText
+	text_end
+
+Text_ShadyShop_HereYouGo:
+	text_far ShadyShop_HereYouGoText
+	text_end

And edit data/text/common_3.asm:

+ShadyShop_IntroText::
+	text "Hello, kiddo!"
+
+	para "Wanna buy any of"
+	line "my goods?"
+
+	para "They fell off the"
+	line "back of a truck!"
+	cont "Hehehe…"
+	done
+
+ShadyShop_ComeAgainText::
+	text "See ya, kid!"
+	done
+
+ShadyShop_HowManyText::
+	text "How many you"
+	line "need?"
+	done
+
+ShadyShop_CostsThisMuchText::
+	text "That'll cost ya"
+	line "¥@"
+	text_decimal hMoneyTemp, 3, 6
+	text ". 'Kay?"
+	done
+
+ShadyShop_InsufficientFundsText::
+	text "That ain't enough!"
+	done
+
+ShadyShop_BagFullText::
+	text "Hehe, you can't"
+	line "carry it!"
+	done
+
+ShadyShop_HereYouGoText::
+	text "Cha-ching!"
+	done

This new Mart type is appropriate for the Team Rocket merchant in Mahogany Town. So edit maps/MahoganyMart1F.asm:

 MahogayMart1FPharmacistScript:
 	faceplayer
 	opentext
 	checkevent EVENT_DECIDED_TO_HELP_LANCE
 	iftrue .LanceEntered
-	pokemart MARTTYPE_STANDARD, MART_MAHOGANY_1
+	pokemart MARTTYPE_SHADY, MART_MAHOGANY_1
 	closetext
 	end

And it works!

Screenshot

5. Sell more than 10 items per Mart

This is a simple improvement.

Edit wram.asm:

 SECTION UNION "Miscellaneous WRAM 1", WRAMX
 
 ; mart items
 wMartItem1BCD:: ds 3
 wMartItem2BCD:: ds 3
 wMartItem3BCD:: ds 3
 wMartItem4BCD:: ds 3
 wMartItem5BCD:: ds 3
 wMartItem6BCD:: ds 3
 wMartItem7BCD:: ds 3
 wMartItem8BCD:: ds 3
 wMartItem9BCD:: ds 3
 wMartItem10BCD:: ds 3
+wMartItem11BCD:: ds 3
+wMartItem12BCD:: ds 3
+wMartItem13BCD:: ds 3
+wMartItem14BCD:: ds 3
+wMartItem15BCD:: ds 3
+wMartItem16BCD:: ds 3
+wMartItem17BCD:: ds 3
+wMartItem18BCD:: ds 3
+wMartItem19BCD:: ds 3
+wMartItem20BCD:: ds 3

 ...

 UNION
 ; mart data
 wCurMartCount:: db
-wCurMartItems:: ds 15
+wCurMartItems:: ds 21

wCurMartItems stores the inventory from data/items/marts.asm, including the count and the ending −1. So with 21 bytes, a Mart can sell 20 items. Then there just has to be enough space to store 20 prices.