-
Notifications
You must be signed in to change notification settings - Fork 106
New Game Modes
The original poketcg base offers only one game mode, but here in the hacking world, we can add more if we're careful about it. This tutorial will give a bare-bones start on what a new game mode looks like with a brief example of its application.
This section will focus on making and defining a new game mode in general. However, for the purposes of this tutorial, we will be using a "Hard Mode" as a use case example. You can replace any of these names with whatever mode you choose, like a Prop 15/3 mode, or Little Cup mode, or anything else you can think of.
Step one, as per usual, is to define your new mode. Go to constants -> script_constants.asm to define a new event.
const_def
const EVENT_TEMP_TRADED_WITH_ISHIHARA ; $00
...
...
const EVENT_SAM_MENU_CHOICE ; $75
const EVENT_AARON_DECK_MENU_CHOICE ; $76
+ const EVENT_DIFFICULTY_MODE ; $77 ; add hard mode
DEF NUM_EVENT_FLAGS EQU const_valueAnd again define it in engine -> overworld -> scripting.asm because in this case we want to set the difficulty mode from the beginning of the game, which is governed under overworld scripts.
; location in wEventVars of each event var:
; offset - which byte holds the event value
; mask - which bits in the byte hold the value
; events 0-7 are reset when game resets
EventVarMasks:
table_width 2
event_def $3f, %10000000 ; EVENT_TEMP_TRADED_WITH_ISHIHARA
...
...
event_def $1c, %11110000 ; EVENT_SAM_MENU_CHOICE
event_def $1c, %00001111 ; EVENT_AARON_DECK_MENU_CHOICE
+ event_def $1d, %00000001 ; EVENT_DIFFICULTY_MODE ; add hard mode
assert_table_length NUM_EVENT_FLAGSIn this case we are only adding 1 new mode to the game, so a simple binary 0 or 1 will suffice. The lowest significant bit of byte $1d in wEventVars will represent which mode the player picked.
Finally, let's now define all the text that will be used in this particular tutorial. Again, your text may differ depending on what needs your mode has to offer.
In text_offsets,
+textpointer NormalModeText
+ textpointer HardModeText
+ textpointer SelectDifficultyText
+ textpointer NormalModeDescription
+ textpointer HardModeDescription
+ textpointer PlayerChoseNormalModeText
+ textpointer PlayerChoseHardModeTextAnd in a free text space like text13 for instance,
+NormalModeText:
+ text "Normal Mode"
+ done
+HardModeText:
+ text "Hard Mode"
+ done
+SelectDifficultyText:
+ text "Select the mode you'd like to play."
+ done
+NormalModeDescription:
+ text "The classic"
+ line "mode. No special"
+ line "additions."
+ done
+HardModeDescription:
+ text "All cards cost"
+ line "points. Decks"
+ line "must be at or"
+ line "under 100 pts." ; This text is specific to the example given in this tutorial at the end
+ done
+PlayerChoseNormalModeText:
+ text "You have chosen Normal Mode!"
+ done
+PlayerChoseHardModeText:
+ text "You have chosen Hard mode."
+ line "Good luck!"
+ doneNow that your new mode has been defined, it's time to do something with it by forcing the player to make a choice of what difficulty mode they want at the beginning of the game.
Let's further define what this mode actually does by creating a new file for its code. Go to src -> main.asm and define a new file in Menus 3, ROMX.
SECTION "Menus 3", ROMX
INCLUDE "engine/menus/debug_main.asm"
INCLUDE "engine/menus/main_menu.asm"
INCLUDE "engine/menus/debug.asm"
INCLUDE "engine/menus/wait_keys.asm"
INCLUDE "engine/gfx/default_palettes.asm"
INCLUDE "engine/menus/naming.asm"
+INCLUDE "engine/menus/select_difficulty.asm" ; add hard modeThen create a file in engine -> menus named select_difficulty and fill it in with this code:
(Note to better coders than me: The text boxes have a slight delay before they appear. If anyone knows how to get rid of that delay, be my guest and add that and delete this message)
PlayerDifficultySelectionScreen: ; governs what happens on a new "Select Difficulty" screen
; setup the screen
xor a
ld [wTileMapFill], a
call EmptyScreen
call ZeroObjectPositions
ld a, $01
ld [wVBlankOAMCopyToggle], a
call LoadSymbolsFont
lb de, $38, $bf
call SetupText
; print text
ld hl, .TextItems
call PlaceTextItems
ldtx hl, SelectDifficultyText
call DrawWideTextBox_PrintText
; Normal mode text box params
push af
lb de, 0, 2
lb bc, 10, 10
call DrawRegularTextBox ; draws a box to make it look good.
; Hard mode text box params
lb de, 10, 2
lb bc, 10, 10
call DrawRegularTextBox
pop af
ld hl, DifficultyDescriptions ; loads the difficulty options text
call PlaceTextItems
; set parameters for the cursor
lb de, 2, 1 ; cursor x and y ; sets initial cursor position at "normal mode"
lb bc, SYM_CURSOR_R, SYM_SPACE
call SetCursorParametersForTextBox
; start loop for selection
ld a, [wCurMenuItem]
jr .refresh_menu
.loop_input ; loops until a selection is made
call DoFrame
call RefreshMenuCursor
ldh a, [hKeysPressed]
bit B_PAD_A, a
jr nz, .selection_made
ldh a, [hDPadHeld]
and PAD_RIGHT | PAD_LEFT
jr z, .loop_input
ld a, SFX_CURSOR
call PlaySFX
call EraseCursor
ld hl, wCurMenuItem
ld a, [hl]
xor $1 ; toggle selected difficulty
ld [hl], a
.refresh_menu
or a
ld a, 1 ; "Normal mode" cursor x ; position of where the cursor must be for normal mode
jr z, .got_cursor_x
ld a, 12 ; "Hard mode" cursor x ; position of where the cursor must be for hard mode
.got_cursor_x
ld [wMenuCursorXOffset], a
xor a
ld [wCursorBlinkCounter], a
jr .loop_input
.selection_made ; player made a selection
; set the difficulty event value
ld a, [wCurMenuItem]
or a
ld a, EVENT_DIFFICULTY_MODE ; set the variable
jr nz, .HardModeEnabled ; If player chose hard mode, jump to there
farcall ZeroOutEventValue ; bit unset if at normal mode
ldtx hl, PlayerChoseNormalModeText ; and load the normal mode text
call DrawWideTextBox_WaitForInput
ret
.HardModeEnabled
farcall MaxOutEventValue ; bit set if at hard mode
ldtx hl, PlayerChoseHardModeText ; and load the hard mode text
call DrawWideTextBox_WaitForInput
ret
.TextItems:
textitem 2, 1, NormalModeText
textitem 13, 1, HardModeText
db $ff
DifficultyDescriptions:
textitem 1, 4, NormalModeDescription
textitem 11, 3, HardModeDescription
db $ff
ret
; An easy reference code to govern what happens if the player chose hard mode or not.
IsHardModeEnabled:
ld a, EVENT_DIFFICULTY_MODE ; load the value in EVENT_DIFFICULTY_MODE to a
farcall GetEventValue
or a
ret ; Return to whatever function called this
This will store the event value permanantly into the game, until New Game is selected again. This code also contains a reference to what game mode was picked to be used for other code. After we have to make a simple call to reference this entire thing at the beginning of the game, but only if "New Game" is selected. In engine -> menus -> main_menu, find
MainMenu_NewGame:
farcall Func_c1b1
+ call PlayerDifficultySelectionScreen ; add difficulty mode
call DisplayPlayerNamingScreen
farcall InitSaveData
call EnableSRAMWith this, you now have a new screen at the beginning of the game! If you used this tutorial's example, it will look like this:
And that's it, you now have a new mode which can do certain things depending on if the variable at the beginning of the game is set or not. The tutorial ends here, but there is one more section in case you want to view an example of how this can be applied to a game.
Throughout this tutorial, we used an example of "Hard mode" using the Points System (https://github.com/pret/poketcg/wiki/Points-System). In brief, the points system assigns point values to every card, ranging from 0 to 4. These points can be tallied up for the entire deck and displayed on screen. This fact can be used to create a new, more difficult mode, wherein the NPCs have no restrictions but the player's deck must be below a certain number of points.
To implement that specifically, go to Use Case 2 in the Points System page. This tutorial will not cover it, but suffice it to say that this counts as an alternative mode for the game due to the player being forced to have a certain number of points in their deck.
However, the points system is by far not the only way to use alternate game modes. As stated earlier, Prop 15/3, the popular Hall of Fame format, or anything else you'd like. In addition, this tutorial only covered 1 alternate game mode, it is theoretically possible to do even more game modes.