Skip to content

Instantly share code, notes, and snippets.

@charasyn
Created August 2, 2021 04:24
Show Gist options
  • Select an option

  • Save charasyn/57ade25c38392cd091ab7b8c432d8da2 to your computer and use it in GitHub Desktop.

Select an option

Save charasyn/57ade25c38392cd091ab7b8c432d8da2 to your computer and use it in GitHub Desktop.
import asm65816
import ccexpand
import cc_asmcall
define SPRITE_GROUPING_PTR_TABLE = 0xEF133F
define SPRITE_GROUPING_PTR_TABLE_p2 = 0xEF1341
define SPRITEMAP_UNUSED_PTR = 0xabb0
define SPRITEMAP_PALETTE = 0xabb2
define SPRITEMAP_PALETTE_p2 = 0xabb4
define SPRITEMAP_0 = 0xabb6
define DrawCharacter = 0xC08CD5
// This goes first in the file so CCScript will put it at the start
atm_card_asm: M_EB_Function_Wrapper({
LDA_i(SPRITEMAP_0)
STA_a(SPRITEMAP_UNUSED_PTR)
LDA_i(0xffff)
STA_a(SPRITEMAP_PALETTE)
STA_a(SPRITEMAP_PALETTE_p2)
// OK actually, we can use the battle sprite system.
// Use 0xC08CD5 to draw sprites on screen.
// Let's try to use sprite graphics at 0xd27880 ?
// Actually let's use Lucky's sprite group (150)
LDY_i(0x2c00) // VRAM Dest
STY_a(0x0097) // DMA_COPY_VRAM_DEST
LDX_i(150) // Lucky
LDY_i(0) // Anim 0
JSL(InitSingleCharacter)
LDA_i(120)
STA_d(0x00)
Loop:
JSL(0xC2DB3F) // ProcessVideoDrugs
JSL(0xC088B1) // ClearOam
LDA_i(SPRITEMAP_0)
LDX_i(0x0080)
LDY_i(0x0050)
JSL(DrawCharacter)
JSL(0xC08B26) // UpdateScreen
JSL(0xC08756) // WaitFrame
DEC_d(0x00)
BNE_a(Loop)
})
InitSingleCharacter: M_EB_Function_Wrapper_Clobber({
// Inputs:
// DMA_COPY_VRAM_DEST must be set
// X: Sprite group #
// Y: Animation #
// Vars:
// 0x00: Temporary storage of animation #
// 0x02: Sprite height
// 0x04: Initial DMA_COPY_VRAM_DEST
// 0x06, 0x08: Sprite group pointer
// 0x0a: Source pointer, used to extract bitfields for flip
// 0x0c: Spritemap: Object #
// 0x0e: Spritemap: Y pos
// Calculate object index from starting VRAM value
LDA_a(0x0097) // DMA_COPY_VRAM_DEST
STA_d(0x04)
STY_d(0x00)
TXA
ASL
ASL
TAX
LDA_xl(SPRITE_GROUPING_PTR_TABLE)
STA_d(0x06)
LDA_xl(SPRITE_GROUPING_PTR_TABLE_p2)
STA_d(0x08)
// Sprite group data pointer in 0x06
// Get sprite copy width (see create_entity.asm:144)
LDY_i(0x0001)
LDA_dly(0x06)
AND_i(0x00ff)
ASL
STA_a(0x0092) // DMA_COPY_SIZE
// Get sprite copy height
LDA_dl(0x06)
AND_i(0x00ff)
STA_d(0x02)
// If it's not even, clear the top row
AND_i(0x0001)
BEQ_a(NoClearTopRow)
// Clear top row
SEP(0x20)
// Set up index into VRAM DMA config table
LDA_8(0x03)
STA_a(0x0091) // UNKNOWN_7E0091
// Load pointer into VRAM DMA source: $C40BE8 is just zeros
LDA_8(0xc4)
STA_a(0x0096) // DMA_COPY_RAM_SRC + 2
REP(0x20)
LDA_i(0x0BE8)
STA_a(0x0094) // DMA_COPY_RAM_SRC
// Perform DMA
JSL(0xC0A56E)
NoClearTopRow:
// Load animation #
LDA_d(0x00)
ASL
ADC_i(0x0009)
TAY
LDA_dly(0x06)
STA_d(0x0a)
AND_i(0xfff0) // Mask out bitfield bits
STA_a(0x0094) // DMA_COPY_RAM_SRC
SEP(0x20)
LDA_8(0x00)
STA_a(0x0091) // UNKNOWN_7E0091
LDY_i(0x0008)
LDA_dly(0x06)
STA_a(0x0096) // DMA_COPY_RAM_SRC + 2
REP(0x20)
VramCopyLoop:
JSL(0xC0A56E)
DEC_d(0x02)
BEQ_a(DoneCopy)
LDA_a(0x0094) // DMA_COPY_RAM_SRC
CLC
ADC_a(0x0092) // DMA_COPY_SIZE
STA_a(0x0094) // DMA_COPY_RAM_SRC
BRA_a(VramCopyLoop)
DoneCopy:
// Begin setting up battle sprite
// Get height again
LDA_dl(0x06)
AND_i(0x00ff)
INC
LSR
STA_d(0x02) // This is actually the # of 16x16 sprites to generate
// Extract flip bit from ptr
LDA_d(0x0a)
STZ_d(0x0a)
AND_i(0x0001)
BEQ(5)
LDA_i(0x0040)
STA_d(0x0a)
LDY_i(0x0003)
LDA_dl(0x06)
AND_i(0x000e)
JSL(InitSingleCharacterPaletteLookup)
ORA_d(0x0a)
ORA_i(0x0030)
STA_d(0x0a)
// Get first object number
LDA_d(0x04)
LSR
LSR
LSR
LSR
AND_i(0xff)
STA_d(0x0c)
STZ_d(0x0e)
LDX_a(SPRITEMAP_UNUSED_PTR)
SpritemapLoop:
SEP(0x20)
LDA_d(0x0e)
STA_x(0x0000)
CLC
ADC_8(0x10)
STA_d(0x0e)
LDA_d(0x0c)
STA_x(0x0001)
INC
INC
STA_d(0x0c)
LDA_d(0x0a)
STA_x(0x0002)
LDA_8(0xf8)
STA_x(0x0003)
LDA_8(0x00)
STA_x(0x0004)
REP(0x20)
TXA
CLC
ADC_i(0x0005)
TAX
DEC_d(0x02)
BNE_a(SpritemapLoop)
// Finish the final sprite part
STX_a(SPRITEMAP_UNUSED_PTR)
DEX
LDA_x(0x0000)
ORA_i(0x0080)
STA_x(0x0000)
})
InitSingleCharacterPaletteLookup: M_EB_Function_Wrapper({
STA_d(0x00)
LDX_i(0x0003)
PaletteSearchLoop:
LDA_x(SPRITEMAP_PALETTE)
AND_i(0x00ff)
CMP_i(0x0080)
BPL_a(PaletteNotFound)
CMP_d(0x00)
BEQ_a(PaletteFound)
DEX
BPL_a(PaletteSearchLoop)
// Error condition - use last uploaded palette
LDA_i(0x0000)
BRA_a(ReturnPaletteBits)
PaletteNotFound:
// X: target
STX_d(0x02)
SEP(0x20)
LDA_d(0x00)
STA_x(SPRITEMAP_PALETTE)
REP(0x20)
// Calculate source address
LDA_i(0x00c3)
STA_d(0x10)
LDA_d(0x00)
ASL
ASL
ASL
ASL
STA_d(0x0e)
// Calculate CGRAM buffer address
TXA
ASL
ASL
ASL
ASL
ASL
ADC_i(0x0380)
// Get CGRAM palette size
LDX_i(0x0020)
// Copy X bytes from address in 0x0e to address in A
JSL(R_memcpy_to_ram)
// Mark that we need to reupload the palette
LDA_a(0x0030)
ORA_i(0x0010)
STA_a(0x0030)
LDA_d(0x02)
BRA_a(ReturnPaletteBits)
PaletteFound:
TXA
ReturnPaletteBits:
ASL
ORA_i(0x0008)
})
// Make Tracy say our custom text.
ROM[0xc66aa4] = { goto(test_text) }
test_text: {
"@Geegoo time?" newline
"[19 02]Yes[02][19 02]No[02][1C 07 02][11]{clearline}[09 02 {long giygas_time} {long no_giygas_time}]"
no_giygas_time:
"@Ok/ maybe later.| Cya" next
eob
giygas_time:
// Start battle with enemy group 478?
window_close(1)
cc_asmcall(setup_giygas, RET_NONE)
"[1f 23 {short 478}]"
window_open(1)
"@Ok cool. Good job bro." next
eob
}
setup_giygas: {
LDA_i(0x0004)
STA_a(0xA97A)
RTL
}
// Overwrite ATM card battle routine with our code
ROM[0xD584A8] = long atm_card_text
ROM[0xD584AC] = long atm_card_asm
ROM[0xD56B10] = byte 0x35
atm_card_text: {
newline
"@{user}[19 1F]{swap} used the" linebreak
" secret debug device![03]" eob
}
////////////////////////////////////////////////////////////////////////////////
////// Setup CCScript stuff: "newgame" commands, hijacks and pointer overwrites
//// "Normal" CCScript commands
// Set Ness' initial position
newgame_location(7720, 360)
// Set the "Startup" text. This normally handles the whole
// Onett night-time flyover sequence.
newgame_startup(newgame_text_in_map)
//// New ASM patch that runs when a new game is created, but
//// before the map is loaded.
ROM[0xc1feb2] = {
// We just call the new text block.
MText(newgame_text_before_map)
BRA(0) // 2-byte no-op
// This skips the following:
// - Set flag 11
// - Disable NPCs
// So if you want those things, make sure to do them yourselves!
// Specifically, if you want to disable/enable NPCs, try this:
// https://github.com/pk-hack/CoilSnake/wiki/CCScript-Library#enabledisable-all-npcs-by-cooprocks123e
}
//// Change a text pointer that is always called after loading a
//// save file but before loading the map.
_asmptr(0xC1FF1C, always_text_before_map)
////////////////////////////////////////////////////////////////////////////////
////// Actual text
newgame_text_before_map:
// This is where you should set all your flags, especially if
// you are adjusting some that affect the map.
call(newgame_set_flags_to_post_meteor)
// Add Paula
"[1f 11 02]"
// Set levels to 80
"[1e 08 01 50]"
"[1e 08 02 50]"
eob
always_text_before_map:
// Unset flag indicating that you just slept in a hotel.
// If this is set, it will play the Good Morning music,
// and you won't be able to sleep in the hotel again (without leaving).
unset(flag 383)
eob
newgame_text_in_map:
// You probably want to save here!
// This is the equivalent
save
eob
newgame_set_flags_to_post_meteor:
unset(flag 11) // Disable "peaceful mode"
set(flag 20) // Picky joined your party. Never unset
set(flag 34) // Post Starman Jr / Picky left party. Never unset
set(flag 94) // Seems to fix your mom
unset(flag 95) // Makes phones work (might already be unset)
set(flag 98) // Makes Ness's phone specifically work
set(flag 100) // King doesn't want to go outside
set(flag 104) // Pokey/Picky punished, first day events cleaned up
unset(flag 107) // When on, primes sunrise transition exiting Pokey's house
set(flag 199) // Know how to call Ness's dad
set(flag 200) // Know how to call Ness's mom
set(flag 209) // Onett warp - necessary to have correct Mom text
set(flag 375) // Most Onett townsfolk
set(flag 422) // Onett daytime palette
set(flag 469) // Suppresses the day 1 townsfolk
unset(flag 476) // Onett roadblocks
unset(flag 477) // Ness head in his room
set(flag 517) // Ness's house's lights are on
unset(flag 532) // No meteor sound in Ness' house
unset(flag 533) // No meteor sound in Ness' room
unset(flag 749) // No pajamas?
eob
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment