├── .github ├── actions │ └── cache_cc65 │ │ └── action.yaml └── workflows │ └── main.yml ├── .gitignore ├── Makefile ├── credits.txt ├── layout ├── license.txt ├── readme.md └── src ├── audio ├── audio.asm ├── blank.asm ├── famistudio.asm ├── famistudio_null.asm └── sfx.asm ├── celeste.asm ├── chr ├── b_cass1.chr ├── b_cass2.chr ├── b_ch1ca.chr ├── b_ch1cb.chr ├── b_ch2ca.chr ├── b_ch2cb.chr ├── b_lvl0.chr ├── b_lvl1.chr ├── b_lvl2.chr ├── b_lvl2b.chr ├── b_lvl2c.chr ├── b_lvl2d.chr ├── b_lvl2e.chr ├── b_lvl2f.chr ├── b_lvl2g.chr ├── b_lvl2h.chr ├── b_lvl3.chr ├── b_lvl3bg.chr ├── b_options.chr ├── b_overw.chr ├── b_postcard.chr ├── b_title.chr ├── ch3bg.nss ├── d_bade.chr ├── d_count.chr ├── d_gran.chr ├── d_made.chr ├── d_main.chr ├── d_mome.chr ├── d_theo.chr ├── sp_anim.chr ├── sp_ch1c.chr ├── sp_ch2c.chr ├── sp_gener.chr ├── sp_heart.chr ├── sp_level0.chr ├── sp_level0b.chr ├── sp_level1.chr ├── sp_level1b.chr ├── sp_level1c.chr ├── sp_level2.chr ├── sp_level2b.chr ├── sp_level2c.chr ├── sp_level2cb.chr ├── sp_level2d.chr ├── sp_level2e.chr ├── sp_level2f.chr ├── sp_level2g.chr ├── sp_level2h.chr ├── sp_level2i.chr ├── sp_level2j.chr ├── sp_level2k.chr ├── sp_level2lm.chr ├── sp_level2n.chr ├── sp_level3.chr ├── sp_overw.chr ├── sp_pause.chr ├── sp_player.chr └── sp_plrdie.chr ├── d_font.asm ├── d_font.chr ├── d_fontw.asm ├── d_macros.asm ├── d_nmi.asm ├── d_portra.asm ├── d_update.asm ├── defines.asm ├── dialogif.asm ├── e_draw.asm ├── e_physic.asm ├── e_spawn.asm ├── e_update.asm ├── extra ├── chcomp.asm ├── endgfx.asm ├── letter.asm ├── lettergfx.asm ├── lettersfx.asm └── levelend.asm ├── g_camera.asm ├── g_control.asm ├── g_decomp.asm ├── g_draw.asm ├── g_level.asm ├── g_math.asm ├── g_palette.asm ├── g_palloc.asm ├── g_pause.asm ├── g_physic.asm ├── g_respawn.asm ├── g_save.asm ├── g_scroll.asm ├── g_sfx.asm ├── g_util.asm ├── g_wait.asm ├── g_wipe.asm ├── gam_main.asm ├── game.asm ├── globals.asm ├── irq.asm ├── level0 ├── bank_0.asm ├── dialog.asm ├── entity.asm ├── layout.txt ├── metatile.asm ├── mpalette.txt ├── music │ └── music.asm ├── palette.asm ├── roomlist.asm ├── rooms │ └── 0.asm ├── sprites.txt ├── tgroups.txt └── warplist.asm ├── level1 ├── bank_0.asm ├── bank_1.asm ├── bank_2.asm ├── bank_3.asm ├── dialog.asm ├── entity.asm ├── layout.txt ├── metatile.asm ├── mpalette.txt ├── music │ ├── level1.dmc │ └── music.asm ├── palette.asm ├── room_end.asm ├── roomlist.asm ├── rooms │ ├── 0.asm │ ├── 1.asm │ ├── 2.asm │ └── 3.asm ├── tgroups.txt └── warplist.asm ├── level2 ├── bank_0.asm ├── bank_1.asm ├── bank_2.asm ├── bank_3.asm ├── bank_4.asm ├── bank_5.asm ├── chaser.asm ├── dialog.asm ├── entity.asm ├── layout.txt ├── metatile.asm ├── mpalette.txt ├── music │ ├── level2.asm │ └── level2.dmc ├── palette.asm ├── payphone.asm ├── payphone2.asm ├── roomlist.asm ├── rooms │ ├── 0.asm │ ├── 1.asm │ ├── 2.asm │ ├── 3.asm │ ├── 4.asm │ └── 5.asm ├── structs.asm ├── tgroups.txt └── warplist.asm ├── level3 ├── bank_0.asm ├── bank_1.asm ├── entity.asm ├── layout.txt ├── metatile.asm ├── mpalette.txt ├── palette.asm ├── roomlist.asm ├── rooms │ ├── 0.asm │ └── 1.asm ├── testmusic.asm ├── tgroups.txt └── warplist.asm ├── levels.txt ├── lvltable.asm ├── m_auxil.asm ├── m_fade.asm ├── nmi.asm ├── overwld.asm ├── p_physic.asm ├── p_scroll.asm ├── p_trace.asm ├── prg_dial.asm ├── prg_ents.asm ├── prg_game.asm ├── prg_main.asm ├── prg_paus.asm ├── prg_phys.asm ├── prg_ttle.asm ├── prg_xtra.asm ├── prologue.asm ├── s_bgfx.asm ├── s_entity.asm ├── s_pldraw.asm ├── s_title.asm ├── title.asm ├── title ├── helper.asm ├── mountain.asm ├── overwld.asm ├── prologue.asm ├── rle.asm ├── title.asm └── titlescr.asm ├── update.asm ├── weather.asm ├── x_rle.asm ├── x_rmtran.asm └── xtraif.asm /.github/actions/cache_cc65/action.yaml: -------------------------------------------------------------------------------- 1 | name: Cache CC65 2 | description: Caches CC65 and builds it from source if missing 3 | inputs: 4 | cc65Ref: 5 | description: "CC65 Git Ref (used to checkout a fixed version)" 6 | required: false 7 | default: "master" 8 | cc65Path: 9 | description: "CC65 path to cache" 10 | required: false 11 | default: ${{ github.workspace }}/opt/cc65 12 | runs: 13 | using: "composite" 14 | steps: 15 | # Cache CC65 16 | - uses: actions/cache@v4 17 | id: cache_cc65 18 | with: 19 | path: ${{ inputs.cc65Path }} 20 | key: ${{ runner.os }}-cc65-${{ inputs.cc65Ref }}-${{ hashFiles('.github/actions/cache_cc65/*') }} 21 | # Checkout CC65 22 | - uses: actions/checkout@v4 23 | if: steps.cache_cc65.outputs.cache-hit != 'true' 24 | with: 25 | repository: cc65/cc65 26 | ref: ${{ inputs.cc65Ref }} 27 | path: './cc65' 28 | # Build CC65 29 | - if: steps.cache_cc65.outputs.cache-hit != 'true' 30 | run: | 31 | cd cc65 32 | PREFIX=${{ inputs.cc65Path }} make 33 | PREFIX=${{ inputs.cc65Path }} make install 34 | shell: bash 35 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build ROM 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build_rom: 7 | runs-on: ubuntu-latest 8 | name: Compile ROM 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v4 12 | - name: Cache cc65 13 | uses: ./.github/actions/cache_cc65 14 | - name: Set path 15 | run: | 16 | echo "${{ github.workspace }}/opt/cc65/bin" >> $GITHUB_PATH 17 | - name: Build the game 18 | run: make 19 | - name: Upload artifacts 20 | uses: actions/upload-artifact@v4 21 | with: 22 | name: celeste.nes 23 | path: celeste.nes 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | keep/* 2 | *.dbg 3 | *.deb 4 | *.map 5 | *.dep 6 | *.lst 7 | *.o 8 | *.nes 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 iProgramInCpp 2 | 3 | AS = ca65 4 | CC = cc65 5 | LD = ld65 6 | 7 | #DEBUGSW= 8 | DEBUGSW=-DDEBUG 9 | 10 | .PHONY: clean 11 | 12 | build: celeste.nes 13 | 14 | %.o: src/%.asm 15 | $(AS) -g --create-dep "$@.dep" --debug-info $< -o $@ --listing "$(notdir $@).lst" $(DEBUGSW) 16 | 17 | celeste.nes: layout celeste.o 18 | $(LD) --dbgfile $@.dbg -C $^ -o $@ -m $@.map 19 | 20 | clean: 21 | rm -f celeste.nes *.dep *.o *.dbg 22 | 23 | include $(wildcard *.dep) 24 | -------------------------------------------------------------------------------- /credits.txt: -------------------------------------------------------------------------------- 1 | C R E D I T S 2 | 3 | 4 | iProgramInCpp - Programming, levels, graphics 5 | 6 | livvy94 - "Resurrections" cover 7 | 8 | zeta0134 - "First Steps" cover 9 | 10 | buttersoap_ - Sound effects, first "First Steps" cover 11 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2025 iProgramInCpp 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | “Software”), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject 9 | to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Celeste NES 2 | 3 | This is the source code to iProgramInCpp's attempt to recreate *[Celeste](https://www.celestegame.com)* 4 | for the Nintendo Entertainment System / Family Computer. 5 | 6 | Currently this is a massive work in progress. This means that the game may be 7 | either: 8 | - buggy, 9 | - unstable, 10 | - or downright broken. 11 | 12 | As of January 25th, 2025, only the first two chapters have been completed. 13 | 14 | Development will happen in the `development` branch, and all pull requests will be pulled 15 | into it. The `demo-1` branch will contain the source code for the demo as released on 16 | January 25th, 2025. 17 | 18 | ## Discord Server 19 | 20 | If you would like to chat about this game, you can do so in our Discord server: https://discord.gg/JWSUpfCubz 21 | 22 | ## Development Builds 23 | 24 | TBA 25 | 26 | ## Credits 27 | 28 | - iProgramInCpp - Lead developer 29 | 30 | - [livvy94](https://youtube.com/@livvy94) - "Resurrections" rendition 31 | 32 | - [zeta0134](https://github.com/zeta0134) - "First Steps" rendition 33 | 34 | - [Persune](https://gumball2415.github.io) - Chapter Complete rendition 35 | 36 | - [Buttersoap](https://www.youtube.com/@iputsoapondabutter) - Sound effects, and first "First Steps" rendition 37 | 38 | - The members of the [NESdev discord server](https://discord.gg/VFnWZV8GWk) for miscellaneous help 39 | 40 | - [TFDSoft](https://twitter.com/TFDSoft) for support, and also the nightly build workflow 41 | 42 | - [Extremely OK Games](https://exok.com) for creating the wonderful game of [Celeste](https://www.celestegame.com) 43 | 44 | - And you, for playing! 45 | 46 | ## Building 47 | 48 | To build you will need the `cc65` toolchain installed (`ca65` and `ld65` are used), as well as a posix-compliant 49 | `make` implementation. 50 | 51 | Run the `make` command to build the ROM for the game. 52 | 53 | ### Warning 54 | 55 | Certain package managers (Ubuntu, for example) will feature outdated builds of ca65 (`ca65 V2.18 - Ubuntu 2.19-1` 56 | for example) Unfortunately, it doesn't support all the features that this code base uses. 57 | 58 | You will need to get a more up to date version. Compiling from source will work. 59 | 60 | ## Code Quality Warning 61 | 62 | Because this is my first project written in 6502 assembly, code quality will vary. If you spot 63 | anything unusual, let me know and I will fix it right up! 64 | 65 | ## Physics 66 | 67 | I have tried my best to make the physics as accurate to the original game as I could, even referencing 68 | the officially released [Player class code](https://github.com/NoelFB/Celeste/blob/master/Source/Player/Player.cs) 69 | from Celeste. However, some features may not be accurately implemented. 70 | 71 | If you know how to write 6502 assembly and also happen to be a keen-eyed player who can notice such 72 | things, **please let me know** with a pull request. 73 | 74 | It is important to also acknowledge the NES' limitations. I think I've struck a good balance between 75 | accuracy and speed. 76 | 77 | ## License 78 | 79 | This project has been neither created nor endorsed by the Celeste team. 80 | 81 | The *Celeste* IP is owned by [Maddy Makes Games, Inc.](https://maddymakesgames.com). 82 | 83 | The *graphics* (all \*.chr files, except d_font.chr) and *music* (`src/level0/music`, 84 | `src/level1/music`, and `src/level2/music`) are under a **strictly non-commercial license**, 85 | meaning you **may not** use these assets for **any** commercial purpose. 86 | 87 | The game code (`src/`) is licensed under [the MIT license](license.txt) 88 | -------------------------------------------------------------------------------- /src/audio/audio.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; Define an external config for FamiStudio 4 | FAMISTUDIO_CFG_EXTERNAL = 1 5 | 6 | .define FAMISTUDIO_CA65_ZP_SEGMENT ZEROPAGE 7 | .define FAMISTUDIO_CA65_RAM_SEGMENT FMSRAM 8 | .define FAMISTUDIO_CA65_CODE_SEGMENT PRG_MAIN 9 | 10 | FAMISTUDIO_CFG_NTSC_SUPPORT = 1 ; no PAL support yet 11 | FAMISTUDIO_CFG_DPCM_SUPPORT = 1 12 | FAMISTUDIO_CFG_THREAD = 1 ; to be able to call FamiStudio SFX routines from main thread 13 | 14 | ; things defined by the demo. I don't care about most of these 15 | FAMISTUDIO_CFG_SFX_SUPPORT = 1 16 | FAMISTUDIO_CFG_SFX_STREAMS = 2 17 | FAMISTUDIO_CFG_EQUALIZER = 1 18 | FAMISTUDIO_USE_VOLUME_TRACK = 1 19 | FAMISTUDIO_USE_PITCH_TRACK = 1 20 | FAMISTUDIO_USE_SLIDE_NOTES = 1 21 | FAMISTUDIO_USE_NOISE_SLIDE_NOTES = 1 22 | FAMISTUDIO_USE_VIBRATO = 1 23 | FAMISTUDIO_USE_ARPEGGIO = 1 24 | FAMISTUDIO_CFG_SMOOTH_VIBRATO = 1 25 | FAMISTUDIO_USE_RELEASE_NOTES = 1 26 | FAMISTUDIO_USE_DUTYCYCLE_EFFECT = 1 27 | FAMISTUDIO_USE_VOLUME_SLIDES = 1 28 | FAMISTUDIO_USE_DELTA_COUNTER = 1 29 | ;FAMISTUDIO_USE_PHASE_RESET = 1 30 | ;FAMISTUDIO_USE_INSTRUMENT_EXTENDED_RANGE = 1 31 | FAMISTUDIO_USE_FAMITRACKER_TEMPO = 1 ; bruh 32 | FAMISTUDIO_USE_FAMITRACKER_DELAYED_NOTES_OR_CUTS = 1 ; bruuuh 33 | FAMISTUDIO_DPCM_OFF = $c200 34 | 35 | .include "famistudio.asm" 36 | ;.include "famistudio_null.asm" 37 | 38 | .include "sfx.asm" 39 | 40 | ; ** SUBROUTINE: aud_run 41 | ; desc: Run a 1/60 tick of the audio engine. 42 | ; 43 | ; note: MUST run in an interrupt-context! 44 | aud_run: 45 | ; load the music bank 46 | lda #(mmc3bk_prg1 | def_mmc3_bn) 47 | sta mmc3_bsel 48 | lda musicbank 49 | sta mmc3_bdat 50 | 51 | jsr famistudio_update 52 | 53 | lda #(mmc3bk_prg1 | def_mmc3_bn) 54 | sta mmc3_bsel 55 | lda currA000bank 56 | sta mmc3_bdat 57 | 58 | ; Restore the old selector 59 | lda mmc3_shadow 60 | sta mmc3_bsel 61 | rts 62 | 63 | ; ** SUBROUTINE: aud_init 64 | ; desc: Initializes the audio engine. 65 | aud_init: 66 | lda #1 ; NTSC 67 | ldx #0 ; no music data yet 68 | ldy #0 69 | jmp famistudio_init 70 | 71 | ; ** SUBROUTINE: aud_play_music_by_index_near 72 | ; desc: Plays a selected track by index. Assumes music is loaded in the $A000 bank. 73 | aud_play_music_by_index_hack: 74 | lda temp11 75 | aud_play_music_by_index_near: 76 | jmp famistudio_music_play 77 | 78 | ; ** SUBROUTINE: aud_load_sfx 79 | ; desc: Loads the sound effect table. 80 | aud_load_sfx: 81 | ldx #game_sfx 83 | jmp famistudio_sfx_init 84 | 85 | ; ** SUBROUTINE: aud_reset 86 | ; desc: Removes all music from playback. 87 | aud_reset: 88 | ldx #music_data_blank 90 | lda #1 91 | jmp famistudio_init 92 | 93 | ; ** SUBROUTINE: aud_play_music_by_index 94 | ; desc: Plays a track by index. Uses a far jump to select the music bank first. 95 | aud_play_music_by_index: 96 | sta temp11 97 | ldx #aud_play_music_by_index_hack 99 | lda musicbank 100 | jmp far_call2 101 | 102 | .include "blank.asm" 103 | -------------------------------------------------------------------------------- /src/audio/blank.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp. 2 | 3 | ; This is music data that only contains one song that plays nothing. 4 | ; This file is for the FamiStudio Sound Engine and was generated by FamiStudio 5 | 6 | .if FAMISTUDIO_CFG_C_BINDINGS 7 | .export _music_data_blank=music_data_blank 8 | .endif 9 | 10 | music_data_blank: 11 | .byte 1 12 | .word @instruments 13 | .word @samples-4 14 | ; 00 : blank 15 | .word @song0ch0 16 | .word @song0ch1 17 | .word @song0ch2 18 | .word @song0ch3 19 | .word @song0ch4 20 | .word 307,256 21 | 22 | .export music_data_blank 23 | .global FAMISTUDIO_DPCM_PTR 24 | 25 | @instruments: 26 | 27 | @env0: 28 | .byte $00,$c0,$7f,$00,$02 29 | @env1: 30 | .byte $c0,$7f,$00,$01 31 | @env2: 32 | .byte $7f,$00,$00 33 | 34 | @samples: 35 | 36 | @song0ch0: 37 | .byte $46, $0a 38 | @song0ch0loop: 39 | .byte $9f, $42 40 | .word @song0ch0loop 41 | @song0ch1: 42 | @song0ch1loop: 43 | .byte $9f, $42 44 | .word @song0ch1loop 45 | @song0ch2: 46 | @song0ch2loop: 47 | .byte $9f, $42 48 | .word @song0ch2loop 49 | @song0ch3: 50 | @song0ch3loop: 51 | .byte $9f, $42 52 | .word @song0ch3loop 53 | @song0ch4: 54 | @song0ch4loop: 55 | .byte $9f, $42 56 | .word @song0ch4loop 57 | -------------------------------------------------------------------------------- /src/audio/famistudio_null.asm: -------------------------------------------------------------------------------- 1 | ; Periodically updated null placeholder for famistudio. 2 | ; Used to test how much space removing famistudio would save. 3 | FAMISTUDIO_SFX_CH0=0 4 | FAMISTUDIO_SFX_CH1=0 5 | famistudio_sfx_init: 6 | famistudio_sfx_play: 7 | famistudio_music_play: 8 | famistudio_init: 9 | famistudio_update: 10 | rts 11 | -------------------------------------------------------------------------------- /src/audio/sfx.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024-2025 iProgramInCpp 2 | 3 | game_sfx: 4 | .word @ntsc 5 | .word @ntsc 6 | @ntsc: 7 | .word @sfx_ntsc_sfx_dash ; 0 - dash 8 | .word @sfx_ntsc_collect_berry; 1 - strawberry collect 9 | .word @sfx_ntsc_click ; 2 - jump 10 | .word @sfx_ntsc_sfx_death ; 3 - death 11 | .word @sfx_ntsc_whoosh ; 4 - whooshing sound 12 | .word @sfx_ntsc_spring ; 5 - spring 13 | .word @sfx_ntsc_caw ; 6 - bird caw 14 | .word @sfx_ntsc_crumble ; 7 - crumble 15 | .word lsfx_ntsc_shatter ; 8 - glass shatter 16 | .word psfx_ntsc_ch1_in ; 9 - Chapter 1 in 17 | .word psfx_ntsc_ch1_out ;10 - Chapter 1 out 18 | .word psfx_ntsc_ch2_in ;11 - Chapter 2 in 19 | .word psfx_ntsc_ch2_out ;12 - Chapter 2 out 20 | 21 | ; TODO: BORROWED FROM FAMIDASH. Provide original version soon. 22 | @sfx_ntsc_click: 23 | .byte $8a,$0b,$89,$3f,$01,$89,$35,$00 24 | 25 | @sfx_ntsc_sfx_dash: ; From Buttersoap 26 | .byte $87,$9a,$88,$01,$86,$8f,$8a,$07,$89,$3a,$01,$87,$89,$8a,$06,$01 27 | .byte $87,$78,$8a,$05,$01,$87,$67,$8a,$04,$01,$87,$0c,$8a,$03,$89,$3e 28 | .byte $01,$87,$1b,$89,$3d,$01,$87,$2a,$89,$3c,$01,$87,$39,$01,$87,$48 29 | .byte $89,$3b,$01,$87,$57,$89,$3a,$01,$87,$66,$89,$39,$01,$87,$75,$01 30 | .byte $87,$84,$89,$38,$01,$87,$93,$89,$37,$01,$86,$80,$89,$36,$02,$89 31 | .byte $35,$01,$89,$34,$01,$89,$33,$02,$89,$32,$01,$89,$31,$01,$00 32 | 33 | @sfx_ntsc_sfx_death: ; From Buttersoap 34 | .byte $87,$86,$88,$00,$86,$8f,$8a,$00,$89,$3f,$02,$87,$93,$88,$01,$02 35 | .byte $84,$3b,$85,$00,$83,$7e,$87,$d5,$88,$00,$8a,$0a,$89,$3e,$01,$83 36 | .byte $70,$89,$3d,$01,$84,$46,$83,$7c,$87,$ef,$89,$3c,$01,$83,$70,$89 37 | .byte $3b,$01,$84,$54,$83,$7a,$87,$0c,$88,$01,$89,$3a,$01,$83,$70,$89 38 | .byte $39,$01,$84,$5e,$83,$78,$87,$2d,$89,$38,$01,$83,$70,$01,$84,$6a 39 | .byte $83,$77,$87,$52,$89,$37,$01,$83,$70,$89,$36,$01,$84,$77,$83,$75 40 | .byte $87,$7c,$89,$35,$01,$83,$70,$89,$34,$01,$84,$86,$83,$73,$87,$ab 41 | .byte $89,$33,$01,$83,$70,$89,$32,$01,$84,$8e,$83,$71,$87,$df,$89,$31 42 | .byte $01,$83,$70,$01,$84,$4f,$83,$74,$87,$2d,$89,$34,$01,$83,$70,$01 43 | .byte $84,$59,$83,$74,$87,$52,$01,$83,$70,$01,$84,$64,$83,$73,$87,$7c 44 | .byte $89,$33,$01,$83,$70,$01,$84,$6a,$83,$73,$87,$93,$01,$83,$70,$01 45 | .byte $84,$70,$83,$72,$87,$ab,$89,$32,$01,$83,$70,$01,$84,$7e,$83,$72 46 | .byte $87,$df,$01,$83,$70,$01,$84,$86,$83,$71,$87,$fb,$89,$31,$01,$83 47 | .byte $70,$01,$84,$8e,$83,$71,$87,$3a,$88,$02,$01,$83,$70,$01,$84,$96 48 | .byte $86,$80,$00 49 | 50 | @sfx_ntsc_spring: ; From iProgram -- Placeholder? 51 | .byte $81,$ff,$82,$07,$80,$bf,$8a,$08,$89,$3f,$01,$80,$be,$89,$3d,$01 52 | .byte $80,$bd,$89,$3b,$01,$80,$bc,$89,$3a,$01,$80,$bb,$89,$38,$01,$80 53 | .byte $ba,$89,$36,$01,$80,$b9,$89,$35,$01,$80,$b8,$89,$34,$01,$80,$b7 54 | .byte $89,$33,$01,$81,$f1,$80,$33,$89,$32,$01,$81,$f2,$80,$34,$89,$30 55 | .byte $01,$81,$f1,$80,$33,$01,$81,$f0,$80,$34,$01,$81,$f1,$80,$33,$01 56 | .byte $81,$f2,$01,$81,$f1,$80,$32,$01,$81,$f0,$80,$31,$01,$00 57 | 58 | @sfx_ntsc_caw: ; from iProgram - Placeholder? 59 | .byte $81,$4b,$82,$00,$80,$3f,$89,$f0,$01,$81,$3b,$80,$3e,$01,$81,$42 60 | .byte $01,$81,$3b,$80,$3d,$01,$81,$46,$80,$3c,$01,$81,$42,$80,$3b,$01 61 | .byte $81,$46,$01,$81,$42,$80,$3a,$01,$81,$46,$80,$39,$01,$81,$42,$80 62 | .byte $38,$01,$81,$46,$80,$37,$01,$80,$36,$02,$80,$35,$01,$80,$34,$01 63 | .byte $80,$33,$02,$80,$32,$01,$80,$31,$01,$00 64 | 65 | @sfx_ntsc_whoosh: ; from iProgram - Placeholder? 66 | .byte $8a,$05,$89,$32,$01,$89,$33,$01,$89,$35,$01,$89,$36,$01,$89,$3f 67 | .byte $01,$89,$3d,$01,$89,$3a,$01,$89,$38,$01,$89,$37,$01,$89,$35,$01 68 | .byte $89,$34,$01,$89,$33,$01,$89,$32,$01,$89,$31,$02,$00 69 | 70 | @sfx_ntsc_collect_berry: ; from iProgram - Placeholder? Probably not 71 | .byte $8a,$03,$01,$8a,$00,$01,$8a,$0d,$89,$31,$01,$8a,$0c,$01,$8a,$09 72 | .byte $01,$8a,$07,$01,$89,$32,$01,$8a,$06,$02,$89,$33,$03,$89,$34,$01 73 | .byte $89,$35,$01,$89,$36,$01,$89,$37,$01,$89,$39,$01,$89,$3c,$01,$89 74 | .byte $3f,$01,$89,$30,$01,$81,$5e,$82,$00,$80,$bb,$89,$3f,$01,$81,$59 75 | .byte $80,$bf,$8a,$07,$89,$39,$01,$81,$54,$80,$bb,$8a,$09,$89,$36,$01 76 | .byte $81,$4b,$80,$ba,$8a,$0b,$89,$33,$01,$81,$42,$80,$b8,$8a,$0e,$89 77 | .byte $31,$01,$81,$38,$80,$b7,$8a,$01,$01,$8a,$02,$01,$8a,$03,$01,$80 78 | .byte $b6,$03,$80,$b5,$02,$80,$b4,$05,$80,$b3,$02,$89,$f0,$02,$80,$b2 79 | .byte $06,$80,$b1,$07,$00 80 | 81 | @sfx_ntsc_crumble: 82 | .byte $87,$ad,$88,$06,$86,$8f,$8a,$8d,$89,$3a,$01,$8a,$0e,$01,$8a,$8e 83 | .byte $01,$8a,$0d,$01,$8a,$8e,$01,$8a,$0e,$00 84 | -------------------------------------------------------------------------------- /src/chr/b_cass1.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_cass1.chr -------------------------------------------------------------------------------- /src/chr/b_cass2.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_cass2.chr -------------------------------------------------------------------------------- /src/chr/b_ch1ca.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_ch1ca.chr -------------------------------------------------------------------------------- /src/chr/b_ch1cb.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_ch1cb.chr -------------------------------------------------------------------------------- /src/chr/b_ch2ca.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_ch2ca.chr -------------------------------------------------------------------------------- /src/chr/b_ch2cb.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_ch2cb.chr -------------------------------------------------------------------------------- /src/chr/b_lvl0.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl0.chr -------------------------------------------------------------------------------- /src/chr/b_lvl1.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl1.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2b.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2b.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2c.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2c.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2d.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2d.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2e.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2e.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2f.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2f.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2g.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2g.chr -------------------------------------------------------------------------------- /src/chr/b_lvl2h.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl2h.chr -------------------------------------------------------------------------------- /src/chr/b_lvl3.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl3.chr -------------------------------------------------------------------------------- /src/chr/b_lvl3bg.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_lvl3bg.chr -------------------------------------------------------------------------------- /src/chr/b_options.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_options.chr -------------------------------------------------------------------------------- /src/chr/b_overw.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_overw.chr -------------------------------------------------------------------------------- /src/chr/b_postcard.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_postcard.chr -------------------------------------------------------------------------------- /src/chr/b_title.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/b_title.chr -------------------------------------------------------------------------------- /src/chr/d_bade.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/d_bade.chr -------------------------------------------------------------------------------- /src/chr/d_count.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/d_count.chr -------------------------------------------------------------------------------- /src/chr/d_gran.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/d_gran.chr -------------------------------------------------------------------------------- /src/chr/d_made.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/d_made.chr -------------------------------------------------------------------------------- /src/chr/d_main.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/d_main.chr -------------------------------------------------------------------------------- /src/chr/d_mome.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/d_mome.chr -------------------------------------------------------------------------------- /src/chr/d_theo.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/d_theo.chr -------------------------------------------------------------------------------- /src/chr/sp_anim.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_anim.chr -------------------------------------------------------------------------------- /src/chr/sp_ch1c.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_ch1c.chr -------------------------------------------------------------------------------- /src/chr/sp_ch2c.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_ch2c.chr -------------------------------------------------------------------------------- /src/chr/sp_gener.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_gener.chr -------------------------------------------------------------------------------- /src/chr/sp_heart.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_heart.chr -------------------------------------------------------------------------------- /src/chr/sp_level0.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level0.chr -------------------------------------------------------------------------------- /src/chr/sp_level0b.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level0b.chr -------------------------------------------------------------------------------- /src/chr/sp_level1.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level1.chr -------------------------------------------------------------------------------- /src/chr/sp_level1b.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level1b.chr -------------------------------------------------------------------------------- /src/chr/sp_level1c.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level1c.chr -------------------------------------------------------------------------------- /src/chr/sp_level2.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2.chr -------------------------------------------------------------------------------- /src/chr/sp_level2b.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2b.chr -------------------------------------------------------------------------------- /src/chr/sp_level2c.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2c.chr -------------------------------------------------------------------------------- /src/chr/sp_level2cb.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2cb.chr -------------------------------------------------------------------------------- /src/chr/sp_level2d.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2d.chr -------------------------------------------------------------------------------- /src/chr/sp_level2e.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2e.chr -------------------------------------------------------------------------------- /src/chr/sp_level2f.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2f.chr -------------------------------------------------------------------------------- /src/chr/sp_level2g.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2g.chr -------------------------------------------------------------------------------- /src/chr/sp_level2h.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2h.chr -------------------------------------------------------------------------------- /src/chr/sp_level2i.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2i.chr -------------------------------------------------------------------------------- /src/chr/sp_level2j.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2j.chr -------------------------------------------------------------------------------- /src/chr/sp_level2k.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2k.chr -------------------------------------------------------------------------------- /src/chr/sp_level2lm.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2lm.chr -------------------------------------------------------------------------------- /src/chr/sp_level2n.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level2n.chr -------------------------------------------------------------------------------- /src/chr/sp_level3.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_level3.chr -------------------------------------------------------------------------------- /src/chr/sp_overw.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_overw.chr -------------------------------------------------------------------------------- /src/chr/sp_pause.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_pause.chr -------------------------------------------------------------------------------- /src/chr/sp_player.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_player.chr -------------------------------------------------------------------------------- /src/chr/sp_plrdie.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/chr/sp_plrdie.chr -------------------------------------------------------------------------------- /src/d_font.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/d_font.chr -------------------------------------------------------------------------------- /src/d_fontw.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | ; This file was auto-generated. 3 | 4 | ; Comment added after generation: 5 | ; This and d_fontv2.chr probably won't be used. They're attempted recreations 6 | ; of the pixel font used during Celeste's development (a lot of it can be seen 7 | ; in the January 2017 version shown in "Celeste Developer Commentary Livestream") 8 | ; 9 | ; I probably won't use this in favor of d_font.chr / d_fontw.asm, which are my 10 | ; homegrown versions. 11 | 12 | dlg_font_widths: 13 | 14 | .byte $35,$74,$77,$27,$33,$64,$63,$72 15 | .byte $55,$55,$55,$55,$55,$32,$77,$67 16 | .byte $67,$66,$66,$66,$66,$66,$66,$66 17 | .byte $66,$66,$66,$66,$66,$96,$99,$39 18 | .byte $57,$55,$55,$54,$25,$53,$62,$55 19 | .byte $55,$44,$54,$65,$55,$74,$77,$76 20 | -------------------------------------------------------------------------------- /src/d_nmi.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | ; This code belongs in the PRG_DIAL segment. 3 | 4 | .align $100 5 | ; ** SUBROUTINE: dlg_nmi_clear_256 6 | ; desc: Clears (almost) 256 bytes in an 8X30 column fashion. 7 | dlg_nmi_clear_256: 8 | lda ctl_flags 9 | ora #pctl_adv32 10 | sta ppu_ctrl 11 | 12 | ldy dlg_colnum 13 | ldx #$FF 14 | @beginning: 15 | lda clearpahi 16 | sta ppu_addr 17 | lda clearpalo 18 | sta ppu_addr 19 | cpy #1 20 | beq @writeLeftEdge 21 | bcc @writeNoEdge 22 | cpy #30 23 | beq @writeRightEdge 24 | bcs @writeNoEdge 25 | 26 | ; 30 writes. 27 | lda #0 28 | sta ppu_data 29 | stx ppu_data 30 | beq @write28x 31 | 32 | @wr28xReturn: 33 | lda clearpalo 34 | clc 35 | adc #1 36 | 37 | ; check if it's zero 38 | and #%00011111 39 | sta clearpalo 40 | bne :+ 41 | 42 | lda #0 43 | sta clearpalo 44 | 45 | ; it is, so change nametable 46 | lda clearpahi 47 | eor #$4 48 | sta clearpahi 49 | 50 | : iny 51 | tya 52 | and #7 53 | bne @beginning 54 | 55 | sty dlg_colnum 56 | lda ctl_flags 57 | sta ppu_ctrl 58 | 59 | rts 60 | 61 | @writeNoEdge: 62 | lda #0 63 | sta ppu_data 64 | sta ppu_data 65 | beq @write28x 66 | 67 | @writeLeftEdge: 68 | ldx #%11111000 69 | lda #%00001000 70 | bne @write30x 71 | sta ppu_data 72 | sta ppu_data 73 | 74 | @writeRightEdge: 75 | ldx #%00011111 76 | lda #%00010000 77 | 78 | @write30x: 79 | sta ppu_data 80 | stx ppu_data 81 | 82 | @write28x: 83 | sta ppu_data 84 | sta ppu_data 85 | sta ppu_data 86 | sta ppu_data 87 | sta ppu_data 88 | sta ppu_data 89 | sta ppu_data 90 | sta ppu_data 91 | sta ppu_data 92 | sta ppu_data 93 | sta ppu_data 94 | sta ppu_data 95 | sta ppu_data 96 | sta ppu_data 97 | sta ppu_data 98 | sta ppu_data 99 | sta ppu_data 100 | sta ppu_data 101 | sta ppu_data 102 | sta ppu_data 103 | sta ppu_data 104 | sta ppu_data 105 | sta ppu_data 106 | sta ppu_data 107 | sta ppu_data 108 | sta ppu_data 109 | sta ppu_data 110 | sta ppu_data 111 | ldx #$FF 112 | jmp @wr28xReturn 113 | 114 | ; ** SUBROUTINE: dlg_nmi_check_upds 115 | ; desc: Checks for updates for the dialog columns. 116 | dlg_nmi_check_upds: 117 | lda ctl_flags 118 | ora #pctl_adv32 119 | sta ppu_ctrl 120 | 121 | ; temp5 is going to be the same because we increment by 256 122 | lda #dlg_bitmap 133 | sta temp6 134 | lda #0 135 | sta temp7 136 | lda #dlg_upds1 139 | sta temp9 140 | 141 | jmp @updateRow 142 | 143 | : lda #2 144 | bit dlg_updates 145 | beq :+ 146 | 147 | ; clear the bit that got us here 148 | eor dlg_updates 149 | sta dlg_updates 150 | lda #>(dlg_bitmap+$100) 151 | sta temp6 152 | lda #1 153 | sta temp7 154 | lda #dlg_upds2 157 | sta temp9 158 | 159 | jmp @updateRow 160 | 161 | : lda #4 162 | bit dlg_updates 163 | beq :+ 164 | 165 | ; clear the bit that got us here 166 | eor dlg_updates 167 | sta dlg_updates 168 | lda #>(dlg_bitmap+$200) 169 | sta temp6 170 | lda #2 171 | sta temp7 172 | lda #dlg_upds3 175 | sta temp9 176 | 177 | jmp @updateRow 178 | 179 | : lda ctl_flags 180 | sta ppu_ctrl 181 | rts 182 | 183 | ; ** SUBROUTINE: dlg_nmi_check_upds::@updateRow 184 | ; desc: Updates a single row of text. 185 | ; arguments: 186 | ; temp1 - Low byte of starting ppuaddr 187 | ; temp2 - High byte of starting ppuaddr 188 | ; temp5 - Low byte of row bitmap start addr 189 | ; temp6 - High byte of row bitmap start addr 190 | ; temp7 - Row number 191 | ; temp8 - Low byte of updates array 192 | ; temp9 - High byte of updates array 193 | ; reserves also: 194 | ; temp3 195 | ; temp4 196 | ; temp10 197 | @updateRow: 198 | ldx temp7 199 | lda dlg_updc1, x 200 | sta dlg_updccurr 201 | ; acknowledge these updates 202 | lda #0 203 | sta dlg_updc1, x 204 | 205 | ; add $A0 206 | lda temp2 207 | ora #$A0 208 | sta temp2 209 | 210 | lda temp7 211 | clc 212 | adc temp1 213 | sta temp1 214 | 215 | lda temp7 216 | asl 217 | asl 218 | asl 219 | asl 220 | asl 221 | sta temp10 ; 0,32,64 222 | 223 | ;lda temp1 224 | ;pha 225 | ;lda temp2 226 | ;pha 227 | 228 | ; ok, now each column 229 | ; TODO: only copy a few columns at a time. 230 | ldy #0 231 | @loopRow: 232 | ; store a backup of the update index in temp4 233 | sty temp4 234 | 235 | ; load the column to be updated 236 | lda (temp8), y 237 | 238 | ; use temp3 as the index into dlg_bitmap 239 | sta temp3 240 | 241 | ; add either 0, 32, or 64. this'll get the index into dlg_updpaddr* 242 | clc 243 | adc temp10 244 | 245 | ; use the thing we calculated earlier as an index 246 | tay 247 | 248 | ; load the next ppuaddr 249 | lda dlg_updpaddrhi, y 250 | sta ppu_addr 251 | lda dlg_updpaddrlo, y 252 | sta ppu_addr 253 | 254 | ; subloop to copy 8 bytes 255 | ldx #0 256 | @subLoopRow: 257 | ; load the read head 258 | ldy temp3 259 | ; load and write that data to the PPU 260 | lda (temp5), y 261 | sta ppu_data 262 | ; increment the read head 263 | lda temp3 264 | clc 265 | adc #32 266 | sta temp3 267 | ; next row 268 | inx 269 | cpx #8 270 | bne @subLoopRow 271 | 272 | ldy temp4 273 | 274 | ; continue 275 | @loopRow_continue: 276 | iny 277 | cpy dlg_updccurr 278 | bne @loopRow 279 | 280 | lda ctl_flags 281 | sta ppu_ctrl 282 | rts 283 | -------------------------------------------------------------------------------- /src/dialogif.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; Dialog interface 4 | ; This allows to call into dialog functions by dynamically switching the loaded bank to the dialog's. 5 | ; 6 | ; The dialog must not reside at the address where DPCM samples reside. 7 | 8 | dlg_update_g: 9 | lda #dlg_update_d 12 | sta farcalladdr+1 13 | ldy #prgb_dial 14 | jmp far_call 15 | 16 | ; ** SUBROUTINE: dlg_begin_cutscene_g 17 | ; desc: Initiates a cutscene. 18 | ; parameters: 19 | ; A - The index of the entity the player is engaging with. 20 | ; X - The low byte of the address of the cutscene data to load. 21 | ; Y - The high byte of the address of the cutscene data to load. 22 | dlg_begin_cutscene_g: 23 | sta dlg_entity 24 | stx dlg_cutsptr 25 | sty dlg_cutsptr+1 26 | 27 | ; NOTE: dlg_run_cutscene_g is the exact same as dlg_begin_cutscene_g right now! 28 | ; This is because dlg_begin_cutscene_d and dlg_run_cutscene are the same as well. 29 | dlg_run_cutscene_g: 30 | lda #dlg_begin_cutscene_d 33 | sta farcalladdr+1 34 | ldy #prgb_dial 35 | jmp far_call 36 | 37 | dlg_end_dialog_g: 38 | lda #dlg_end_dialog 41 | sta farcalladdr+1 42 | ldy #prgb_dial 43 | jmp far_call 44 | -------------------------------------------------------------------------------- /src/e_draw.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_draw_common 4 | ; desc: draws a common 2X sprite. 5 | ; parameters: 6 | ; temp5 - attributes for left side 7 | ; temp8 - attributes for right side 8 | ; temp6 - tile # for left side 9 | ; temp7 - tile # for right side 10 | gm_draw_common: 11 | lda temp3 12 | sta y_crd_temp 13 | 14 | ; draw the left sprite 15 | lda temp2 16 | cmp #$F8 17 | bcc :+ 18 | ; sprite X is bigger than $F8, because either the sprite is to the 19 | ; left of the screen (so fraudulently got there via overflow), or 20 | ; legitimately to the right 21 | lda temp4 22 | bmi @skipLeftSprite ; X high coord < $00, don't draw that part 23 | lda temp2 24 | 25 | : sta x_crd_temp 26 | 27 | lda temp5 28 | ldy temp6 29 | jsr oam_putsprite 30 | 31 | @skipLeftSprite: 32 | ; draw the right sprite 33 | lda temp4 34 | bmi @temp4neg 35 | lda temp2 36 | clc 37 | adc #8 38 | bcs :+ ; if it overflew while computing the coord, 39 | @temp4negd: 40 | sta x_crd_temp ; then it need not render 41 | 42 | lda temp8 43 | ldy temp7 44 | jsr oam_putsprite 45 | 46 | : rts 47 | 48 | @temp4neg: 49 | lda temp2 50 | clc 51 | adc #8 52 | bcs @temp4negd 53 | bcc @temp4negd 54 | 55 | ; ** SUBROUTINE: gm_draw_common2 56 | ; desc: draws a common 2X sprite. Ensures that there is no wraparound. 57 | .proc gm_draw_common2 58 | 59 | lda temp4 60 | bmi @temp4Negative 61 | bne @temp4PositiveNonZero 62 | 63 | ; temp4 is zero, so can draw 64 | @doDraw: 65 | jmp gm_draw_common 66 | 67 | @temp4PositiveNonZero: 68 | @temp4NegativeTemp2Negative: 69 | ; if temp4 > 0, then clearly off screen 70 | rts 71 | 72 | @temp4Negative: 73 | ; it could still be on screen if temp2 >= $F8 (so, the RHS would end up back 74 | ; in screen bounds) 75 | lda temp2 76 | cmp #$F8 77 | bcc @temp4NegativeTemp2Negative 78 | bcs @doDraw 79 | 80 | .endproc 81 | 82 | ; ** SUBROUTINE: gm_unload_cassette_manager 83 | ; desc: Unloads a cassette block manager entity. 84 | ; parameters: 85 | ; X - The entity to unload. 86 | .proc gm_unload_cassette_manager 87 | lda #0 88 | sta cassrhythm 89 | lda sprspace+sp_cbmg_ospbk, x 90 | sta spr1_bknum 91 | lda sprspace+sp_cbmg_obg0b, x 92 | sta bg0_bknum 93 | lda sprspace+sp_cbmg_obg1b, x 94 | sta bg1_bknum 95 | rts 96 | .endproc 97 | 98 | ; ** SUBROUTINE: gm_unload_os_ents 99 | ; desc: Unloads entities that went off the left side of the screen. 100 | gm_unload_os_ents: 101 | ldx #sgm_unload_os_ents 103 | lda #prgb_ents 104 | jmp far_call2 105 | 106 | ; ** SUBROUTINE: gm_draw_entities 107 | ; desc: Draws visible entities to the screen. 108 | gm_draw_entities: 109 | ldx #xt_draw_entities 111 | lda #prgb_ents 112 | jmp far_call2 113 | 114 | -------------------------------------------------------------------------------- /src/e_spawn.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_spawn_particle 4 | ; desc: Spawns a particle. 5 | ; parameters: 6 | ; temp1 - X position 7 | ; temp2 - Y position 8 | ; temp3 - X high position in pages 9 | ; temp4 - character tile 10 | ; temp5 - attributes (when palette alloc added, type of an associated entity`) 11 | ; temp6 - direction (0-UL, 1-UR, 2-DL, 3-DR, 4-None) 12 | ; temp8 - gravity 13 | ; temp9 - time alive 14 | .proc gm_spawn_particle 15 | ldy #0 16 | : lda sprspace+sp_kind, y 17 | beq slotFound 18 | iny 19 | cpy #sp_max 20 | bne :- 21 | rts ; no more space :( 22 | 23 | slotFound: 24 | ; from here until startConvergence, gm_spawn_particle does its own thing 25 | lda temp1 26 | sta sprspace+sp_x, y 27 | lda temp2 28 | sta sprspace+sp_y, y 29 | lda temp3 30 | sta sprspace+sp_x_pg, y 31 | 32 | startConvergence: 33 | lda #e_particle 34 | sta sprspace+sp_kind, y 35 | 36 | lda roomnumber 37 | and #1 38 | asl 39 | sta sprspace+sp_flags, y 40 | 41 | lda #0 42 | sta sprspace+sp_wid, y 43 | sta sprspace+sp_hei, y 44 | sta sprspace+sp_vel_x_lo, y 45 | sta sprspace+sp_vel_y_lo, y 46 | sta sprspace+sp_x_lo, y 47 | sta sprspace+sp_y_lo, y 48 | 49 | ldx temp6 50 | lda partdirx, x 51 | sta sprspace+sp_part_vel_x, y 52 | lda partdiry, x 53 | sta sprspace+sp_part_vel_y, y 54 | 55 | lda temp9 56 | sta sprspace+sp_part_timer, y 57 | lda temp8 58 | sta sprspace+sp_part_gravi, y 59 | lda temp4 60 | sta sprspace+sp_part_chrti, y 61 | lda temp5 62 | sta sprspace+sp_part_chrat, y 63 | rts 64 | .endproc 65 | 66 | ; ** SUBROUTINE: gm_spawn_particle_at_ent 67 | ; desc: Spawns a particle at an entity's position. 68 | ; parameters: 69 | ; temp1 - old entity index 70 | ; temp4 - character tile 71 | ; temp5 - attributes of that tile (when palette alloc added, the old entity type) 72 | ; temp8 - gravity 73 | ; temp9 - time alive 74 | ; reg X - direction (0-UL, 1-UR, 2-DL, 3-DR, 4-None) 75 | ; note: the value of X is preserved. 76 | ; note: the value of temp6 is clobbered 77 | .proc gm_spawn_particle_at_ent 78 | stx temp6 79 | ldy #0 80 | : lda sprspace+sp_kind, y 81 | beq @slotFound 82 | iny 83 | cpy #sp_max 84 | bne :- 85 | 86 | ; no more space :( 87 | rts 88 | 89 | @slotFound: 90 | 91 | ldx temp1 92 | lda sprspace+sp_kind, x 93 | sta sprspace+sp_part_entty, y 94 | 95 | lda sprspace+sp_x, x 96 | clc 97 | adc #4 98 | sta sprspace+sp_x, y 99 | 100 | lda sprspace+sp_x_pg, x 101 | adc #0 102 | sta sprspace+sp_x_pg, y 103 | 104 | lda sprspace+sp_y, x 105 | clc 106 | adc #4 107 | sta sprspace+sp_y, y 108 | 109 | jmp gm_spawn_particle::startConvergence 110 | .endproc 111 | 112 | partdirx: .byte $FF,$01,$FF,$01,$00 113 | partdiry: .byte $FF,$FF,$01,$01,$00 114 | 115 | ; ** SUBROUTINE: gm_give_points_ent 116 | ; desc: Gives points to a player, setting the points' coordinates to an entity's. 117 | ; parameters: X - the ID of the entity 118 | gm_give_points_ent: 119 | lda sprspace+sp_x, x 120 | sta temp1 121 | lda sprspace+sp_x_pg, x 122 | sta temp2 123 | lda sprspace+sp_y, x 124 | sta temp3 125 | 126 | jmp gm_give_points2 127 | 128 | ; ** SUBROUTINE: gm_give_points 129 | ; desc: Gives points to a player. Note: these aren't actually tracked anywhere >:) 130 | ; 131 | ; Handles the bonus streak mechanic. 132 | gm_give_points: 133 | lda player_x 134 | clc 135 | adc camera_x 136 | sta temp1 137 | lda camera_x_pg 138 | adc #0 139 | sta temp2 140 | lda player_y 141 | sta temp3 142 | 143 | gm_give_points2: 144 | inc ptscount 145 | ldx ptscount 146 | cpx #7 ; values between 1 and 6 are valid. 147 | bne :+ 148 | ldx #6 149 | stx ptscount 150 | : lda #120 151 | sta ptstimer 152 | 153 | ; fallthrough 154 | 155 | ; ** SUBROUTINE: gm_spawn_points 156 | ; desc: Spawns a floating points sprite at the player's position. 157 | ; arguments: 158 | ; reg X: amount of points ((X+1)*1000, or 1UP) 159 | gm_spawn_points: 160 | ldy #0 161 | : lda sprspace+sp_kind, y 162 | beq :+ 163 | iny 164 | cpy #sp_max 165 | bne :- 166 | 167 | ; no more space :( 168 | rts 169 | 170 | : ; slot found! 171 | lda #e_points 172 | sta sprspace+sp_kind, y 173 | 174 | lda roomnumber 175 | and #1 176 | asl 177 | sta sprspace+sp_flags, y 178 | 179 | lda temp1 180 | sta sprspace+sp_x, y 181 | 182 | lda temp2 183 | sta sprspace+sp_x_pg, y 184 | 185 | lda temp3 186 | sta sprspace+sp_y, y 187 | 188 | lda #60 189 | sta sprspace+sp_points_timer, y 190 | 191 | txa 192 | cmp #6 193 | bcc :+ 194 | lda #6 195 | : sta sprspace+sp_points_count, y 196 | 197 | rts 198 | -------------------------------------------------------------------------------- /src/e_update.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; Parameters: 4 | ; temp1 - Entity Index (passed in through X too) 5 | ; temp2 - X Screen Position 6 | ; temp3 - Y Screen Position 7 | ; temp4 - X High Position 8 | 9 | ; ** SUBROUTINE: gm_check_player_bb 10 | ; desc: Checks if the player is located within this entity's bounding box. 11 | gm_check_player_bb: 12 | lda #0 13 | sta temp7 14 | sta temp8 15 | lda #16 16 | sta temp9 17 | sta temp10 18 | txa 19 | tay 20 | jmp gm_check_collision_ent 21 | 22 | ; ** SUBROUTINE: gm_ent_oscillate 23 | ; desc: Oscillates this entity using the first entity specific field as a timer. 24 | gm_ent_oscillate: 25 | ldx temp1 26 | lda sprspace+sp_oscill_timer, x 27 | clc 28 | adc #1 29 | sta sprspace+sp_oscill_timer, x 30 | 31 | sta temp5 32 | and #7 33 | bne @return 34 | 35 | lda temp5 36 | lsr 37 | lsr 38 | lsr 39 | and #15 40 | tax 41 | lda osciltable, x 42 | sta temp5 43 | ldx temp1 44 | 45 | lda temp5 46 | bmi @temp5Negative 47 | 48 | clc 49 | adc sprspace+sp_y, x 50 | sta sprspace+sp_y, x 51 | bcs @overflow 52 | @return: 53 | rts 54 | 55 | @temp5Negative: 56 | clc 57 | adc sprspace+sp_y, x 58 | sta sprspace+sp_y, x 59 | bcc @overflow 60 | rts 61 | 62 | @overflow: 63 | lda #g3_transitA 64 | bit gamectrl3 65 | bne @continue ; in transition, so can't be in limbo 66 | 67 | lda #rf_new 68 | bit roomflags 69 | beq @continue ; can't go in limbo in a normal room 70 | 71 | lda sprspace+sp_flags,x 72 | eor #ef_limbo 73 | sta sprspace+sp_flags,x 74 | 75 | @continue: 76 | rts 77 | 78 | ; ** SUBROUTINE: gm_collect_berry 79 | ; desc: Collects a strawberry. 80 | ; parameters: X - The entity ID of the strawberry. 81 | ; clobbers: A, X, Y 82 | .proc gm_collect_berry 83 | lda sprspace+sp_strawb_ident, x 84 | tay ; keep the ID into Y 85 | lsr ; byte number into X 86 | lsr 87 | lsr 88 | tax 89 | tya ; restore the Index 90 | and #7 ; get the bit number 91 | tay 92 | lda bitmask, y ; 1 single bit set based on Y 93 | ora strawberries, x 94 | sta strawberries, x 95 | lda #0 96 | rts 97 | bitmask: .byte $01, $02, $04, $08, $10, $20, $40, $80 98 | .endproc 99 | 100 | ; ** SUBROUTINE: gm_remove_follower 101 | ; desc: Removes a follower from the player's followers. 102 | ; parameters: X - The index of the entity to remove as follower. 103 | ; clobbers: all regs 104 | .proc gm_remove_follower 105 | ; load the following ID, to compare with the rest of the entities 106 | lda sprspace+sp_strawb_colid, x 107 | 108 | ldx #0 109 | loop: 110 | ldy sprspace+sp_kind, x 111 | cpy #e_strawb 112 | bne continue 113 | 114 | ; compare following IDs 115 | cmp sprspace+sp_strawb_colid, x 116 | bcs continue 117 | 118 | lda sprspace+sp_strawb_colid, x 119 | sec 120 | sbc #8 121 | sta sprspace+sp_strawb_colid, x 122 | 123 | continue: 124 | inx 125 | cpx #sp_max 126 | bne loop 127 | 128 | lda #$F0 129 | sta groundtimer 130 | 131 | dec plrstrawbs 132 | rts 133 | .endproc 134 | 135 | ; ** SUBROUTINE: gm_pick_up_berry_entity 136 | ; desc: Picks up a berry entity. 137 | ; parameters: X - The index of the entity to pick up. 138 | .proc gm_pick_up_berry_entity 139 | lda temp11 140 | pha 141 | stx temp11 142 | ;lda sprspace+sp_strawb_flags, x 143 | ;ora #esb_shrink 144 | ;and #<~esb_picked 145 | ;sta sprspace+sp_strawb_flags, x 146 | 147 | ; since esb_picked == 1 and esb_shrink == 2 148 | inc sprspace+sp_strawb_flags, x 149 | 150 | lda #0 151 | sta sprspace+sp_strawb_timer, x 152 | 153 | jsr gm_remove_follower 154 | jsr gm_strawb_sfx 155 | 156 | ldx temp11 157 | jsr gm_collect_berry 158 | 159 | ldx temp11 160 | pla 161 | sta temp11 162 | rts 163 | .endproc 164 | -------------------------------------------------------------------------------- /src/extra/chcomp.asm: -------------------------------------------------------------------------------- 1 | ; This file is for the FamiStudio Sound Engine and was generated by FamiStudio 2 | ; Project uses FamiTracker tempo, you must set FAMISTUDIO_USE_FAMITRACKER_TEMPO = 1. 3 | ; Project uses release notes, you must set FAMISTUDIO_USE_RELEASE_NOTES = 1. 4 | ; Volume track is used, you must set FAMISTUDIO_USE_VOLUME_TRACK = 1. 5 | ; Volume slides are used, you must set FAMISTUDIO_USE_VOLUME_SLIDES = 1. 6 | ; DPCM Delta Counter effect is used, you must set FAMISTUDIO_USE_DELTA_COUNTER = 1. 7 | 8 | .if FAMISTUDIO_CFG_C_BINDINGS 9 | .export _music_data_chapter_complete=music_data_chapter_complete 10 | .endif 11 | 12 | music_data_chapter_complete: 13 | .byte 1 14 | .word @instruments 15 | .word @samples-4 16 | ; 00 : chapter_complete 17 | .word @song0ch0 18 | .word @song0ch1 19 | .word @song0ch2 20 | .word @song0ch3 21 | .word @song0ch4 22 | .word 307,256 23 | 24 | .export music_data_chapter_complete 25 | .global FAMISTUDIO_DPCM_PTR 26 | 27 | @instruments: 28 | .word @env2,@env3,@env1,@env0 ; 00 : piano 29 | 30 | @env0: 31 | .byte $00,$c0,$7f,$00,$02 32 | @env1: 33 | .byte $c2,$c1,$00,$01 34 | @env2: 35 | .byte $05,$cb,$cc,$00,$02,$ca,$c8,$c7,$c5,$c4,$c3,$c3,$c2,$c2,$c1,$c0,$00,$0f 36 | @env3: 37 | .byte $c0,$7f,$00,$01 38 | @env4: 39 | .byte $7f,$00,$00 40 | 41 | @samples: 42 | 43 | @song0ch0: 44 | .byte $51, $ff, $e0, $80, $16, $8d, $7f, $51, $ff, $e0, $1d, $8d, $7f, $51, $ff, $e0, $22, $8d, $7f, $51, $ff, $e0, $29, $8d 45 | .byte $7f, $51, $ff, $e0, $2e, $89, $45, $81, $7f, $51, $fe, $e0, $11, $81, $7f, $51, $ff, $e0, $15, $81, $7f, $51, $ff, $e0 46 | .byte $1f, $95, $7f, $51, $fe, $e0, $0c, $81, $7f, $51, $ff, $e0, $16, $81, $7f, $51, $ff, $e0, $21, $95, $7f, $51, $fd, $e0 47 | .byte $0a, $81, $7f, $51, $ff, $e0, $18, $81, $7f, $1d, $85, $51, $fc, $00, $8f, $81 48 | @song0ch0loop: 49 | .byte $00, $fd, $42 50 | .word @song0ch0loop 51 | @song0ch1: 52 | .byte $87, $51, $ff, $e0, $80, $1b, $8d, $7f, $51, $ff, $e0, $21, $8d, $7f, $51, $ff, $e0, $27, $8d, $7f, $51, $ff, $e0, $2d 53 | .byte $8d, $7f, $51, $ff, $e0, $33, $81, $45, $81, $81, $7f, $51, $ff, $e0, $13, $81, $7f, $51, $ff, $e0, $16, $99, $7f, $51 54 | .byte $ff, $e0, $13, $81, $7f, $51, $ff, $e0, $1b, $99, $7f, $51, $ff, $e0, $11, $81, $7f, $1a, $87, $51, $fc, $00, $91 55 | @song0ch1loop: 56 | .byte $70, $00, $fd, $42 57 | .word @song0ch1loop 58 | @song0ch2: 59 | .byte $51, $ff, $e0, $80, $22, $85, $7f, $51, $ff, $e0, $27, $85, $7f, $51, $ff, $e0, $29, $85, $7f, $51, $ff, $e0, $2d, $85 60 | .byte $7f, $51, $ff, $e0, $2e, $85, $7f, $51, $ff, $e0, $33, $85, $7f, $51, $ff, $e0, $35, $85, $7f, $51, $ff, $e0, $39, $85 61 | .byte $7f, $51, $ff, $e0, $3a, $85, $7f, $51, $ff, $e0, $3f, $81, $45, $81, $89, $7f, $51, $ff, $e0, $3a, $9d, $7f, $51, $ff 62 | .byte $e0, $3a, $83, $7f, $51, $ff, $e0, $35, $85, $7f, $51, $ff, $e0, $3c, $85, $45, $87, $7f, $51, $fe, $00, $3e, $87, $45 63 | .byte $8b 64 | @song0ch2loop: 65 | .byte $70, $00, $fd, $42 66 | .word @song0ch2loop 67 | @song0ch3: 68 | .byte $46, $08, $46, $08, $8f, $46, $06, $a7, $46, $05, $97, $46, $04, $89, $46, $0d, $95, $46, $04, $89, $46, $0f, $95, $46 69 | .byte $03, $89, $46, $0f, $97 70 | @song0ch3loop: 71 | .byte $ff, $42 72 | .word @song0ch3loop 73 | @song0ch4: 74 | .byte $52, $d0, $cf, $52, $d0, $e1 75 | @song0ch4loop: 76 | .byte $ff, $42 77 | .word @song0ch4loop 78 | -------------------------------------------------------------------------------- /src/extra/lettergfx.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; This file defines the graphics for each letter. 4 | ; These use the NEXXT RLE format. 5 | 6 | postcard_ch1: 7 | .byte $50,$00,$50,$a1,$b6,$b7,$50,$14,$b0,$b1,$b2,$b3,$b4,$b8,$00,$50 8 | .byte $03,$c6,$c7,$e6,$e7,$e8,$e9,$ea,$87,$50,$0e,$c0,$c1,$c2,$c3,$c4 9 | .byte $c5,$00,$50,$03,$c6,$87,$f6,$50,$04,$f7,$f8,$87,$50,$0c,$d0,$d1 10 | .byte $d2,$d3,$d4,$d5,$00,$50,$03,$c6,$f6,$50,$04,$f7,$f6,$f8,$87,$50 11 | .byte $0c,$e0,$e1,$e2,$e3,$e4,$e5,$00,$50,$03,$c6,$87,$50,$15,$f1,$f2 12 | .byte $f3,$f4,$f5,$00,$50,$03,$c6,$87,$50,$19,$c8,$00,$50,$03,$c6,$87 13 | .byte $50,$19,$c8,$00,$50,$03,$c6,$87,$86,$01,$02,$03,$04,$05,$06,$07 14 | .byte $08,$09,$0a,$0b,$0c,$0d,$0e,$0f,$10,$11,$12,$13,$14,$15,$16,$17 15 | .byte $87,$c8,$00,$50,$03,$c6,$87,$50,$19,$c8,$00,$50,$03,$c6,$18,$19 16 | .byte $1a,$1b,$1c,$1d,$1e,$1f,$20,$21,$22,$23,$24,$25,$26,$27,$28,$87 17 | .byte $29,$2a,$2b,$2c,$2d,$2e,$2f,$87,$c8,$00,$50,$03,$c6,$87,$50,$19 18 | .byte $c8,$00,$50,$03,$c6,$87,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39 19 | .byte $3a,$3b,$3c,$3d,$3e,$3f,$40,$41,$42,$43,$44,$45,$46,$47,$87,$c8 20 | .byte $00,$50,$03,$c6,$87,$50,$19,$c8,$00,$50,$03,$c6,$87,$50,$08,$48 21 | .byte $49,$4a,$4b,$4c,$4d,$4e,$4f,$87,$50,$08,$c8,$00,$50,$03,$c6,$87 22 | .byte $50,$19,$c8,$00,$50,$03,$c6,$87,$50,$19,$c8,$00,$50,$03,$c6,$87 23 | .byte $50,$19,$c8,$00,$50,$03,$c6,$f9,$fa,$fb,$fc,$87,$50,$14,$eb,$c8 24 | .byte $00,$50,$03,$d6,$d7,$50,$19,$d8,$00,$50,$c1,$50,$00 25 | 26 | postcard_ch2: 27 | .byte $01,$00,$01,$a1,$b6,$b7,$01,$14,$b0,$b1,$b2,$b3,$b4,$b8,$00,$01 28 | .byte $03,$c6,$c7,$e6,$e7,$e8,$e9,$ea,$87,$01,$0e,$c0,$c1,$c2,$c3,$c4 29 | .byte $c5,$00,$01,$03,$c6,$87,$f6,$01,$04,$f7,$f8,$87,$01,$0c,$d0,$d1 30 | .byte $d2,$d3,$d4,$d5,$00,$01,$03,$c6,$f6,$01,$04,$f7,$f6,$f8,$87,$01 31 | .byte $0c,$e0,$e1,$e2,$e3,$e4,$e5,$00,$01,$03,$c6,$87,$01,$15,$f1,$f2 32 | .byte $f3,$f4,$f5,$00,$01,$03,$c6,$87,$01,$19,$c8,$00,$01,$03,$c6,$87 33 | .byte $01,$19,$c8,$00,$01,$03,$c6,$87,$01,$19,$c8,$00,$01,$03,$c6,$87 34 | .byte $01,$02,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$5b,$5c,$5d 35 | .byte $5e,$5f,$87,$61,$62,$63,$64,$87,$87,$c8,$00,$01,$03,$c6,$87,$01 36 | .byte $19,$c8,$00,$01,$03,$c6,$87,$01,$02,$65,$66,$67,$68,$69,$6a,$6b 37 | .byte $6c,$6d,$6e,$6f,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$87,$87 38 | .byte $c8,$00,$01,$03,$c6,$87,$01,$19,$c8,$00,$01,$03,$c6,$87,$01,$06 39 | .byte $7a,$7b,$7c,$7d,$7e,$7f,$80,$81,$82,$83,$84,$85,$87,$01,$06,$c8 40 | .byte $00,$01,$03,$c6,$87,$01,$19,$c8,$00,$01,$03,$c6,$87,$01,$19,$c8 41 | .byte $00,$01,$03,$c6,$87,$01,$19,$c8,$00,$01,$03,$c6,$87,$01,$19,$c8 42 | .byte $00,$01,$03,$c6,$f9,$fa,$fb,$fc,$87,$01,$14,$eb,$c8,$00,$01,$03 43 | .byte $d6,$d7,$01,$19,$d8,$00,$01,$c1,$01,$00 -------------------------------------------------------------------------------- /src/extra/lettersfx.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; TODO: Also play the whoosh sound effects alongside the piano solo. 4 | 5 | psfx_ntsc_ch1_in: 6 | .byte $81,$54,$82,$00,$80,$bf,$89,$f0,$01,$80,$78,$01,$80,$7a,$01,$80 7 | .byte $bc,$01,$80,$bd,$01,$80,$be,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb 8 | .byte $01,$80,$ba,$01,$80,$b9,$01,$80,$b8,$01,$80,$b7,$01,$80,$b6,$01 9 | .byte $80,$b5,$01,$80,$b4,$84,$55,$85,$00,$83,$b2,$01,$80,$b3,$01,$80 10 | .byte $b2,$01,$80,$b1,$01,$80,$b0,$0b,$83,$b1,$0a,$80,$bf,$01,$80,$78 11 | .byte $01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be,$83,$b0,$01,$80 12 | .byte $bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81,$70,$80,$bf,$01 13 | .byte $80,$78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be,$83,$b2 14 | .byte $01,$80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81,$4b,$80 15 | .byte $bf,$01,$80,$78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be 16 | .byte $84,$71,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81 17 | .byte $42,$80,$bf,$01,$80,$78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01 18 | .byte $80,$be,$84,$4c,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba 19 | .byte $01,$80,$b9,$01,$80,$b8,$01,$80,$b7,$01,$80,$b6,$01,$80,$b5,$01 20 | .byte $80,$b4,$84,$43,$01,$80,$b3,$01,$80,$b2,$01,$80,$b1,$01,$80,$b0 21 | .byte $0b,$83,$b1,$18,$00 22 | psfx_ntsc_ch1_out: 23 | .byte $81,$42,$82,$00,$80,$bf,$89,$f0,$01,$80,$78,$01,$80,$7a,$01,$80 24 | .byte $bc,$01,$80,$bd,$01,$80,$be,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb 25 | .byte $01,$80,$ba,$01,$81,$3f,$80,$bf,$01,$80,$78,$01,$80,$7a,$01,$80 26 | .byte $bc,$01,$80,$bd,$01,$80,$be,$84,$43,$85,$00,$83,$b2,$01,$80,$bd 27 | .byte $01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81,$38,$80,$bf,$01,$80 28 | .byte $78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be,$84,$40,$01 29 | .byte $80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$80,$b9,$01,$80 30 | .byte $b8,$01,$80,$b7,$01,$80,$b6,$01,$80,$b5,$01,$80,$b4,$84,$39,$01 31 | .byte $80,$b3,$01,$80,$b2,$01,$80,$b1,$01,$80,$b0,$0b,$83,$b1,$18,$00 32 | psfx_ntsc_ch2_in: 33 | .byte $81,$3f,$82,$00,$80,$bf,$89,$f0,$01,$80,$78,$01,$80,$7a,$01,$80 34 | .byte $bc,$01,$80,$bd,$01,$80,$be,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb 35 | .byte $01,$80,$ba,$01,$80,$b9,$01,$80,$b8,$01,$80,$b7,$01,$80,$b6,$01 36 | .byte $80,$b5,$01,$80,$b4,$84,$40,$85,$00,$83,$b2,$01,$80,$b3,$01,$80 37 | .byte $b2,$01,$80,$b1,$01,$80,$b0,$0b,$83,$b1,$0a,$80,$bf,$01,$80,$78 38 | .byte $01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be,$83,$b0,$01,$80 39 | .byte $bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81,$54,$80,$bf,$01 40 | .byte $80,$78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be,$83,$b2 41 | .byte $01,$80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81,$38,$80 42 | .byte $bf,$01,$80,$78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be 43 | .byte $84,$55,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81 44 | .byte $34,$80,$bf,$01,$80,$78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01 45 | .byte $80,$be,$84,$39,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba 46 | .byte $01,$80,$b9,$01,$80,$b8,$01,$80,$b7,$01,$80,$b6,$01,$80,$b5,$01 47 | .byte $80,$b4,$84,$35,$01,$80,$b3,$01,$80,$b2,$01,$80,$b1,$01,$80,$b0 48 | .byte $0b,$83,$b1,$18,$00 49 | psfx_ntsc_ch2_out: 50 | .byte $81,$42,$82,$00,$80,$bf,$89,$f0,$01,$80,$78,$01,$80,$7a,$01,$80 51 | .byte $bc,$01,$80,$bd,$01,$80,$be,$01,$80,$bd,$01,$80,$bc,$01,$80,$bb 52 | .byte $01,$80,$ba,$01,$81,$3f,$80,$bf,$01,$80,$78,$01,$80,$7a,$01,$80 53 | .byte $bc,$01,$80,$bd,$01,$80,$be,$84,$43,$85,$00,$83,$b2,$01,$80,$bd 54 | .byte $01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$81,$54,$80,$bf,$84,$40 55 | .byte $01,$80,$78,$01,$80,$7a,$01,$80,$bc,$01,$80,$bd,$01,$80,$be,$01 56 | .byte $80,$bd,$01,$80,$bc,$01,$80,$bb,$01,$80,$ba,$01,$80,$b9,$84,$55 57 | .byte $01,$80,$b8,$01,$80,$b7,$01,$80,$b6,$01,$80,$b5,$01,$80,$b4,$01 58 | .byte $80,$b3,$01,$80,$b2,$01,$80,$b1,$01,$80,$b0,$01,$83,$b1,$13,$00 59 | -------------------------------------------------------------------------------- /src/g_camera.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_calc_camera_nosplit 4 | ; desc: Calculate the quake scroll offsets, and adds them to cameraX/cameraY. 5 | ; Then calculates the cameraX/cameraY and prepares it for upload to the PPU. 6 | ; note: Does not handle scroll splits. 7 | gm_calc_camera_nosplit: 8 | ; scroll X 9 | lda camera_x 10 | sta scroll_x 11 | 12 | ; scroll Y 13 | lda camera_y 14 | clc 15 | adc camera_y_sub 16 | cmp #240 17 | bcc :+ 18 | adc #15 ; adds 16 because carry is set 19 | : sta scroll_y 20 | 21 | jmp gm_calc_camera_shake_and_hi 22 | 23 | ; ** SUBROUTINE: gm_calc_camera 24 | ; desc: Calculates the cameraX/cameraY and prepares it for upload to the PPU. 25 | ; note: Does not calculate quake offsets. 26 | gm_calc_camera_split: 27 | ; scroll X 28 | lda camera_x 29 | sta scroll_x 30 | 31 | ; scroll Y 32 | lda camera_y 33 | clc 34 | adc camera_y_sub 35 | cmp #240 36 | bcc :+ 37 | adc #15 38 | : sta scroll_y 39 | 40 | ; add the scroll split offset if needed. 41 | lda scrollsplit 42 | beq @doneAdding 43 | 44 | sec 45 | adc scroll_y 46 | sta scroll_y 47 | bcs @carryIsSet 48 | 49 | ; carry clear, just check if >$F0 50 | cmp #$F0 51 | bcc @doneAdding 52 | 53 | sec 54 | sbc #$F0 55 | sta scroll_y 56 | 57 | @flipHighBitAndDone: 58 | lda temp2 59 | eor #1 60 | sta temp2 61 | 62 | @doneAdding: 63 | jmp gm_calc_camera_shake_and_hi 64 | 65 | @carryIsSet: 66 | ; carry was set 67 | adc #$0F ; add +$10 68 | sta scroll_y 69 | ; TODO: carry might be set again. I don't think it matters right now 70 | ; but if you set scrolllimit to > like 80, then look here first. 71 | jmp @flipHighBitAndDone 72 | 73 | ; ** SUBROUTINE: gm_calc_camera_shake_and_hi 74 | ; desc: Shakes the camera according to quakeflags, and calculates the high bits of scroll. 75 | .proc gm_calc_camera_shake_and_hi 76 | ; scroll X/Y high 77 | lda camera_x_pg 78 | and #1 79 | sta temp1 80 | lda camera_y_hi 81 | sta temp2 82 | 83 | lda #0 84 | sta temp11 85 | 86 | lda quaketimer 87 | beq noQuake 88 | 89 | dec quaketimer 90 | 91 | lda #cont_up 92 | bit quakeflags 93 | beq notUp 94 | 95 | jsr rand_m2_to_p1 96 | sta temp11 97 | 98 | notUp: 99 | lda #cont_down 100 | bit quakeflags 101 | beq notDown 102 | 103 | jsr rand_m1_to_p2 104 | clc 105 | adc temp11 106 | sta temp11 107 | 108 | notDown: 109 | lda #cont_left 110 | bit quakeflags 111 | beq notLeft 112 | 113 | jsr rand_m2_to_p1 114 | clc 115 | adc scroll_x 116 | sta scroll_x 117 | lda temp1 118 | adc temp5 119 | and #1 120 | sta temp1 121 | 122 | notLeft: 123 | lda #cont_right 124 | bit quakeflags 125 | beq notRight 126 | 127 | jsr rand_m1_to_p2 128 | clc 129 | adc scroll_x 130 | sta scroll_x 131 | lda temp1 132 | adc temp5 133 | and #1 134 | sta temp1 135 | 136 | notRight: 137 | lda temp11 138 | bmi shakeNegative 139 | 140 | ; shake positive 141 | clc 142 | adc scroll_y 143 | cmp #240 144 | bcc :+ 145 | adc #15 146 | : sta scroll_y 147 | jmp noQuake 148 | 149 | shakeNegative: 150 | clc 151 | adc scroll_y 152 | cmp #240 153 | bcc :+ 154 | sbc #16 155 | : sta scroll_y 156 | 157 | noQuake: 158 | lda #0 159 | ldx temp1 160 | beq :+ 161 | ora #pctl_highx 162 | 163 | : ldx temp2 164 | beq :+ 165 | ora #pctl_highy 166 | 167 | : sta scroll_flags 168 | rts 169 | .endproc 170 | -------------------------------------------------------------------------------- /src/g_control.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_check_climb_input 4 | ; desc: Depending on the control scheme, checks the state of the CLIMB button. 5 | ; 6 | ; For the SNES controller, checks the state of the L or R buttons. 7 | ; For the NES controller, if emulator mode is selected, the state of the SELECT button is checked. 8 | ; Otherwise, the UP button is checked. 9 | gm_check_climb_input: 10 | lda climbcdown 11 | beq :+ 12 | dec climbcdown 13 | lda #0 14 | sta climbbutton 15 | rts 16 | 17 | : lda ctrlscheme 18 | cmp #cns_snes 19 | beq @isSNES 20 | cmp #cns_emulat 21 | beq @isEmulator 22 | 23 | lda game_cont 24 | and #cont_up 25 | sta climbbutton 26 | rts 27 | 28 | @isSNES: 29 | lda game_cont+1 30 | and #(cont_lsh|cont_rsh) 31 | sta climbbutton 32 | rts 33 | 34 | @isEmulator: 35 | lda game_cont 36 | and #cont_select 37 | sta climbbutton 38 | rts 39 | 40 | ; ** SUBROUTINE: gm_update_lift_boost 41 | ; desc: Updates the lift boost. 42 | .proc gm_update_lift_boost 43 | lda currlboostX 44 | bne notZero 45 | lda currlboostY 46 | bne notZero 47 | 48 | ; it's zero, check if the lift boost is zero 49 | lda liftboosttm 50 | bne liftBoostGraceNonZero 51 | 52 | ; lift boost grace is zero 53 | sta liftboostX 54 | sta liftboostY 55 | jmp ensureSane 56 | 57 | liftBoostGraceNonZero: 58 | ; not zero, so copy the last boost 59 | lda lastlboostX 60 | sta liftboostX 61 | lda lastlboostY 62 | sta liftboostY 63 | dec liftboosttm 64 | jmp ensureSane 65 | 66 | notZero: 67 | ; lift boost is not zero right now. 68 | lda liftboostX 69 | sta lastlboostX 70 | lda liftboostY 71 | sta lastlboostY 72 | 73 | lda currlboostX 74 | sta liftboostX 75 | lda currlboostY 76 | sta liftboostY 77 | 78 | lda #0 79 | sta currlboostX 80 | sta currlboostY 81 | 82 | lda #8 83 | sta liftboosttm 84 | 85 | ensureSane: 86 | lda liftboostY 87 | bpl boostPositive 88 | rts 89 | 90 | boostPositive: 91 | lda #0 92 | sta liftboostY 93 | rts 94 | .endproc 95 | 96 | ; ** SUBROUTINE: gm_update_game_cont 97 | ; desc: Updates the game_cont variables to the state of p1_cont. If input is blocked, then 98 | ; it's actually set to zero. 99 | gm_update_game_cont: 100 | lda #g3_blockinp 101 | bit gamectrl3 102 | beq @normalInput 103 | 104 | lda #0 105 | sta game_cont 106 | sta game_cont+1 107 | sta game_conto 108 | sta game_conto+1 109 | rts 110 | 111 | @normalInput: 112 | lda p1_cont 113 | ora game_cont_force 114 | sta game_cont 115 | lda p1_cont+1 116 | ora game_cont_force+1 117 | sta game_cont+1 118 | 119 | lda p1_conto 120 | sta game_conto 121 | lda p1_conto+1 122 | sta game_conto+1 123 | 124 | lda #0 125 | sta game_cont_force 126 | sta game_cont_force+1 127 | rts 128 | -------------------------------------------------------------------------------- /src/g_math.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | 4 | ; NOTE: this only covers a range of PI/4. 5 | ; Each table is 32 items in size. 6 | sintable: .byte 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,59,62,65,67,70,73,75,78,80,82,85,87,89,91,94,96,98,100,102,103,105,107,108,110,112,113,114,116,117,118,119,120,121,122,123,123,124,125,125,126,126,126,126,126,127 7 | 8 | ; ** SUBROUTINE: sine 9 | ; desc: Calculates the sine for an angle. 10 | ; parameters: A - Angle in 1/256 Full Rotations 11 | ; note: clobbers X, temp5 12 | ; note: Flags match the current state of A. 13 | .proc sine 14 | cmp #65 15 | bcs notFirstQuarter 16 | tax 17 | 18 | ; between 0 and PI/4, straightforward - take the small side of a triangle in the first 8th 19 | lda sintable, x 20 | rts 21 | 22 | notFirstQuarter: 23 | ; maybe it's the second half 24 | cmp #128 25 | bcs notFirstHalf 26 | 27 | ; between PI/4 and PI/2, take the first quarter but mirrored 28 | and #63 29 | sta temp5 30 | lda #64 31 | sec 32 | sbc temp5 33 | tax 34 | lda sintable, x 35 | rts 36 | 37 | notFirstHalf: 38 | ; between PI and 2PI, it's actually the first half but upside down. 39 | and #$7F 40 | jsr sine 41 | 42 | ; not done yet! we need to flip the sine now 43 | sta temp5 44 | lda #0 45 | sec 46 | sbc temp5 47 | rts 48 | .endproc 49 | 50 | ; ** SUBROUTINE: cosine 51 | ; desc: Calculates the cosine for an angle. 52 | ; note: See sine for a description of parameters and clobbers. 53 | .proc cosine 54 | clc 55 | adc #64 56 | jmp sine 57 | .endproc 58 | 59 | ; ** SUBROUTINE: mul_8x8 60 | ; desc: Multiplies two 8 bit numbers. 61 | ; clobbers: temp1, temp2 62 | ; parameters: A - factor 1, Y - factor 2 63 | ; returns: A - low 8 bits, Y - high 8 bits 64 | ; clobbers: temp1, temp2, Y reg 65 | ; credits: https://www.nesdev.org/wiki/8-bit_Multiply#tepples_unrolled 66 | .proc mul_8x8 67 | @productLow = temp1 68 | @factor2 = temp2 69 | lsr 70 | sta @productLow 71 | tya 72 | beq return 73 | dey 74 | sty @factor2 75 | lda #0 76 | .repeat 8, i 77 | .if i > 0 78 | ror @productLow 79 | .endif 80 | bcc :+ 81 | adc @factor2 82 | : ror 83 | .endrepeat 84 | tay 85 | lda @productLow 86 | ror 87 | return: 88 | rts 89 | .endproc 90 | -------------------------------------------------------------------------------- /src/g_palette.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | init_palette: 4 | .byte $0f,$20,$10,$00 ; grey tiles 5 | .byte $0f,$37,$16,$06 ; brown tiles 6 | .byte $0f,$20,$21,$11 ; blue tiles 7 | .byte $0f,$39,$29,$19 ; green tiles 8 | .byte $0f,$37,$14,$21 ; player sprite colors 9 | .byte $0f,$00,$00,$00 ; red/strawberry sprite 10 | .byte $0f,$00,$00,$00 ; blue sprite 11 | .byte $0f,$00,$00,$00 ; green/refill sprite 12 | owld_palette: 13 | .byte $0f,$0c,$01,$00 14 | .byte $0f,$0c,$10,$30 15 | .byte $0f,$0c,$00,$10 16 | .byte $0f,$30,$10,$00 17 | .byte $0f,$37,$14,$21 ; player sprite colors 18 | .byte $0f,$36,$16,$06 ; red/strawberry sprite 19 | .byte $0f,$31,$21,$01 ; blue sprite 20 | .byte $0f,$30,$29,$09 ; green/refill sprite 21 | title_palette: 22 | .byte $0f,$30,$10,$2d 23 | .byte $0f,$30,$11,$2d 24 | .byte $0f,$30,$32,$2d 25 | .byte $0f,$30,$11,$32 26 | .byte $0f,$37,$14,$21 ; player sprite colors 27 | .byte $0f,$36,$16,$06 ; red/strawberry sprite 28 | .byte $0f,$20,$21,$11 ; blue sprite 29 | .byte $0f,$30,$29,$09 ; green/refill sprite 30 | -------------------------------------------------------------------------------- /src/g_palloc.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_allocate_palette 4 | ; desc: Allocates a palette for use while rendering. 5 | ; Returns the palette slot given, or one, if no palette slots were left. 6 | ; 7 | ; arguments: 8 | ; A - The palette ID (prg_main::sprite_palettes) to load. 9 | ; 10 | ; returns: 11 | ; A - The palette index returned. 12 | ; 13 | ; clobbers: 14 | ; temp1 15 | gm_allocate_palette: 16 | tax 17 | lda palidxs, x 18 | beq @notLoaded 19 | 20 | ; palette was loaded, so just return that index 21 | rts 22 | 23 | @notLoaded: 24 | txa ; transfer the original thing back into A 25 | ldy sprpalcount 26 | cpy #3 ; check if 3 palettes have been written 27 | bne @mayAllocate 28 | 29 | ; may not allocate because there was not enough space! 30 | ; assert(0) 31 | lda #1 32 | rts 33 | 34 | @mayAllocate: 35 | ; palette count already loaded in Y 36 | 37 | ; multiply by three, and store in X 38 | sta sprpaltemp 39 | asl 40 | clc 41 | adc sprpaltemp 42 | tax 43 | 44 | lda @indexTable, y 45 | tay 46 | 47 | ; now write 3 bytes 48 | lda sprite_palettes, x 49 | sta spritepals, y 50 | inx 51 | iny 52 | lda sprite_palettes, x 53 | sta spritepals, y 54 | inx 55 | iny 56 | lda sprite_palettes, x 57 | sta spritepals, y 58 | iny 59 | 60 | ; Well sprpaltemp still contains the original palette index 61 | ldx sprpaltemp 62 | 63 | ; then increment the amount of loaded palettes 64 | inc sprpalcount 65 | lda sprpalcount 66 | sta palidxs, x 67 | 68 | ; and return! 69 | rts 70 | 71 | @indexTable: .byte 0,3,6 72 | 73 | ; ** SUBROUTINE: gm_clear_palette_allocator 74 | ; desc: Clears the palette allocator and copies the current 75 | ; sprite palette into the old sprite palette. Run every frame. 76 | gm_clear_palette_allocator: 77 | ldy #0 78 | sty sprpalcount 79 | 80 | : lda spritepals, y 81 | sta spritepalso,y 82 | 83 | ;;;; DEBUG ;;;; 84 | ; TODO: Remove on release 85 | lda #0 86 | sta spritepals, y 87 | ;;;; DEBUG DONE ;;;; 88 | 89 | iny 90 | cpy #9 91 | bne :- 92 | 93 | ldy #0 94 | lda #0 95 | : sta palidxs, y 96 | iny 97 | cpy #pal_max 98 | bne :- 99 | 100 | rts 101 | 102 | ; ** SUBROUTINE: gm_check_updated_palettes 103 | ; desc: Checks for updated palettes and enqueues an upload for each. 104 | gm_check_updated_palettes: 105 | ldy #0 106 | @loop: 107 | lda spritepals, y 108 | cmp spritepalso, y 109 | beq @dontSet 110 | lda @flags, y 111 | ora nmictrl2 112 | sta nmictrl2 113 | @dontSet: 114 | iny 115 | cpy #9 116 | bne @loop 117 | rts 118 | 119 | @flags: 120 | .byte nc2_updpal1,nc2_updpal1,nc2_updpal1 121 | .byte nc2_updpal2,nc2_updpal2,nc2_updpal2 122 | .byte nc2_updpal3,nc2_updpal3,nc2_updpal3 123 | 124 | ; Sprite Palettes 125 | sprite_palettes: 126 | .byte $30,$21,$11 ; blue sprite 127 | .byte $36,$16,$06 ; red sprite 128 | .byte $34,$25,$15 ; pink palette 129 | .byte $30,$29,$09 ; green sprite 130 | .byte $20,$10,$00 ; gray sprite 131 | .byte $30,$27,$07 ; golden palette 132 | .byte $20,$37,$09 ; old lady palette 133 | .byte $27,$21,$11 ; bird palette 134 | .byte $30,$21,$01 ; bird tutorial palette 135 | .byte $34,$14,$04 ; dark chaser palette 136 | .byte $30,$21,$0f ; mirror edge palette 137 | .byte $30,$26,$06 ; fire palette 138 | .byte $30,$1C,$0C ; tower palette 139 | .byte $30,$23,$03 ; stone palette 140 | .byte $30,$30,$30 ; full white palette 141 | .byte $15,$00,$0F ; dust bunny palette 142 | -------------------------------------------------------------------------------- /src/g_pause.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_pause 4 | ; desc: Pauses the game. 5 | .proc gm_pause 6 | ;lda dialogsplit 7 | ;bne return 8 | ;lda dlg_cutsptr+1 9 | ;bne return 10 | lda playerctrl 11 | and #pl_dead 12 | beq dontreturn 13 | return: 14 | rts 15 | 16 | dontreturn: 17 | inc paused 18 | 19 | lda dlgmusicpaus 20 | beq :+ 21 | jsr famistudio_music_pause 22 | 23 | : lda scrollsplit 24 | sta scrollsplitb 25 | lda dialogsplit 26 | sta dialogsplitb 27 | 28 | beq @dontStall 29 | 30 | ; stall to avoid a race condition with the dialog, 31 | ; since we are relatively early in the frame. 32 | ldx #5 33 | @loop2: 34 | ldy #255 35 | @loop1: 36 | dey 37 | bne @loop1 38 | dex 39 | bne @loop2 40 | 41 | @dontStall: 42 | lda #0 43 | sta scrollsplit 44 | sta dialogsplit 45 | lda camera_y 46 | clc 47 | adc camera_y_sub 48 | sta scroll_y 49 | 50 | lda spr0_bknum 51 | sta spr0_paubk 52 | lda spr1_bknum 53 | sta spr1_paubk 54 | lda spr2_bknum 55 | sta spr2_paubk 56 | lda spr3_bknum 57 | sta spr3_paubk 58 | 59 | lda #$FF 60 | sta pauseoption 61 | 62 | lda #chrb_pause 63 | sta spr0_bknum 64 | lda #chrb_pause+1 65 | sta spr1_bknum 66 | lda #chrb_pause+2 67 | sta spr2_bknum 68 | lda #chrb_pause+3 69 | sta spr3_bknum 70 | 71 | ; fill in the first 3 palettes with stuff and reupload 72 | lda #$10 73 | sta spritepals+0 74 | lda #$00 75 | sta spritepals+1 76 | ; 3rd color of that palette is unused. 77 | 78 | lda #$30 79 | sta spritepals+3 80 | ; 2nd color of that palette are unused 81 | 82 | lda #$29 83 | sta spritepals+6 84 | ; 2nd color of that palette are unused 85 | 86 | lda #$0F 87 | sta spritepals+2 88 | sta spritepals+5 89 | sta spritepals+8 90 | 91 | lda nmictrl2 92 | ora #(nc2_updpal1 | nc2_updpal2 | nc2_updpal3) 93 | sta nmictrl2 94 | rts 95 | .endproc 96 | 97 | ; ** SUBROUTINE: gm_unpause 98 | ; desc: Unpauses the game. 99 | .proc gm_unpause 100 | lda paused 101 | beq return 102 | 103 | dec paused 104 | 105 | lda spr0_paubk 106 | sta spr0_bknum 107 | lda spr1_paubk 108 | sta spr1_bknum 109 | lda spr2_paubk 110 | sta spr2_bknum 111 | lda spr3_paubk 112 | sta spr3_bknum 113 | 114 | lda scrollsplitb 115 | sta scrollsplit 116 | lda dialogsplitb 117 | sta dialogsplit 118 | 119 | lda dlgmusicpaus 120 | beq :+ 121 | 122 | lda #0 123 | jsr famistudio_music_pause 124 | 125 | ; restore old palette 126 | : ldy #0 127 | palettePrepLoop: 128 | lda (paladdr), y 129 | sta temprow1, y 130 | iny 131 | cpy #16 132 | bne palettePrepLoop 133 | 134 | ; set that bit 135 | lda #$3F 136 | sta ppuaddrHR1+1 137 | lda #$00 138 | sta ppuaddrHR1 139 | lda #$10 140 | sta wrcountHR1 141 | lda #$00 142 | sta wrcountHR2 143 | sta wrcountHR3 144 | 145 | lda nmictrl 146 | ora #nc_flushrow 147 | sta nmictrl 148 | 149 | ; wait for the palette to be shifted 150 | jsr soft_nmi_on 151 | jsr nmi_wait 152 | jsr soft_nmi_off 153 | 154 | return: 155 | rts 156 | .endproc 157 | 158 | ; ** SUBROUTINE: gm_check_pause 159 | ; desc: Checks the start button to see if the game should be paused. 160 | .proc gm_check_pause 161 | lda p1_conto 162 | and #cont_start 163 | bne gm_unpause::return ; the button was already pressed 164 | 165 | lda p1_cont 166 | and #cont_start 167 | beq gm_unpause::return ; you didn't actually press start 168 | 169 | lda paused 170 | bne gm_unpause 171 | jmp gm_pause 172 | .endproc 173 | 174 | ; ** SUBROUTINE: gm_clear_collided 175 | ; desc: Clears the collided flag for entities, and updates the old velocities 176 | .proc gm_clear_collided 177 | ldy #0 178 | : lda sprspace+sp_flags, y 179 | and #<~ef_collided 180 | sta sprspace+sp_flags, y 181 | iny 182 | cpy #sp_max 183 | bne :- 184 | 185 | rts 186 | .endproc 187 | -------------------------------------------------------------------------------- /src/g_respawn.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_init_respawn 4 | ; desc: Performs the respawn scene. 5 | .proc gm_do_respawn 6 | lda nmictrl 7 | ora #nc_turnon 8 | sta nmictrl 9 | 10 | jsr gm_init_death_wipe 11 | 12 | lda deathwipe 13 | ldx deathwipe2 14 | sta deathwipe2 15 | stx deathwipe 16 | 17 | lda #$04 18 | sta plr_spr_l 19 | lda #$06 20 | sta plr_spr_r 21 | lda #$32 22 | sta plh_spr_l 23 | lda #$30 24 | sta plh_spr_r 25 | lda #0 26 | sta sprxoff 27 | sta spryoff 28 | sta spryoffbase 29 | 30 | jsr gm_respawn_leave_doframe2 31 | 32 | loop: 33 | lda respawntmr 34 | sta deathtimer 35 | sta transtimer 36 | 37 | ; temp11 is the divider count in like gm_dead_sub3 or something 38 | lda #16 39 | sta plattemp1 40 | lda #4 41 | sta temp11 42 | 43 | jsr gm_draw_dead::respawnOverride 44 | 45 | lda respawntmr 46 | cmp #$10 47 | bcs doWindWipeUpdate 48 | 49 | lda #0 50 | sta miscsplit 51 | lda #def_ppu_msk 52 | sta deathwipe 53 | sta deathwipe2 54 | 55 | lda #irq_death_wipe 58 | sta irqaddr+1 59 | 60 | bne doneWipe 61 | 62 | doWindWipeUpdate: 63 | jsr gm_wind_wipe_update 64 | 65 | lda #16 66 | sta miscsplit 67 | doneWipe: 68 | jsr gm_respawn_leave_doframe2 69 | 70 | dec respawntmr 71 | bne loop 72 | 73 | lda #0 74 | sta spr0_bknum 75 | sta miscsplit 76 | sta deathwipe 77 | sta deathwipe2 78 | lda #def_ppu_msk 79 | sta ppu_mask 80 | 81 | jsr gm_leave_doframe 82 | rts 83 | .endproc 84 | -------------------------------------------------------------------------------- /src/g_sfx.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | gm_dash_sfx: 4 | lda #0 5 | ldx #FAMISTUDIO_SFX_CH1 6 | jmp famistudio_sfx_play 7 | 8 | gm_strawb_sfx: 9 | lda #1 10 | ldx #FAMISTUDIO_SFX_CH1 11 | jmp famistudio_sfx_play 12 | 13 | gm_jump_sfx: 14 | lda #2 15 | ldx #FAMISTUDIO_SFX_CH0 16 | jmp famistudio_sfx_play 17 | 18 | gm_death_sfx: 19 | lda #3 20 | ldx #FAMISTUDIO_SFX_CH1 21 | jmp famistudio_sfx_play 22 | 23 | gm_whoosh_sfx: 24 | lda #4 25 | ldx #FAMISTUDIO_SFX_CH0 26 | jmp famistudio_sfx_play 27 | 28 | gm_spring_sfx: 29 | lda #5 30 | ldx #FAMISTUDIO_SFX_CH1 31 | jmp famistudio_sfx_play 32 | 33 | gm_bird_caw_sfx: 34 | lda #6 35 | ldx #FAMISTUDIO_SFX_CH0 36 | jmp famistudio_sfx_play 37 | 38 | gm_crumble_sfx: 39 | lda #7 40 | ldx #FAMISTUDIO_SFX_CH0 41 | jmp famistudio_sfx_play 42 | -------------------------------------------------------------------------------- /src/g_wait.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_leave_doframe 4 | ; desc: Completes processing of this frame early, waits for the frame to elapse, and returns. 5 | gm_leave_doframe: 6 | jsr gm_load_hair_palette 7 | jsr gm_draw_player 8 | jsr gm_draw_entities 9 | jsr gm_calc_camera_nosplit 10 | jsr gm_update_bg_effects 11 | jsr gm_check_updated_palettes 12 | jsr soft_nmi_on 13 | jsr nmi_wait 14 | jsr soft_nmi_off 15 | 16 | jsr com_clear_oam 17 | jmp gm_clear_palette_allocator 18 | 19 | -------------------------------------------------------------------------------- /src/g_wipe.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: gm_respawn_leave_doframe 4 | ; desc: Completes processing of this frame early, waits for the frame to elapse, and returns. 5 | ; Used by respawn code. 6 | gm_respawn_leave_doframe: 7 | ; note: hair palette is already loaded, don't update palettes, don't clear OAM 8 | ; (whatever gm_draw_dead will draw, will override everything) 9 | jsr gm_wind_wipe_update 10 | jsr gm_draw_dead 11 | 12 | gm_respawn_leave_doframe2: 13 | jsr gm_calc_camera_nosplit 14 | jsr soft_nmi_on 15 | jsr nmi_wait 16 | jsr soft_nmi_off 17 | jmp com_clear_oam 18 | 19 | ; NOTE: The total of irqtmp1 + irqtmp2 MUST be 18 20 | ; death_irq_table_1 MOVED TO gam_main.asm 21 | 22 | ; ** SUBROUTINE: gm_wind_wipe_update 23 | ; desc: Updates the wind wipe. 24 | .proc gm_wind_wipe_update 25 | lda #32 26 | sec 27 | sbc transtimer 28 | ; the table is only 25 items long 29 | cmp #24 30 | bcc :+ 31 | lda #24 32 | : tay 33 | 34 | .repeat 4, idx 35 | lda death_irq_table_1 + 25 * idx, y 36 | sta irqtmp + 2 * idx + 0 37 | lda #18 38 | sec 39 | sbc death_irq_table_1 + 25 * idx, y 40 | sta irqtmp + 2 * idx + 1 41 | .endrepeat 42 | 43 | rts 44 | 45 | .endproc 46 | 47 | .proc gm_init_death_wipe 48 | ; prepare the wind wipe 49 | lda #$01 50 | sta irqtmp1 51 | sta irqtmp3 52 | sta irqtmp5 53 | sta irqtmp7 54 | 55 | lda #$11 56 | sta irqtmp2 57 | lda #$13 58 | sta irqtmp4 59 | sta irqtmp6 60 | sta irqtmp8 61 | 62 | lda #def_ppu_msk 63 | sta deathwipe2 64 | lda #%00010000 ; only sprites 65 | sta deathwipe 66 | lda #irq_death_wipe 69 | sta irqaddr+1 70 | lda #16 71 | sta miscsplit 72 | rts 73 | .endproc 74 | -------------------------------------------------------------------------------- /src/gam_main.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; Desc: If you put these functions in the game segment, it will overflow. 4 | ; These functions are instead implemented in the main segment. 5 | .include "g_decomp.asm" 6 | .include "g_scroll.asm" 7 | -------------------------------------------------------------------------------- /src/level0/bank_0.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL0A" 4 | .include "metatile.asm" 5 | .include "rooms/0.asm" 6 | .include "music/music.asm" 7 | .include "roomlist.asm" 8 | .include "warplist.asm" 9 | .include "palette.asm" 10 | .include "dialog.asm" 11 | .include "entity.asm" 12 | 13 | level0_music: 14 | .word music_data_ch0 ; song list 15 | .byte $00 ; default song 16 | -------------------------------------------------------------------------------- /src/level0/dialog.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024-2025 iProgramInCpp 2 | 3 | ch0_granny: 4 | begin 5 | lock_input 6 | wait_ground 7 | face_player 0 8 | left 9 | 10 | ; note: the camera should be fixed at a certain position, therefore 11 | ; we can get away with hardcoding walking positions 12 | 13 | speaker SPK_madeline 14 | expression MAD_normal 15 | dialog2 @d0 16 | 17 | face_ent 1 18 | 19 | walk_player $7C, $70 20 | wait 6 21 | face_player 0 22 | expression MAD_normal 23 | dialog2 @d1 24 | 25 | right 26 | speaker SPK_granny 27 | expression GRN_normal 28 | dialog2 @d2 29 | 30 | walk_player $BC, $70 31 | wait 6 32 | speaker SPK_madeline 33 | expression MAD_sad 34 | face_player 1 35 | wait 5 36 | face_ent 0 37 | dialog2 @d3 38 | 39 | trigger 2 ; "haha" 40 | wait 30 ; half a sec 41 | left 42 | speaker SPK_granny 43 | expression GRN_laugh 44 | dialog2 @d4 45 | 46 | right 47 | speaker SPK_madeline 48 | expression MAD_upset 49 | dialog @d5 50 | 51 | expression MAD_angry 52 | dialog2 @d6 53 | 54 | left 55 | trigger 0 ; stop laughing 56 | speaker SPK_granny 57 | expression GRN_normal 58 | dialog @d7 59 | dialog @d8 60 | expression GRN_creepA 61 | dialog @d9 62 | expression GRN_creepB 63 | dialog2 @d10 64 | 65 | wait 30 66 | right 67 | speaker SPK_madeline 68 | expression MAD_upset 69 | dialogE @d11 70 | 71 | unlock_input 72 | end 73 | 74 | line @d0, "Excuse me, ma'am?" 75 | line @d1, "The sign out front is busted...\nis this the Mountain trail?" 76 | line @d2, "You're almost there.\nIt's just across the bridge." 77 | line @d3, "By the way, you should call someone\nabout your driveway. The ridge\ncollapsed and I nearly died." 78 | line @d4, "If my \"driveway\" almost did you in,\nthe Mountain might be a bit much\nfor you." 79 | line @d5, "..." 80 | line @d6, "Well, if an old bat like you can\nsurvive out here, I think I'll be fine." 81 | line @d7, "Suit yourself." 82 | line @d8, "But you should know,\nCeleste Mountain is a strange place." 83 | line @d9, "You might see things." 84 | line @d10,"Things you ain't ready to see." 85 | line @d11,"You should seek help, lady." 86 | 87 | ch0_dash_tutorial: 88 | begin 89 | pcdgOFF 90 | 91 | face_player 0 92 | rm25pcvel 93 | wait 5 94 | rm25pcvel 95 | wait 5 96 | rm25pcvel 97 | wait 5 98 | rm25pcvel 99 | wait 5 100 | rm25pcvel 101 | wait 5 102 | rm25pcvel 103 | wait 5 104 | rm25pcvel 105 | wait 5 106 | rm25pcvel 107 | wait 5 108 | rm25pcvel 109 | wait 5 110 | rm25pcvel 111 | wait 5 112 | 113 | trigger 2 ; fly down 114 | zerovel 115 | 116 | wait 80 117 | trigger 3 ; knock knock 118 | 119 | wait 64 120 | trigger 4 ; bawk!! 121 | 122 | wait_ground 123 | walk_player 188,160 124 | trigger 5 ; fly away 125 | 126 | ; start panting 127 | call_rt gm_set_panting 128 | lock_input 129 | wait 80 130 | 131 | 132 | finish_level 133 | end 134 | -------------------------------------------------------------------------------- /src/level0/layout.txt: -------------------------------------------------------------------------------- 1 | level0_r1,0,0 2 | Props,level0_r1,0,0 3 | Spawn,level0_r1,0,144 4 | Spawn,level0_r1,432,160 5 | PaletteOverride,level0_r1,16,4,2,17,4,2,18,4,2,19,4,2,16,5,2,17,5,2,18,5,2,19,5,2,16,6,2,17,6,2,18,6,2,19,6,2,16,7,2,17,7,2,18,7,2,19,7,2,16,8,2,17,8,2,18,8,2,19,8,2,16,9,2,17,9,2,18,9,2,19,9,2 6 | level0_r2,448,-16 7 | Props,level0_r2,0,0 8 | Spawn,level0_r2,464,96 9 | Spawn,level0_r2,0,176 10 | level0_r3,928,-80 11 | Props,level0_r3,0,0 12 | Spawn,level0_r3,0,160 13 | Spawn,level0_r3,272,128 14 | level0_r4,1216,-112 15 | Props,level0_r4,0,0 16 | Spawn,level0_r4,0,160 17 | Filler,864,-128,64,112 18 | -------------------------------------------------------------------------------- /src/level0/metatile.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; Metatile Data for "Prologue" (Level 0) 4 | 5 | ; Metatiles 6 | ; 7 | ; For a single metatile ID, the following properties: 8 | ; - metatiles: The char tiles that make up the visual representation of the metatile 9 | ; - metatile_palette: The palette used for the metatile 10 | ; - metatile_collision: The collision mask for the metatile. 11 | 12 | ; These are the metatiles for the Intro level. 13 | ; Eventually the metatile bank will be swappable with different level banks. 14 | 15 | ;metatiles: 16 | .align $100 17 | .byte $00 ; Air 18 | .byte $60,$64,$70,$74 ; Dirt Corners 19 | .byte $61,$62,$63 ; Dirt Tops 20 | .byte $71,$72,$73 ; Dirt Bottoms 21 | .byte $67,$77,$68,$67 ; Dirt Left 22 | .byte $69,$79,$6A,$7A ; Dirt Right 23 | .byte $6B,$6C,$6D,$6E,$7B,$7C,$7D,$A5 ; Dirt Middles 24 | .byte $6F,$78 ; Dirt Left, Right Ends 25 | .byte $80,$84,$83,$87 ; Snow Corners 26 | .byte $88,$8C,$8A ; Snow Tops 27 | .byte $8F,$93,$91 ; Snow Bottoms 28 | .byte $81,$82 ; Snow Left 29 | .byte $85,$86 ; Snow Right 30 | .byte $8D,$89,$8E,$92,$90,$98,$99,$9A,$9B ; Snow Middles 31 | .byte $94,$96,$95,$97 ; Snow In-corners 32 | .byte $65,$66,$75,$76 ; Dirt In-corners 33 | .byte $A2,$A3,$A4 ; Jump Through 34 | .byte $AA ; Spikes 35 | .byte $AA,$AB,$AC,$AD ; Grass Decals 36 | .byte $B0,$B1,$B2,$B3,$B4 ; House Layer 0 37 | .byte $B5,$B6,$B7,$B8,$B9,$BA,$BC,$BD ; House Layer 1 38 | .byte $C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7,$C8,$C9,$CA,$CC ; House Layer 2 39 | .byte $D3,$D4,$D5,$D6,$D7,$D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF ; House Layer 3 40 | .byte $E3,$E4,$E5,$E6,$E7,$E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; House Layer 4 41 | .byte $F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$CD,$CE ; House Layer 5 42 | .byte $01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F ; House Layer 6 43 | .byte $2F,$2D,$2E,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F ; House Layer 7 44 | .byte $CB,$BB ; House Addenda 45 | .byte $10,$11,$12,$13,$24,$25,$26,$27,$28,$29,$2A,$2B ; Bridge 1 46 | .byte $3C,$3D,$7E,$7F,$BE,$BF,$CF,$D2,$D0,$D1,$E0,$E1 ; Bridge 2 47 | .byte $F0,$F1,$A8 ; Bridge 3 48 | .byte $E2,$F2,$3E,$2C,$A0,$A1 ; Bridge Pole 49 | .byte $00 ; Blank Tile for Intro Crusher 50 | .byte $CF,$D2,$E2,$F2 ; Bridge Pole (Gray) 51 | .byte $60,$67 ; Dirt (Gray) 52 | 53 | ;metatile_info: 54 | .align $100 55 | .byte ct_none ; Air 56 | .res 28, ct_full ; Dirt 57 | .res 27, ct_full ; Snow 58 | .res 4, ct_full ; Dirt 59 | .res 3, ct_jumpthru ; Jump Through 60 | .byte ct_deadlyUP ; Spikes 61 | .res 4, ct_none ; Grass Decals 62 | .res 96, ct_none ; House Decal 63 | ;.res 18, ct_full ; Bridge 64 | .byte ct_jumpthru, ct_none, ct_jumpthru, ct_none, ct_jumpthru, ct_none, ct_jumpthru, ct_none 65 | .byte ct_jumpthru, ct_none, ct_jumpthru, ct_none, ct_jumpthru, ct_none, ct_jumpthru, ct_none 66 | .byte ct_jumpthru, ct_none 67 | .res 2, ct_none ; Bridge Pole 68 | ;.res 7, ct_full ; Bridge 69 | .byte ct_jumpthru, ct_none, ct_jumpthru, ct_none, ct_jumpthru, ct_none, ct_none 70 | .res 6, ct_none ; Bridge Pole 71 | .res 1, ct_none ; Blank Tile for Intro Crusher 72 | .res 4, ct_none ; Bridge Pole (Gray) 73 | .res 2, ct_full ; Dirt (Gray) 74 | 75 | .align $100 -------------------------------------------------------------------------------- /src/level0/mpalette.txt: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; note : this file is NOT included for the game! only for my level editor. 4 | metatile_palette: 5 | .byte $0 ; Air 6 | .res 28, $1 ; Dirt 7 | .res 27, $2 ; Snow 8 | .res 4, $1 ; Dirt 9 | .res 3, $1 ; Jump Through 10 | .byte $0 ; Spikes 11 | .res 4, $3 ; Grass Decals 12 | .res 96, $1 ; House Decal 13 | .res 18, $0 ; Bridge 14 | .res 2, $1 ; Bridge Pole 15 | .res 7, $0 ; Bridge 16 | .res 6, $1 ; Bridge Pole 17 | .res 1, $2 ; Blank Tile for Intro Crusher 18 | .res 4, $0 ; Bridge Pole (Gray) 19 | .res 2, $0 ; Dirt (Gray) 20 | 21 | ; this is only used for the level editor 22 | ; 23 | ; NOTE: $XX means CHARACTER id, not METATILE ID. To specify a metatile ID, use #$XX 24 | ; 25 | ; Header: "mmt [MetametatileID],[Name],[CollisionType]" 26 | ; 27 | ; [udlrABCD]|none|all - All the sides that are NOT connected to solids 28 | ; $FF character ID means unspecified, use the default one 29 | ; you can also redirect to a specific label by passing its name 30 | ; 31 | ; Layout for connections 32 | ; A u B 33 | ; l X r 34 | ; C d D 35 | ; where X - current tile. 36 | ;metametatiles: 37 | ; mmt Air,NonSolid 38 | ; all: $00 39 | ; mmt Dirt,Solid 40 | ; none: $6B,$6C,$6D,$6E,$7B,$7C,$7D 41 | ; u: $61,$62,$63 42 | ; d: $71,$72,$73 43 | ; l: $67,$77,$68,$67 44 | ; r: $69,$79,$6A,$7A 45 | ; ul: $60 46 | ; ur: $64 47 | ; dl: $70 48 | ; dr: $74 49 | ; lr: $FF 50 | ; lru: $FF 51 | ; lrd: $FF 52 | ; lrud: $FF 53 | ; ud: $FF 54 | ; udl: $FF 55 | ; udr: $FF 56 | ; A: none 57 | ; B: none 58 | ; C: none 59 | ; D: none 60 | ; AB: none 61 | ; CD: none 62 | ; AC: none 63 | ; BD: none 64 | ; AD: none 65 | ; BC: none 66 | ; BCD: none 67 | ; ACD: none 68 | ; ABD: none 69 | ; ABC: none 70 | ; ABCD: none 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/level0/palette.asm: -------------------------------------------------------------------------------- 1 | 2 | level0_palette: 3 | .byte $0f,$20,$10,$00 ; grey tiles 4 | .byte $0f,$37,$16,$06 ; brown tiles 5 | .byte $0f,$20,$21,$11 ; blue tiles 6 | .byte $0f,$39,$29,$19 ; green tiles 7 | .byte $0f,$37,$14,$21 ; player sprite colors 8 | -------------------------------------------------------------------------------- /src/level0/roomlist.asm: -------------------------------------------------------------------------------- 1 | level0: 2 | .word level0_music ; music table 3 | .word level0_banks ; list of banks for each room 4 | .byte $00 ; environment type 5 | .byte $07 ; warp count 6 | .word level0_w_init 7 | .word level0_w_r1_to_r2 8 | .word level0_w_r2_to_r1 9 | .word level0_w_r2_to_r3 10 | .word level0_w_r3_to_r2 11 | .word level0_w_r3_to_r4 12 | .word level0_w_r4_to_r3 13 | level0_banks: 14 | .byte prgb_lvl0a ; level0_w_init 15 | .byte prgb_lvl0a ; level0_w_r1_to_r2 16 | .byte prgb_lvl0a ; level0_w_r2_to_r1 17 | .byte prgb_lvl0a ; level0_w_r2_to_r3 18 | .byte prgb_lvl0a ; level0_w_r3_to_r2 19 | .byte prgb_lvl0a ; level0_w_r3_to_r4 20 | .byte prgb_lvl0a ; level0_w_r4_to_r3 21 | -------------------------------------------------------------------------------- /src/level0/sprites.txt: -------------------------------------------------------------------------------- 1 | Granny: 2 | Idle: $00,$04,$08,$00,$04,$08,$0C 3 | Laugh:$10,$14 4 | Walk: $18,$1C 5 | Haha: 6 | $3C 7 | Bird: 8 | Fly: $20,$24,$28,$2C 9 | Dash: $24 10 | Crow: $34,$38 11 | Idle: $30 -------------------------------------------------------------------------------- /src/level0/tgroups.txt: -------------------------------------------------------------------------------- 1 | ; BITS: 2 | ; 0 - Up 3 | ; 1 - Down 4 | ; 2 - Left 5 | ; 3 - Right 6 | ; 4 - UpLeft 7 | ; 5 - UpRight 8 | ; 6 - DownLeft 9 | ; 7 - DownRight 10 | ; 11 | ; the bit mask is left to right, so bit 0 corresponds to index 0. 12 | ; 13 | ; - - don't matter 14 | ; 1 - is one 15 | ; 0 - is zero 16 | ; 17 | ; ex. -------- - default mask, -1000000 - up doesn't matter, down must be 1, rest must be zero 18 | 19 | group 1 20 | name DIRT 21 | color $37 22 | -------- $14 23 | 0101---- $01 24 | 0110---- $02 25 | 1001---- $03 26 | 1010---- $04 27 | 0111---- $05 $06 $07 28 | 1011---- $08 $09 $0A 29 | 1101---- $0B $0C $0D $0E 30 | 1110---- $0F $10 $11 $12 31 | 1111---- $13 $14 $15 $16 $17 $18 $19 $1A 32 | 1111---0 $38 33 | 1111--0- $39 34 | 1111-0-- $3A 35 | 11110--- $3B 36 | 0001---- $1B 37 | 0010---- $1C 38 | 39 | group 2 40 | name SNOW 41 | color $21 42 | -------- $2B 43 | 0101---- $1D 44 | 0110---- $1E 45 | 1001---- $1F 46 | 1010---- $20 47 | 0111---- $21 $22 $23 48 | 1011---- $24 $25 $26 49 | 1101---- $27 $28 50 | 1110---- $29 $2A 51 | 1111---- $2B $2C $2D $2E $2F $30 $31 $32 $33 52 | 1111---0 $34 53 | 1111--0- $35 54 | 1111-0-- $36 55 | 11110--- $37 56 | 0001---- $1D 57 | 0010---- $1E 58 | 59 | -------------------------------------------------------------------------------- /src/level0/warplist.asm: -------------------------------------------------------------------------------- 1 | level0_w_init: 2 | .byte 0 ; room left offset 3 | .byte 0, 144 ; player spawn X/Y 4 | .word level0_r1 5 | level0_w_r1_to_r2: 6 | .byte 0 ; room left offset 7 | .byte 0, 176 ; player spawn X/Y 8 | .word level0_r2 9 | level0_w_r2_to_r1: 10 | .byte 24 ; room left offset 11 | .byte 240, 160 ; player spawn X/Y 12 | .word level0_r1 13 | level0_w_r2_to_r3: 14 | .byte 0 ; room left offset 15 | .byte 0, 160 ; player spawn X/Y 16 | .word level0_r3 17 | level0_w_r3_to_r2: 18 | .byte 28 ; room left offset 19 | .byte 240, 96 ; player spawn X/Y 20 | .word level0_r2 21 | level0_w_r3_to_r4: 22 | .byte 0 ; room left offset 23 | .byte 0, 160 ; player spawn X/Y 24 | .word level0_r4 25 | level0_w_r4_to_r3: 26 | .byte 4 ; room left offset 27 | .byte 240, 128 ; player spawn X/Y 28 | .word level0_r3 29 | -------------------------------------------------------------------------------- /src/level1/bank_0.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL1A" 4 | .include "rooms/0.asm" 5 | -------------------------------------------------------------------------------- /src/level1/bank_1.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL1B" 4 | .include "metatile.asm" 5 | 6 | music_data_ch1_dmc: 7 | .incbin "music/level1.dmc" 8 | 9 | level1_music: 10 | .word music_data_ch1 ; song list 11 | .byte $00 ; default song 12 | 13 | .include "roomlist.asm" 14 | .include "warplist.asm" 15 | .include "palette.asm" 16 | .include "dialog.asm" 17 | .include "rooms/1.asm" 18 | .include "entity.asm" 19 | 20 | fall_ch1_a: 21 | .byte 32, 32 ; width, height 22 | .byte 1 ; tile to set 23 | .byte chrb_splv1c ; sprite bank, or $00 for none 24 | .byte pal_blue ; palette 25 | .byte 255 ; max Y 26 | .word 0 ; CHR data address 27 | ; sprite data (stored column-wise) 28 | .byte $40,$70 ; col 1 29 | .byte $42,$72 ; col 2 30 | .byte $44,$74 ; col 3 31 | .byte $46,$76 ; col 4 32 | 33 | fall_ch1_b: 34 | .byte 16, 32 ; width, height 35 | .byte 1 ; tile to set 36 | .byte chrb_splv1c ; sprite bank, or $00 for none 37 | .byte pal_blue ; palette 38 | .byte 255 ; max Y 39 | .word 0 ; CHR data address 40 | ; sprite data (stored column-wise) 41 | .byte $40,$60 ; col 1 42 | .byte $46,$66 ; col 2 43 | 44 | fall_ch1_c: 45 | .byte 16, 56+128 ; width, height (+128 for spiked on top) 46 | .byte 1 ; tile to set 47 | .byte chrb_splv1c ; sprite bank, or $00 for none 48 | .byte pal_blue ; palette 49 | .byte 152 ; max Y 50 | .word fall_ch1_c_chr ; CHR data address 51 | ; sprite data (stored column-wise) 52 | .byte $40,$50,$50,$68 ; col 1 53 | .byte $46,$52,$52,$6E ; col 2 54 | 55 | fall_ch1_c_chr: 56 | .byte $C8,$80,$90,$90,$82,$90,$82,$92 57 | .byte $C8,$81,$83,$83,$91,$83,$91,$93 58 | 59 | ; Would be in level1_r8z, but falling blocks are buggy in new format levels and I'm lazy 60 | ;fall_ch1_d: 61 | ; .byte 24, 16 ; width, height 62 | ; .byte 1 ; tile to set 63 | ; .byte chrb_splv1c ; sprite bank, or $00 for none 64 | ; .byte pal_blue ; palette 65 | ; .byte 255 ; max Y 66 | ; .word 0 ; CHR data offset 67 | ; ; sprite data 68 | ; .byte $48 69 | ; .byte $4A 70 | ; .byte $4E 71 | 72 | fall_ch1_d: 73 | .byte 24, 40 ; width, height 74 | .byte 1 ; tile to set 75 | .byte chrb_splv1c ; sprite bank, or $00 for none 76 | .byte pal_blue ; palette 77 | .byte 176 ; max Y 78 | .word fall_ch1_d_chr ; CHR data offset 79 | ; sprite data 80 | .byte $40,$50,$68 81 | .byte $42,$54,$6A 82 | .byte $46,$52,$6E 83 | 84 | fall_ch1_d_chr: 85 | .byte $80,$90,$90,$82,$92 86 | .byte $8B,$84,$84,$9B,$95 87 | .byte $81,$83,$83,$91,$93 88 | 89 | fall_ch1_e: 90 | .byte 16, 24 ; width, height 91 | .byte 1 ; tile to set 92 | .byte chrb_splv1c ; sprite bank, or $00 for none 93 | .byte pal_blue ; palette 94 | .byte 200 ; max Y 95 | .word fall_ch1_e_chr ; CHR data offset 96 | ; sprite data 97 | .byte $40,$68 98 | .byte $46,$6E 99 | 100 | fall_ch1_e_chr: 101 | .byte $80,$90,$92 102 | .byte $81,$83,$93 103 | 104 | fall_ch1_f: 105 | .byte 24, 32+128 ; width, height 106 | .byte 1 ; tile to set 107 | .byte chrb_splv1c ; sprite bank, or $00 for none 108 | .byte pal_blue ; palette 109 | .byte 184 ; max Y 110 | .word fall_ch1_f_chr ; CHR data offset 111 | ; sprite data 112 | .byte $40,$60 113 | .byte $42,$62 114 | .byte $46,$66 115 | 116 | fall_ch1_f_chr: 117 | .byte $C8,$80,$90,$82,$92 118 | .byte $C8,$8B,$84,$9B,$95 119 | .byte $C8,$81,$83,$91,$93 120 | -------------------------------------------------------------------------------- /src/level1/bank_2.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL1C" 4 | .include "music/music.asm" 5 | .include "rooms/2.asm" 6 | -------------------------------------------------------------------------------- /src/level1/bank_3.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL1D" 4 | .include "rooms/3.asm" 5 | -------------------------------------------------------------------------------- /src/level1/dialog.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ch1_ending: 4 | begin 5 | lock_input 6 | 7 | wait 30 8 | walk_player $CE, $A0 9 | 10 | wait 90 11 | face_player 0 12 | 13 | wait 30 14 | 15 | speaker SPK_madeline 16 | expression MAD_distract 17 | dialog2 @d0 18 | 19 | wait 12 20 | walk_player $9C, $A0 21 | face_player 0 22 | wait 42 23 | 24 | trigger 2 25 | wait 84 26 | 27 | ; trigger sleep 28 | wait 240 29 | 30 | ; trigger bird stuff 31 | 32 | wait 30 33 | ; trigger bird cawing 34 | 35 | ; more bird stuff... 36 | speaker SPK_madeline 37 | expression MAD_sad ; deadpan 38 | dialog2 @d1 39 | 40 | wait 18 41 | 42 | finish_level 43 | 44 | line @d0, "Ugh, I'm exhausted." 45 | line @d1, "This might have been a mistake." -------------------------------------------------------------------------------- /src/level1/layout.txt: -------------------------------------------------------------------------------- 1 | level1_r1,0,0 2 | Props,level1_r1,4,0 3 | Spawn,level1_r1,16,160 4 | level1_r2,224,-240 5 | Props,level1_r2,4,0 6 | Spawn,level1_r2,40,168 7 | level1_r3,480,-480 8 | Props,level1_r3,4,0 9 | Spawn,level1_r3,40,176 10 | level1_r4,736,-720 11 | Props,level1_r4,4,0 12 | Spawn,level1_r4,32,168 13 | level1_r3b,864,-960 14 | Props,level1_r3b,4,0 15 | Spawn,level1_r3b,48,160 16 | level1_r5,1024,-1200 17 | Props,level1_r5,4,0 18 | Spawn,level1_r5,32,184 19 | Spawn,level1_r5,304,184 20 | level1_r5z,704,-1200 21 | Props,level1_r5z,0,0 22 | Spawn,level1_r5z,304,176 23 | level1_r6,1280,-1584 24 | Props,level1_r6,4,0 25 | Spawn,level1_r6,32,192 26 | Spawn,level1_r6,336,104 27 | level1_r5a,1344,-1104 28 | Props,level1_r5a,0,0 29 | Spawn,level1_r5a,0,88 30 | level1_r6a,1632,-1584 31 | Props,level1_r6a,6,0 32 | Spawn,level1_r6a,0,104 33 | Spawn,level1_r6a,368,104 34 | level1_r6z,960,-1584 35 | Props,level1_r6z,0,2 36 | Spawn,level1_r6z,304,112 37 | Spawn,level1_r6z,0,120 38 | level1_r6b,2016,-1680 39 | Props,level1_r6b,6,8 40 | Spawn,level1_r6b,0,200 41 | level1_r7zb,640,-1824 42 | Props,level1_r7zb,0,0 43 | Spawn,level1_r7zb,336,176 44 | Spawn,level1_r7zb,40,152 45 | level1_r6zb,640,-1584 46 | Props,level1_r6zb,0,0 47 | Spawn,level1_r6zb,304,120 48 | Spawn,level1_r6zb,24,96 49 | level1_r6c,2336,-1824 50 | Props,level1_r6c,4,0 51 | Spawn,level1_r6c,0,176 52 | level1_rs0,1696,-1856 53 | Props,level1_rs0,0,2 54 | Spawn,level1_rs0,304,200 55 | level1_r7,2560,-2064 56 | Props,level1_r7,5,0 57 | Spawn,level1_r7,48,176 58 | level1_r7z,2016,-1920 59 | Props,level1_r7z,12,1 60 | Spawn,level1_r7z,304,160 61 | Spawn,level1_r7z,224,56 62 | level1_rs1,1376,-2032 63 | Props,level1_rs1,0,0 64 | Spawn,level1_rs1,304,192 65 | Spawn,level1_rs1,48,152 66 | level1_r8,2688,-2304 67 | Props,level1_r8,0,0 68 | Spawn,level1_r8,336,64 69 | Spawn,level1_r8,224,80 70 | Spawn,level1_r8,272,192 71 | Spawn,level1_r8,32,168 72 | PaletteOverride,level1_r8,8,9,2,8,10,2,8,11,2,8,12,2 73 | level1_r8z,2048,-2160 74 | Props,level1_r8z,0,8 75 | Spawn,level1_r8z,304,-48 76 | Spawn,level1_r8z,104,200 77 | level1_rs1a,1056,-2032 78 | Props,level1_rs1a,0,0 79 | Spawn,level1_rs1a,280,112 80 | level1_r7a,2880,-2064 81 | Props,level1_r7a,8,0 82 | Spawn,level1_r7a,40,56 83 | level1_r9z,2688,-2544 84 | Props,level1_r9z,1,8 85 | Spawn,level1_r9z,232,184 86 | level1_r8b,3040,-2336 87 | Props,level1_r8b,4,0 88 | Spawn,level1_r8b,0,96 89 | level1_r8zb,2368,-2336 90 | Props,level1_r8zb,4,2 91 | Spawn,level1_r8zb,304,136 92 | Spawn,level1_r8zb,0,128 93 | level1_r9,3264,-2576 94 | Props,level1_r9,4,0 95 | Spawn,level1_r9,40,184 96 | Spawn,level1_r9,304,72 97 | level1_r9b,3584,-2656 98 | Props,level1_r9b,4,0 99 | Spawn,level1_r9b,0,152 100 | Spawn,level1_r9b,256,32 101 | Spawn,level1_r9b,304,64 102 | level1_r10a,3712,-2896 103 | Props,level1_r10a,8,0 104 | Spawn,level1_r10a,128,192 105 | level1_r9c,3904,-2656 106 | Props,level1_r9c,0,0 107 | Spawn,level1_r9c,0,64 108 | level1_r10,3360,-2896 109 | Props,level1_r10,1,0 110 | Spawn,level1_r10,248,200 111 | Spawn,level1_r10,240,56 112 | Spawn,level1_r10,0,176 113 | Spawn,level1_r10,64,40 114 | level1_r11,3360,-3136 115 | Props,level1_r11,0,0 116 | Spawn,level1_r11,352,208 117 | Spawn,level1_r11,64,208 118 | level1_r10z,3040,-2896 119 | Props,level1_r10z,0,0 120 | Spawn,level1_r10z,0,104 121 | Spawn,level1_r10z,304,176 122 | level1_r12,3424,-3376 123 | Props,level1_r12,4,0 124 | Spawn,level1_r12,24,200 125 | Spawn,level1_r12,400,176 126 | PaletteOverride,level1_r12,5,11,2,5,12,2,5,13,2,11,11,2,12,11,2,11,12,2,12,12,2,11,13,2,12,13,2,6,11,2,7,11,2,6,12,2,7,12,2,6,13,2,7,13,2,6,10,2,7,10,2 127 | level1_r11z,3040,-3136 128 | Props,level1_r11z,4,2 129 | Spawn,level1_r11z,304,160 130 | PaletteOverride,level1_r11z,10,11,3,11,11,3,9,1,3,10,1,3,9,2,3,10,2,3,9,3,3,10,3,3,9,4,3,10,4,3,1,4,3,2,4,3,1,5,3,2,5,3,6,1,2,6,2,2,6,3,2,6,4,2,7,1,2,7,2,2,7,3,2,7,4,2,2,10,2,3,10,2,6,11,2,7,11,2,6,10,2,7,10,2,14,10,2,15,10,2,14,11,2,15,11,2 131 | level1_r10zb,2752,-2896 132 | Props,level1_r10zb,0,0 133 | Spawn,level1_r10zb,272,104 134 | level1_r12a,3840,-3360 135 | Props,level1_r12a,4,0 136 | Spawn,level1_r12a,0,160 137 | level1_r12z,3104,-3504 138 | Props,level1_r12z,0,0 139 | Spawn,level1_r12z,304,160 140 | level1_rend,3840,-3744 141 | Props,level1_rend,4,0 142 | Spawn,level1_rend,72,168 143 | Filler,768,-1312,224,0 144 | Filler,1024,-1664,32,0 145 | Filler,704,-1344,320,64 146 | Filler,608,-1600,0,160 147 | Filler,1024,-1632,256,48 148 | Filler,2320,-1824,0,96 149 | Filler,1360,-1168,0,16 150 | Filler,1376,-1168,0,16 151 | Filler,1344,-1360,64,320 152 | Filler,1264,-1072,0,16 153 | Filler,2288,-1712,48,128 154 | -------------------------------------------------------------------------------- /src/level1/metatile.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; Metatile Data for "Forsaken City" (Level 1) 4 | 5 | ; Metatiles 6 | ; 7 | ; For a single metatile ID, the following properties: 8 | ; - metatiles: The char tiles that make up the visual representation of the metatile 9 | ; - metatile_palette: The palette used for the metatile 10 | ; - metatile_collision: The collision mask for the metatile. 11 | 12 | ; These are the metatiles for the Intro level. 13 | ; Eventually the metatile bank will be swappable with different level banks. 14 | 15 | ;metatiles: 16 | .align $100 17 | .byte $00 ; Air 18 | .byte $60,$64,$70,$74 ; Dirt Corners 19 | .byte $61,$62,$63 ; Dirt Tops 20 | .byte $71,$72,$73 ; Dirt Bottoms 21 | .byte $67,$77,$68,$67 ; Dirt Left 22 | .byte $69,$79,$6A,$7A ; Dirt Right 23 | .byte $6B,$6C,$6D,$6E,$7B,$7C,$7D,$9A ; Dirt Middles 24 | .byte $6F,$78 ; Dirt Left, Right Ends 25 | .byte $80,$81,$92,$93 ; Snow Corners 26 | .byte $8B,$8C,$8D ; Snow Tops 27 | .byte $94,$95,$96 ; Snow Bottoms 28 | .byte $90,$82 ; Snow Left 29 | .byte $91,$83 ; Snow Right 30 | .byte $84,$85,$86,$9E,$8F,$8E,$9B,$9C,$9D ; Snow Middles 31 | .byte $87,$88,$97,$98 ; Snow In-corners 32 | .byte $65,$66,$75,$76 ; Dirt In-corners 33 | .byte $89,$8A,$99 ; Jump Through 34 | .byte $C8 ; Spikes 35 | .byte $C4,$C5,$C6,$C7 ; Grass Decals 36 | .byte $A0,$A4,$B0,$B4 ; Cement Corners 37 | .byte $A5,$A6,$B5,$B6 ; Cement Corners Alt 38 | .byte $A1,$A2,$A3 ; Cement Tops 39 | .byte $B1,$B2,$B3 ; Cement Bottoms 40 | .byte $A9,$B9 ; Cement Left 41 | .byte $AA,$BA ; Cement Right 42 | .byte $AB,$AC,$AD,$AE,$AF,$BB,$BC,$BD,$BE,$BF ; Cement Middles 43 | .byte $A7,$A8,$B7,$B8 ; Cement Corners 44 | .byte $C0,$C1,$C2,$C3 ; Girders 45 | .byte $C9,$CA,$CB ; Spikes 46 | .byte $89,$8A,$99 ; Grey Jump Through 47 | .byte $F4,$F5 ; Memorial 48 | .byte $F8,$D9,$F9,$E7 ; Memorial 49 | .byte $D0,$D1,$D2,$D3 ; Memorial 50 | .byte $E0,$E1,$E2,$E3 ; Memorial 51 | .byte $F6,$D4,$F7 ; Memorial 52 | .byte $F0,$F1,$F2,$F3 ; Memorial 53 | .byte $D5,$D6,$D7,$D8 ; Memorial 54 | .byte $E4,$E5,$E6,$E8,$E9 ; Memorial 55 | .byte $DA,$DB,$DC,$DD ; Campfire 56 | .byte $C8,$C9,$CA,$CB ; Spikes (Blue) 57 | .byte $9F,$CC,$CD,$CE,$CF,$DF ; Snow 58 | ; $99 59 | .byte $21,$04,$20,$24,$02,$22,$01,$05 ; Cassette Blocks 1 (UL UR DL DR U D L R) 60 | .byte $08,$0C,$28,$2C,$0A,$2A,$09,$0D ; Cassette Blocks 2 (UL UR DL DR U D L R) 61 | 62 | ;metatile_info: 63 | .align $100 64 | .byte ct_none ; Air 65 | .res 28, ct_full ; Dirt 66 | .res 27, ct_full ; Snow 67 | .res 4, ct_full ; Dirt 68 | .res 3, ct_jumpthru ; Jump Through 69 | .byte ct_deadlyUP ; Spikes 70 | .res 4, ct_none ; Grass Decals 71 | .res 32, ct_full ; Cement 72 | .res 4, ct_full ; Girder 73 | .byte ct_deadlyRT ; Spikes 74 | .byte ct_deadlyDN ; Spikes 75 | .byte ct_deadlyLT ; Spikes 76 | .res 3, ct_jumpthru ; Grey Jump Through 77 | .res 30, ct_none ; Memorial 78 | .res 4, ct_none ; Campfire 79 | .byte ct_deadlyUP ; Spikes 80 | .byte ct_deadlyRT ; Spikes 81 | .byte ct_deadlyDN ; Spikes 82 | .byte ct_deadlyLT ; Spikes 83 | .res 6, ct_full ; Dirt 84 | .res 8, ct_cass1 ; Cassette Blocks 1 85 | .res 8, ct_cass2 ; Cassette Blocks 1 86 | 87 | .align $100 -------------------------------------------------------------------------------- /src/level1/mpalette.txt: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; note : this file is NOT included for the game! only for my level editor. 4 | metatile_palette: 5 | .byte $0 ; Air 6 | .res 28, $1 ; Dirt 7 | .res 27, $2 ; Snow 8 | .res 4, $1 ; Dirt 9 | .res 3, $1 ; Jump Through 10 | .byte $0 ; Spikes 11 | .res 4, $3 ; Grass Decals 12 | .res 32, $0 ; Cement 13 | .res 4, $0 ; Girder 14 | .res 3, $0 ; Spikes 15 | .res 3, $0 ; Grey Jump Through 16 | .res 30, $0 ; Memorial 17 | .res 4, $1 ; Campfire 18 | .res 4, $2 ; Spikes (Blue) 19 | .res 6, $2 ; Snow -------------------------------------------------------------------------------- /src/level1/music/level1.dmc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/level1/music/level1.dmc -------------------------------------------------------------------------------- /src/level1/palette.asm: -------------------------------------------------------------------------------- 1 | 2 | level1_palette: 3 | .byte $0f,$20,$10,$00 ; grey tiles 4 | .byte $0f,$37,$16,$06 ; brown tiles 5 | .byte $0f,$20,$21,$11 ; blue tiles 6 | .byte $0f,$39,$29,$19 ; green tiles 7 | .byte $0f,$37,$14,$21 ; player sprite colors 8 | -------------------------------------------------------------------------------- /src/level1/room_end.asm: -------------------------------------------------------------------------------- 1 | level1_rEnd_p: 2 | .byte $00,$00,$00,$00,$00,$A0,$08,$00 3 | .byte $00,$00,$00,$00,$00,$60,$22,$02 4 | .byte $00,$00,$00,$00,$00,$90,$AA,$0A 5 | .byte $00,$00,$00,$00,$00,$A0,$0A,$00 6 | .byte $00,$00,$00,$00,$00,$2A,$00,$00 7 | .byte $00,$00,$00,$00,$00,$0A,$00,$00 8 | .byte $00,$00,$00,$00,$00,$8A,$00,$00 9 | .byte $00,$00,$00,$00,$00,$54,$00,$00 10 | .byte $00,$00,$00,$00,$00,$51,$00,$00 11 | .byte $00,$00,$00,$00,$00,$A0,$00,$00 12 | .byte $FF 13 | level1_rEnd_e: 14 | .byte $FF 15 | level1_rEnd_t: 16 | .byte $D6,$21,$2F,$C6,$96,$1E,$36,$86 17 | .byte $96,$00,$22,$33,$85,$97,$23,$2B 18 | .byte $85,$97,$21,$2C,$2C,$33,$30,$2F 19 | .byte $2B,$97,$1E,$29,$A5,$2A,$97,$3D 20 | .byte $C6,$97,$3C,$86,$97,$3E,$86,$97 21 | .byte $01,$28,$27,$27,$27,$28,$27,$97 22 | .byte $22,$2D,$33,$33,$30,$32,$2D,$97 23 | .byte $23,$30,$C5,$97,$21,$2D,$85,$97 24 | .byte $22,$2C,$85,$97,$21,$32,$85,$96 25 | .byte $1D,$37,$C6,$95,$1D,$37,$C7,$92 26 | .byte $A1,$87,$1D,$28,$37,$C8,$8C,$70 27 | .byte $74,$78,$7C,$7F,$A1,$83,$A1,$88 28 | .byte $23,$30,$C9,$8B,$6E,$71,$75,$79 29 | .byte $7D,$80,$A1,$84,$A1,$89,$21,$2D 30 | .byte $89,$8B,$6F,$72,$76,$7A,$7D,$A1 31 | .byte $81,$A1,$85,$82,$33,$89,$8B,$00 32 | .byte $73,$77,$7B,$7E,$A1,$82,$A1,$86 33 | .byte $A1,$8A,$21,$30,$89,$8C,$C6,$A1 34 | .byte $8B,$1E,$36,$2D,$88,$92,$00,$00 35 | .byte $23,$89,$95,$2E,$88,$94,$1E,$36 36 | .byte $88,$94,$00,$21,$31,$87,$95,$1E 37 | .byte $36,$87,$95,$00,$05,$87,$96,$07 38 | .byte $13,$86,$95,$A1,$8C,$07,$14,$86 39 | .byte $95,$A1,$8D,$05,$17,$86,$95,$A1 40 | .byte $8E,$05,$1A,$86,$95,$A1,$8F,$07 41 | .byte $13,$86,$95,$00,$06,$19,$86,$97 42 | .byte $C7,$96,$22,$87,$97,$2E,$86,$96 43 | .byte $23,$2B,$86,$96,$22,$32,$86,$FF 44 | level1_rEnd: 45 | .byte 40, 0, 0 46 | .byte 48, 168 47 | .byte 255, 255, 255, 255 48 | .byte 0, 0, 0, 0 49 | .byte 0 50 | .word level1_rEnd_t 51 | .word level1_rEnd_p 52 | .word level1_rEnd_e 53 | -------------------------------------------------------------------------------- /src/level1/rooms/1.asm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/level1/rooms/1.asm -------------------------------------------------------------------------------- /src/level1/tgroups.txt: -------------------------------------------------------------------------------- 1 | ; BITS: 2 | ; 0 - Up 3 | ; 1 - Down 4 | ; 2 - Left 5 | ; 3 - Right 6 | ; 4 - UpLeft 7 | ; 5 - UpRight 8 | ; 6 - DownLeft 9 | ; 7 - DownRight 10 | ; 11 | ; the bit mask is left to right, so bit 0 corresponds to index 0. 12 | ; 13 | ; - - don't matter 14 | ; 1 - is one 15 | ; 0 - is zero 16 | ; 17 | ; ex. -------- - default mask, -1000000 - up doesn't matter, down must be 1, rest must be zero 18 | 19 | group 1 20 | name DIRT 21 | color $37 22 | -------- $14 23 | 0101---- $01 24 | 0110---- $02 25 | 1001---- $03 26 | 1010---- $04 27 | 0111---- $05 $06 $07 28 | 1011---- $08 $09 $0A 29 | 1101---- $0B $0C $0D $0E 30 | 1110---- $0F $10 $11 $12 31 | 1111---- $13 $14 $15 $16 $17 $18 $19 $1A 32 | 1111---0 $38 33 | 1111--0- $39 34 | 1111-0-- $3A 35 | 11110--- $3B 36 | 0001---- $1B 37 | 0010---- $1C 38 | 39 | 40 | group 2 41 | name SNOW 42 | color $21 43 | -------- $2B 44 | 0101---- $1D 45 | 0110---- $1E 46 | 1001---- $1F 47 | 1010---- $20 48 | 0111---- $21 $22 $23 49 | 1011---- $24 $25 $26 50 | 1101---- $27 $28 51 | 1110---- $29 $2A 52 | 1111---- $2B $2C $2D $2E $2F $30 $31 $32 $33 53 | 1111---0 $34 54 | 1111--0- $35 55 | 1111-0-- $36 56 | 11110--- $37 57 | 0001---- $1D 58 | 0010---- $1E 59 | 60 | group 3 61 | name CEMENT 62 | color $20 63 | -------- $56 64 | 0101---- $44 $48 65 | 0110---- $45 $49 66 | 1001---- $46 $4A 67 | 1010---- $47 $4B 68 | 0111---- $4C $4D $4E 69 | 1011---- $4F $50 $51 70 | 1101---- $52 $53 71 | 1110---- $54 $55 72 | 1111---- $56 $57 $58 $59 $5A $5B $5C $5D $5E $5F 73 | 1111---0 $60 74 | 1111--0- $61 75 | 1111-0-- $62 76 | 11110--- $63 77 | 0001---- $44 78 | 0010---- $45 79 | 80 | group 4 81 | name GIRDER 82 | color $10 83 | -------- $64 84 | 11------ $65 85 | 0011---- $66 86 | -------------------------------------------------------------------------------- /src/level2/bank_0.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL2A" 4 | .include "rooms/0.asm" 5 | 6 | .include "payphone2.asm" 7 | -------------------------------------------------------------------------------- /src/level2/bank_1.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL2B" 4 | .include "metatile.asm" 5 | 6 | music_data_ch2_dmc: 7 | .incbin "music/level2.dmc" 8 | 9 | level2_music: 10 | .word music_data_ch2 ; song list 11 | .byte $00 ; default song 12 | 13 | .include "roomlist.asm" 14 | .include "rooms/1.asm" 15 | .include "warplist.asm" 16 | .include "palette.asm" 17 | .include "structs.asm" 18 | .include "dialog.asm" 19 | .include "entity.asm" 20 | .include "payphone.asm" 21 | 22 | level2_mirror_frames_lo: .byte level2_mirror_frame_0, >level2_mirror_frame_1, >level2_mirror_frame_2, >level2_mirror_frame_3, >level2_mirror_frame_4, >level2_mirror_frame_5 24 | 25 | level2_alt_palette: 26 | .byte $0f,$30,$1c,$0c 27 | .byte $0f,$37,$16,$06 28 | .byte $0f,$30,$21,$11 29 | .byte $0f,$30,$10,$00 30 | .byte $0f 31 | 32 | lsfx_ntsc_shatter: 33 | .byte $87,$46,$88,$01,$86,$8f,$8a,$01,$89,$34,$01,$87,$60,$8a,$02,$01 34 | .byte $87,$79,$8a,$03,$01,$87,$93,$8a,$04,$01,$87,$ac,$8a,$05,$01,$87 35 | .byte $c6,$8a,$06,$01,$87,$df,$8a,$07,$01,$87,$f9,$8a,$08,$01,$87,$12 36 | .byte $88,$02,$8a,$09,$01,$87,$2c,$8a,$0a,$01,$87,$45,$8a,$0b,$01,$87 37 | .byte $5c,$8a,$0c,$01,$87,$60,$88,$03,$8a,$84,$89,$3e,$01,$87,$6a,$8a 38 | .byte $05,$01,$87,$74,$8a,$85,$01,$87,$7e,$8a,$04,$89,$3d,$01,$87,$88 39 | .byte $8a,$85,$01,$87,$92,$8a,$05,$01,$87,$9c,$8a,$84,$89,$3c,$01,$87 40 | .byte $a6,$8a,$05,$01,$87,$b0,$8a,$85,$01,$87,$ba,$8a,$04,$89,$3b,$01 41 | .byte $87,$c4,$8a,$85,$01,$87,$ce,$8a,$05,$01,$87,$d8,$8a,$84,$89,$3a 42 | .byte $01,$87,$e2,$8a,$05,$01,$87,$ec,$8a,$85,$01,$87,$f6,$8a,$04,$01 43 | .byte $87,$00,$88,$04,$8a,$85,$01,$87,$0a,$8a,$05,$89,$33,$01,$87,$14 44 | .byte $8a,$84,$89,$35,$01,$87,$1e,$8a,$05,$01,$87,$28,$8a,$85,$01,$87 45 | .byte $32,$8a,$04,$01,$87,$3c,$8a,$85,$01,$87,$46,$8a,$05,$01,$87,$50 46 | .byte $8a,$84,$01,$87,$5a,$8a,$05,$01,$87,$64,$8a,$85,$01,$87,$6e,$8a 47 | .byte $04,$01,$87,$74,$8a,$85,$01,$8a,$05,$01,$86,$80,$8a,$84,$89,$32 48 | .byte $01,$8a,$05,$01,$8a,$85,$01,$8a,$04,$01,$8a,$85,$01,$8a,$05,$01 49 | .byte $8a,$84,$01,$8a,$05,$01,$8a,$85,$01,$8a,$04,$01,$8a,$85,$01,$8a 50 | .byte $05,$01,$8a,$84,$89,$31,$01,$8a,$05,$01,$8a,$85,$01,$8a,$04,$01 51 | .byte $8a,$85,$01,$8a,$05,$01,$8a,$84,$01,$8a,$05,$01,$8a,$85,$01,$8a 52 | .byte $04,$01,$8a,$85,$01,$8a,$05,$01,$8a,$84,$01,$8a,$05,$01,$8a,$85 53 | .byte $01,$8a,$04,$01,$8a,$85,$01,$8a,$05,$00 54 | 55 | level2_sfx_shatter: 56 | lda #8 57 | ldx #FAMISTUDIO_SFX_CH0 58 | jmp famistudio_sfx_play 59 | 60 | level2_db_opening_rows_lo: 61 | .byte level2_db_opening_row_6 73 | .byte >level2_db_opening_row_5 74 | .byte >level2_db_opening_row_4 75 | .byte >level2_db_opening_row_3 76 | .byte >level2_db_opening_row_2 77 | .byte >level2_db_opening_row_1 78 | .byte >level2_db_opening_empty 79 | .byte >level2_db_opening_empty 80 | .byte >level2_db_opening_empty 81 | .byte >level2_db_opening_empty 82 | level2_db_closing_rows_lo: 83 | .byte level2_db_closing_row_1 95 | .byte >level2_db_closing_row_2 96 | .byte >level2_db_closing_row_3 97 | .byte >level2_db_closing_row_4 98 | .byte >level2_db_opening_empty 99 | .byte >level2_db_opening_empty 100 | .byte >level2_db_opening_empty 101 | .byte >level2_db_opening_empty 102 | .byte >level2_db_opening_empty 103 | .byte >level2_db_opening_empty 104 | 105 | fall_ch2_a: 106 | .byte 24, 16 ; width, height 107 | .byte 1 ; tile to set 108 | .byte chrb_splvl2 ; sprite bank, or $00 for none 109 | .byte pal_stone ; palette 110 | .byte 176 ; max Y 111 | .word fall_ch2_a_chr ; CHR data offset 112 | ; sprite data 113 | .byte $60,$62,$64 114 | 115 | fall_ch2_a_chr: 116 | .byte $36,$50 117 | .byte $43,$53 118 | .byte $44,$39 119 | 120 | fall_ch2_b: 121 | .byte 40, 56 ; width, height 122 | .byte 2 ; tile to set 123 | .byte 0 ; sprite bank, or $00 for none 124 | .byte pal_tower ; palette 125 | .byte 176 ; max Y 126 | .word fall_ch2_b_chr ; CHR data offset 127 | ; sprite data 128 | .byte $03,$0B,$0B,$1F 129 | .byte $05,$0D,$0D,$3D 130 | .byte $07,$01,$01,$3F 131 | .byte $05,$1B,$1B,$3D 132 | .byte $09,$1D,$1D,$2B 133 | 134 | fall_ch2_b_chr: 135 | .byte $A5,$A9,$B9,$A9,$B9,$A9,$B5 136 | .byte $A2,$AB,$BC,$BD,$BC,$BD,$B1 137 | .byte $A2,$AD,$00,$00,$00,$BC,$B3 138 | .byte $A2,$AB,$BD,$BC,$BD,$BC,$B1 139 | .byte $A6,$BA,$BA,$AA,$BA,$AA,$B6 140 | -------------------------------------------------------------------------------- /src/level2/bank_2.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_LVL2C" 4 | .include "rooms/2.asm" -------------------------------------------------------------------------------- /src/level2/bank_3.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | .segment "PRG_LVL2D" 4 | .include "rooms/3.asm" 5 | 6 | level2_mirror_frame_0: 7 | .byte $61,$71,$72,$79 8 | .byte $62,$72,$73,$7A 9 | .byte $63,$73,$74,$7B 10 | .byte $64,$74,$75,$7C 11 | .byte $65,$75,$6D,$7D 12 | .byte $66,$76,$6E,$7E 13 | level2_mirror_frame_1: 14 | .byte $61,$71,$72,$5F 15 | .byte $62,$72,$73,$7A 16 | .byte $63,$73,$74,$7B 17 | .byte $64,$4F,$75,$7C 18 | .byte $65,$75,$6D,$7D 19 | .byte $66,$76,$6E,$7E 20 | level2_mirror_frame_2: 21 | .byte $61,$71,$72,$5F 22 | .byte $62,$72,$16,$06 23 | .byte $63,$73,$27,$7B 24 | .byte $64,$4F,$28,$7C 25 | .byte $65,$75,$6D,$7D 26 | .byte $66,$76,$6E,$7E 27 | level2_mirror_frame_3: 28 | .byte $61,$01,$01,$01 29 | .byte $69,$01,$01,$01 30 | .byte $6A,$01,$01,$01 31 | .byte $6B,$01,$01,$01 32 | .byte $6C,$01,$01,$01 33 | .byte $66,$01,$01,$01 34 | level2_mirror_frame_4: 35 | .byte $61,$01,$01,$26 36 | .byte $69,$01,$17,$01 37 | .byte $6A,$02,$18,$01 38 | .byte $6B,$03,$19,$29 39 | .byte $6C,$01,$01,$01 40 | .byte $66,$01,$01,$01 41 | level2_mirror_frame_5: 42 | .byte $04,$0A,$1A,$2A 43 | .byte $05,$0B,$1B,$2B 44 | .byte $63,$0C,$1C,$2C 45 | .byte $07,$0D,$1D,$2D 46 | .byte $08,$0E,$1E,$2E 47 | .byte $09,$0F,$1F,$2F 48 | 49 | level2_db_opening_row_1: .byte $41,$42,$41,$42,$44,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$36,$42 50 | level2_db_opening_row_2: .byte $4C,$5B,$4D,$5D,$55,$42,$44,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$47,$5C 51 | level2_db_opening_row_3: .byte $00,$00,$00,$00,$00,$4D,$58,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$42,$43,$56,$00 52 | level2_db_opening_row_4: .byte $00,$00,$00,$00,$00,$5B,$57,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$56,$5C,$5D,$00,$00 53 | level2_db_opening_row_5: .byte $00,$00,$00,$00,$00,$00,$55,$42,$43,$41,$42,$37,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$56,$4C,$5B,$00,$00,$00,$00,$00 54 | level2_db_opening_row_6: .byte $00,$00,$00,$00,$00,$00,$00,$5D,$5C,$4C,$4D,$55,$43,$41,$44,$F8,$D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF,$FD,$49,$5C,$4E,$00,$00,$00,$00,$00,$00,$00,$00 55 | level2_db_closing_row_1: .byte $00,$00,$00,$4B,$57,$00,$00,$00,$00,$00,$00,$36,$42,$42,$41,$41,$41,$41,$42,$42,$42,$43,$43,$42,$42,$43,$41,$42,$44,$00,$00,$47,$4C,$00,$00,$00 56 | level2_db_closing_row_2: .byte $00,$00,$00,$4C,$58,$00,$00,$00,$40,$41,$41,$56,$5C,$5D,$5C,$4D,$4C,$5E,$5B,$4D,$4D,$4C,$5C,$4C,$5E,$5D,$4C,$4D,$55,$43,$41,$56,$00,$00,$00,$00 57 | level2_db_closing_row_3: .byte $00,$00,$00,$00,$55,$41,$42,$43,$56,$5D,$4B,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$4C,$5E,$00,$00,$00,$00,$00 58 | level2_db_closing_row_4: .byte $00,$00,$00,$00,$00,$5E,$5C,$4D,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 59 | level2_db_opening_empty: .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 60 | 61 | ; would move to bank_3.asm, but doesn't work, since $26 (38) bytes isn't enough (we need $30 or 48) 62 | level2_s_mirror_offsets: 63 | .byte 0, 5, 10, 15, 20, 25, 30, 35 64 | 65 | level2_s_mirror: 66 | .byte $00,$60,$70,$68,$78 67 | .byte $3A,$61,$71,$72,$79 68 | .byte $3B,$62,$72,$73,$7A 69 | .byte $3C,$63,$73,$74,$7B 70 | .byte $3D,$64,$74,$75,$7C 71 | .byte $3E,$65,$75,$6D,$7D 72 | .byte $3F,$66,$76,$6E,$7E 73 | .byte $00,$67,$77,$6F,$7F 74 | 75 | .proc level2_revealdb_row 76 | lda roombeglo2 77 | tax 78 | sta temp11 79 | clc 80 | adc #36 ; the other end 81 | and #$1F ; get its X in nametable coordinates 82 | sta wrcountHR2 ; that'll be how many bytes we need to write 83 | 84 | lda #36 85 | sec 86 | sbc wrcountHR2 87 | sta wrcountHR1 88 | 89 | ; calculate the ppu addresses we need to write to 90 | jsr h_calcppuaddr 91 | 92 | lda clearpalo 93 | sta ppuaddrHR1 94 | and #%11100000 95 | sta ppuaddrHR2 96 | 97 | lda clearpahi 98 | sta ppuaddrHR1+1 99 | eor #$04 100 | sta ppuaddrHR2+1 101 | 102 | ldy #0 103 | sty wrcountHR3 104 | sty wrcountHP1 105 | sty wrcountHP2 106 | 107 | lda temp11 108 | and #$1F 109 | tax 110 | @writeLoop: 111 | lda (setdataaddr), y 112 | cpx #32 113 | bcs @writeOtherHalf 114 | sta temprow1, y 115 | inx 116 | iny 117 | cpy #36 118 | bne @writeLoop 119 | beq @endWriteLoop 120 | 121 | @writeOtherHalf: 122 | sta temprow2-32, x 123 | inx 124 | iny 125 | cpy #36 126 | bne @writeLoop 127 | 128 | @endWriteLoop: 129 | lda nmictrl 130 | ora #nc_flushrow 131 | sta nmictrl 132 | 133 | ldx temp1 134 | rts 135 | .endproc 136 | 137 | .proc level2_revealdb_row2 138 | lda temp9 139 | ldx temp10 140 | ldy temp11 141 | jmp level2_revealdb_row 142 | .endproc 143 | -------------------------------------------------------------------------------- /src/level2/bank_4.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | .segment "PRG_LVL2E" 4 | .include "rooms/4.asm" 5 | .include "music/level2.asm" 6 | -------------------------------------------------------------------------------- /src/level2/bank_5.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | .segment "PRG_LVL2F" 4 | 5 | .include "rooms/5.asm" 6 | ; level2_start is located here, so also add the memorial 7 | level2_s_memorial: 8 | .byte $00,$70,$64,$74,$68,$09,$19,$78 9 | .byte $7E,$71,$65,$75,$69,$0A,$1A,$79 10 | .byte $7F,$72,$66,$76,$69,$0B,$1B,$79 11 | .byte $00,$73,$67,$77,$6A,$0C,$1C,$7A 12 | 13 | ; level2_end_chase is located here, so also add the info kiosk 14 | level2_s_info_kiosk_offsets: 15 | .byte 0, 9, 18, 27, 36, 45, 54, 63, 72, 81 16 | 17 | level2_s_info_kiosk: 18 | .byte $00,$00,$00,$14,$39,$50,$49,$49,$3A 19 | .byte $00,$00,$00,$15,$40,$51,$4A,$5A,$3B 20 | .byte $10,$20,$30,$16,$41,$52,$00,$5B,$3C 21 | .byte $11,$21,$31,$17,$42,$52,$00,$5B,$3D 22 | .byte $12,$22,$32,$18,$43,$53,$00,$5B,$3E 23 | .byte $13,$23,$33,$26,$44,$54,$4B,$5C,$3C 24 | .byte $00,$00,$34,$27,$45,$55,$4C,$5D,$3F 25 | .byte $00,$00,$35,$28,$46,$56,$4D,$5E,$2A 26 | .byte $00,$24,$36,$38,$47,$57,$4E,$29,$2B ;done 27 | .byte $00,$25,$00,$00,$48,$58,$59,$59,$4F 28 | 29 | .include "level2/chaser.asm" 30 | -------------------------------------------------------------------------------- /src/level2/metatile.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024-2025 iProgramInCpp 2 | 3 | ; Metatile Data for "Old Site" (Level 2) 4 | 5 | ; Metatiles 6 | ; 7 | ; For a single metatile ID, the following properties: 8 | ; - metatiles: The char tiles that make up the visual representation of the metatile 9 | ; - metatile_palette: The palette used for the metatile 10 | ; - metatile_collision: The collision mask for the metatile. 11 | 12 | ; These are the metatiles for the Intro level. 13 | ; Eventually the metatile bank will be swappable with different level banks. 14 | 15 | ;metatiles: 16 | .align $100 17 | .byte $00 ; Air 18 | .byte $60,$64,$70,$74 ; Dirt Corners 19 | .byte $61,$62,$63 ; Dirt Tops 20 | .byte $71,$72,$73 ; Dirt Bottoms 21 | .byte $67,$77,$68,$67 ; Dirt Left 22 | .byte $69,$79,$6A,$7A ; Dirt Right 23 | .byte $6B,$6C,$6D,$6E,$7B,$7C,$7D,$9A ; Dirt Middles 24 | .byte $6F,$78 ; Dirt Left, Right Ends 25 | .byte $80,$84,$90,$94 ; Snow Corners 26 | .byte $81,$82,$83 ; Snow Tops 27 | .byte $91,$92,$93 ; Snow Bottoms 28 | .byte $87,$97 ; Snow Left 29 | .byte $88,$98 ; Snow Right 30 | .byte $8B,$8C,$8D,$8E,$8F,$9B,$9C,$9D,$9E ; Snow Middles 31 | .byte $85,$86,$95,$96 ; Snow In-corners 32 | .byte $65,$66,$75,$76 ; Dirt In-corners 33 | .byte $89,$8A,$99 ; Jump Through 34 | .byte $C8 ; Spikes 35 | .byte $CC,$CD,$CE,$CF ; Snow Connections 36 | .byte $A0,$A4,$B0,$B4 ; Tower Corners 37 | .byte $A5,$A6,$B5,$B6 ; Tower Corners Alt 38 | .byte $A1,$A2,$A3 ; Tower Tops 39 | .byte $B1,$B2,$B3 ; Tower Bottoms 40 | .byte $A9,$B9 ; Tower Left 41 | .byte $AA,$BA ; Tower Right 42 | .byte $AB,$AC,$AD,$AE,$AF,$BB,$BC,$BD 43 | .byte $BE ; Tower Connection 44 | .byte $BF ; Snow Connection 45 | .byte $A7,$A8,$B7,$B8 ; Tower Corners 46 | .byte $16,$26,$17,$27 ; Tower R, L, UD, LR 47 | .byte $C9,$CA,$CB ; Spikes 48 | .byte $89,$8A,$99 ; Grey Jump Through 49 | .byte $0E ; Memorial 50 | .byte $0F ; Memorial 51 | .byte $2C,$2D,$2E,$2F ; Campfire 52 | .byte $C8,$C9,$CA,$CB ; Spikes (Blue) 53 | .byte $C0,$C1,$C2,$C3,$D0,$D1,$D2,$D3,$E0,$E1,$E2,$E3,$F0,$F1,$F2,$F3 ; Dream Block Middles 54 | .byte $C4,$D4,$E4,$F4,$C6,$D6,$E6,$F6 ; Dream Block Left 55 | .byte $C5,$D5,$E5,$F5,$C7,$D7,$E7,$F7 ; Dream Block Right 56 | .byte $D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF ; Dream Block Top 57 | .byte $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; Dream Block Bottom 58 | .byte $F8,$FC,$F9,$FD,$FA,$FE,$FB,$FF ; Dream Block Corners 59 | .byte $36,$40,$37,$44,$38,$50,$39,$54 ; Stone Corners - $B0 60 | .byte $41,$42,$43 ; Stone Tops $B8 61 | .byte $51,$52,$53 ; Stone Bottoms $BB 62 | .byte $47,$48,$49,$4A ; Stone Left $BE 63 | .byte $57,$58,$59,$5A ; Stone Right $C2 64 | .byte $45,$46,$55,$56 ; Stone In-corners $C6 65 | .byte $10,$11,$12 ; Stone Pillar $CA 66 | .byte $20,$21,$22 ; Stone Pillar Top $CD 67 | .byte $30,$31,$32 ; Stone Pillar Bottom $D0 68 | .byte $13,$14,$15 ; Stone Bar Left $D3 69 | .byte $23,$24,$25 ; Stone Bar Right $D6 70 | .byte $33,$34,$35 ; Stone Bar $D9 71 | .byte $4B,$4C,$4D,$4E,$5B,$5C,$5D,$5E ; Stone Middles $DC 72 | .byte $18,$28 ; Tower U, D $E4 73 | .byte $3A ; Snow LR $E6 74 | .byte $C8,$C9,$CA,$CB ; Spikes (Red) 75 | .byte $89,$8A,$99 ; Purp Jump Through 76 | .byte $00 ; No BG Effects 77 | .byte $6F ; Memorial Compressed 78 | .byte $6E ; Info Kiosk Compressed 79 | .byte $6E ; Mirror Compressed 80 | .byte $00 ; Barrier 81 | ; $F3 (like 12 blocks more UL UR DL DR U D - horz only) 82 | .byte $A1,$84,$A0,$A4,$82,$A2 ; Cassette Blocks 1 (UL UR DL DR U D) 83 | .byte $88,$8C,$A8,$AC,$8A,$AA ; Cassette Blocks 2 (UL UR DL DR U D) 84 | 85 | ;metatile_info: 86 | .align $100 87 | .byte ct_none ; Air 88 | .res 18, ct_full ; Dirt 89 | .res 8, ct_none ; Dirt Middles 90 | .res 2, ct_full ; Dirt 91 | .res 27, ct_full ; Snow 92 | .res 4, ct_full ; Dirt 93 | .res 3, ct_jumpthru ; Jump Through 94 | .byte ct_deadlyUP ; Spikes 95 | .res 4, ct_full ; Snow Conns 96 | .res 36, ct_full ; Tower (27) + SnowConn (1) + Tower (8) 97 | .byte ct_deadlyRT ; Spikes 98 | .byte ct_deadlyDN ; Spikes 99 | .byte ct_deadlyLT ; Spikes 100 | .res 3, ct_jumpthru ; Grey Jump Through 101 | .res 2, ct_none ; Memorial 102 | .res 4, ct_none ; Campfire 103 | .byte ct_deadlyUP ; Spikes (Blue) 104 | .byte ct_deadlyRT ; Spikes (Blue) 105 | .byte ct_deadlyDN ; Spikes (Blue) 106 | .byte ct_deadlyLT ; Spikes (Blue) 107 | .res 56, ct_dream ; Dream Block 108 | .res 44, ct_full ; Stone 109 | .res 8, ct_none ; Stone Middles 110 | .res 3, ct_full ; Tower + Snow 111 | .byte ct_deadlyUP ; Spikes (Red) 112 | .byte ct_deadlyRT ; Spikes (Red) 113 | .byte ct_deadlyDN ; Spikes (Red) 114 | .byte ct_deadlyLT ; Spikes (Red) 115 | .res 3, ct_jumpthru ; Purp Jump Through 116 | .res 4, ct_none ; No BG Effects + Compressed Structures 117 | .byte ct_full ; Barrier 118 | .res 6, ct_cass1 ; Cassette Blocks 1 119 | .res 6, ct_cass2 ; Cassette Blocks 2 120 | 121 | .align $100 -------------------------------------------------------------------------------- /src/level2/mpalette.txt: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; note : this file is NOT included for the game! only for my level editor. 4 | metatile_palette: 5 | .byte $0 ; Air 6 | .res 28, $1 ; Dirt 7 | .res 27, $2 ; Snow 8 | .res 4, $1 ; Dirt 9 | .res 3, $1 ; Jump Through 10 | .byte $0 ; Spikes 11 | .res 4, $2 ; Snow Connection 12 | .res 27, $0 ; Tower 13 | .res 1, $2 ; Snow Connection 14 | .res 8, $0 ; Tower 15 | .res 3, $0 ; Spikes 16 | .res 3, $0 ; Grey Jump Through 17 | .res 2, $3 ; Memorial 18 | .res 4, $1 ; Campfire 19 | .res 4, $2 ; Spikes (Blue) 20 | .res 56, $4 ; Dream Block 21 | .res 52, $3 ; Stone 22 | .res 2, $0 ; Tower 23 | .res 1, $2 ; Snow 24 | .res 4, $3 ; Spikes (Purp) 25 | .res 3, $3 ; Jumpthroughs (Purp) 26 | .res 1, $0 ; Barrier 27 | .res 1, $3 ; Compressed Memorial 28 | .res 1, $2 ; Compressed Info Kiosk 29 | .res 1, $2 ; Compressed Mirror -------------------------------------------------------------------------------- /src/level2/music/level2.dmc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/level2/music/level2.dmc -------------------------------------------------------------------------------- /src/level2/palette.asm: -------------------------------------------------------------------------------- 1 | 2 | level2_palette: 3 | .byte $0f,$30,$1C,$0C ; grey tiles 4 | .byte $0f,$30,$16,$06 ; brown tiles 5 | .byte $0f,$30,$21,$11 ; blue tiles 6 | .byte $0f,$30,$23,$03 ; purple tiles 7 | .byte $0f,$37,$14,$21 ; player sprite colors -------------------------------------------------------------------------------- /src/level2/rooms/1.asm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iProgramMC/CelesteNES/1b3c73e399d6809298ee77e15fe9c3ec3807fcca/src/level2/rooms/1.asm -------------------------------------------------------------------------------- /src/level2/structs.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; Pre-built structures created using one tile type. Not actually 4 | ; any kind of "struct" object type like you might think. 5 | 6 | ; ** SUBROUTINE: level2_struct_detour 7 | ; desc: Called by h_gener_col_r to generate a tile for a structure, based on the 8 | ; chosen X/Y coordinate. Done this way because we do not support more than 9 | ; 256 metatiles. 10 | ; 11 | ; parameters: 12 | ; X register - The tile used 13 | ; (ntwrhead - roombeglo2) & 0x3F - The X position 14 | ; Y register - The Y position 15 | ; 16 | ; returns: A register - The CHR tile to use 17 | ; 18 | ; note: MUST NOT CLOBBER THE Y REGISTER 19 | .proc level2_struct_detour 20 | lda ntwrhead 21 | 22 | gotX: 23 | sec 24 | sbc roombeglo2 25 | and #$3F 26 | 27 | cpx #$EF ; check if it's the memorial 28 | beq @memorial 29 | cpx #$F1 ; check if it's the mirror 30 | beq @mirror 31 | 32 | ; info kiosk starts at tile 20,13 33 | sec 34 | sbc #20 35 | tax 36 | tya 37 | sec 38 | sbc #13 39 | clc 40 | adc level2_s_info_kiosk_offsets, x 41 | tax 42 | lda level2_s_info_kiosk, x 43 | rts 44 | 45 | @mirror: 46 | ; mirror starts at tile 16,15 47 | sec 48 | sbc #16 49 | tax 50 | tya 51 | sec 52 | sbc #15 53 | clc 54 | adc level2_s_mirror_offsets, x 55 | tax 56 | lda level2_s_mirror, x 57 | rts 58 | 59 | @memorial: 60 | ; the memorial starts at tile 18,11 61 | sec 62 | sbc #18 63 | and #3 64 | asl 65 | asl 66 | asl 67 | sta temp11 68 | 69 | tya 70 | sec 71 | sbc #11 72 | and #7 73 | ora temp11 74 | tax 75 | lda level2_s_memorial, x 76 | rts 77 | .endproc 78 | 79 | ; ** SUBROUTINE: level2_struct_detour2 80 | ; desc: Jumps to the middle of level2_struct_detour after calculating the X coordinate. 81 | ; This is used by h_gener_row_u. 82 | ; 83 | ; parameters: 84 | ; X register - The tile used 85 | ; Y register - The Y position 86 | ; 87 | ; returns: A register - the CHR tile to use. 88 | .proc level2_struct_detour2 89 | lda ntwrhead 90 | clc 91 | adc temp1 92 | and #$3F 93 | jmp level2_struct_detour::gotX 94 | .endproc 95 | 96 | ; ** SUBROUTINE: level2_struct_detour2 97 | ; desc: Jumps to the middle of level2_struct_detour after calculating the X coordinate. 98 | ; This is used by h_gener_row_u_nice. 99 | ; 100 | ; parameters: 101 | ; X register - The tile used 102 | ; Y register - The Y position 103 | ; 104 | ; returns: A register - the CHR tile to use. 105 | .proc level2_struct_detour3 106 | lda temp1 107 | and #$3F 108 | jmp level2_struct_detour::gotX 109 | .endproc 110 | -------------------------------------------------------------------------------- /src/level2/tgroups.txt: -------------------------------------------------------------------------------- 1 | ; BITS: 2 | ; 0 - Up 3 | ; 1 - Down 4 | ; 2 - Left 5 | ; 3 - Right 6 | ; 4 - UpLeft 7 | ; 5 - UpRight 8 | ; 6 - DownLeft 9 | ; 7 - DownRight 10 | ; 11 | ; the bit mask is left to right, so bit 0 corresponds to index 0. 12 | ; 13 | ; - - don't matter 14 | ; 1 - is one 15 | ; 0 - is zero 16 | ; 17 | ; ex. -------- - default mask, -1000000 - up doesn't matter, down must be 1, rest must be zero 18 | 19 | group 1 20 | name DIRT 21 | color $37 22 | -------- $14 23 | 0101---- $01 24 | 0110---- $02 25 | 1001---- $03 26 | 1010---- $04 27 | 0111---- $05 $06 $07 28 | 1011---- $08 $09 $0A 29 | 1101---- $0B $0C $0D $0E 30 | 1110---- $0F $10 $11 $12 31 | 1111---- $13 $14 $15 $16 $17 $18 $19 $1A 32 | 1111---0 $38 33 | 1111--0- $39 34 | 1111-0-- $3A 35 | 11110--- $3B 36 | 0001---- $1B 37 | 0010---- $1C 38 | 39 | 40 | group 2 41 | name SNOW 42 | color $21 43 | -------- $2B 44 | 0101---- $1D 45 | 0110---- $1E 46 | 1001---- $1F 47 | 1010---- $20 48 | 0111---- $21 $22 $23 49 | 1011---- $24 $25 $26 50 | 1101---- $27 $28 51 | 1110---- $29 $2A 52 | 1111---- $2B $2C $2D $2E $2F $30 $31 $32 $33 53 | 1111---0 $34 54 | 1111--0- $35 55 | 1111-0-- $36 56 | 11110--- $37 57 | 0001---- $40 58 | 0010---- $41 59 | 0011---- $E6 60 | 1100---- $42 61 | 0100---- $43 62 | 1000---- $5F 63 | 64 | group 3 65 | name TOWER 66 | color $20 67 | -------- $56 68 | 0101---- $44 $48 69 | 0110---- $45 $49 70 | 1001---- $46 $4A 71 | 1010---- $47 $4B 72 | 0111---- $4C $4D $4E 73 | 1011---- $4F $50 $51 74 | 1101---- $52 $53 75 | 1110---- $54 $55 76 | 1111---- $56 $57 $58 $59 $5A $5B $5C $5D $00 $00 $00 77 | 1111---0 $60 78 | 1111--0- $61 79 | 1111-0-- $62 80 | 11110--- $63 81 | 0001---- $64 82 | 0010---- $65 83 | 1100---- $66 84 | 0011---- $67 $E5 85 | 0100---- $E4 86 | 1000---- $5E 87 | 88 | group 4 89 | name DREAM 90 | color $14 91 | -------- $A4 92 | 0101---- $A8 $A9 93 | 0110---- $AA $AB 94 | 1001---- $AC $AD 95 | 1010---- $AE $AF 96 | 0111---- $98 $99 $9A $9B $9C $9D $9E $9F 97 | 1011---- $A0 $A1 $A2 $A3 $A4 $A5 $A6 $A7 98 | 1101---- $88 $89 $8A $8B $8C $8D $8E $8F 99 | 1110---- $90 $91 $92 $93 $94 $95 $96 $97 100 | 1111---- $78 $79 $7A $7B $7C $7D $7E $7F $80 $81 $82 $83 $84 $85 $86 $87 101 | 102 | group 5 103 | name STONE 104 | color $15 105 | -------- $00 106 | 0101---- $B0 $B1 107 | 0110---- $B2 $B3 108 | 1001---- $B4 $B5 109 | 1010---- $B6 $B7 110 | 0111---- $B8 $B9 $BA 111 | 1011---- $BB $BC $BD 112 | 1101---- $BE $BF $C0 $C1 113 | 1110---- $C2 $C3 $C4 $C5 114 | 1111---- $DC $DD $DE $DF $E0 $E1 $E2 $E3 115 | 1111---0 $C6 116 | 1111--0- $C7 117 | 1111-0-- $C8 118 | 11110--- $C9 119 | 0001---- $D3 $D4 $D5 120 | 0010---- $D6 $D7 $D8 121 | 0011---- $D9 $DA $DB 122 | 0100---- $CD $CE $CF 123 | 1000---- $D0 $D1 $D2 124 | 1100---- $CA $CB $CC 125 | -------------------------------------------------------------------------------- /src/level3/bank_0.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | .segment "PRG_LVL3A" 4 | .include "rooms/0.asm" 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/level3/bank_1.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | .segment "PRG_LVL3B" 4 | .include "metatile.asm" 5 | .include "roomlist.asm" 6 | .include "warplist.asm" 7 | .include "palette.asm" 8 | .include "testmusic.asm" 9 | .include "rooms/1.asm" 10 | .include "entity.asm" 11 | 12 | level3_music: 13 | .word music_data_ch3 14 | .byte $00 15 | -------------------------------------------------------------------------------- /src/level3/layout.txt: -------------------------------------------------------------------------------- 1 | level3_s0,0,112 2 | Props,level3_s0,0,0 3 | Spawn,level3_s0,16,144 4 | Spawn,level3_s0,304,144 5 | level3_s1,320,112 6 | Props,level3_s1,0,0 7 | Spawn,level3_s1,0,144 8 | Spawn,level3_s1,400,144 9 | PaletteOverride,level3_s1,12,12,2,13,12,2,12,13,2,13,13,2 10 | NiceWarp,level3_s1,level3_s1u 11 | level3_s1u,320,-128 12 | Props,level3_s1u,0,0 13 | Spawn,level3_s1u,400,184 14 | NiceWarp,level3_s1u,level3_s1 15 | level3_s2,736,112 16 | Props,level3_s2,0,0 17 | Spawn,level3_s2,0,144 18 | Spawn,level3_s2,464,72 19 | PaletteOverride,level3_s2,9,5,1 20 | NiceWarp,level3_s2,level3_s2u 21 | level3_s2u,736,-128 22 | Props,level3_s2u,0,0 23 | Spawn,level3_s2u,0,184 24 | PaletteOverride,level3_s2u,6,6,2,6,7,2,6,8,2,6,9,2,3,9,2,4,9,2,5,9,2 25 | NiceWarp,level3_s2u,level3_s2 26 | level3_s3,1216,16 27 | Props,level3_s3,0,0 28 | Spawn,level3_s3,0,168 29 | PaletteOverride,level3_s3,7,11,2,8,11,2,9,11,2,10,11,2,11,11,2,12,11,2,13,11,2,16,10,2,17,10,2 30 | level3_0x_a,1536,16 31 | Props,level3_0x_a,0,0 32 | Spawn,level3_0x_a,304,152 33 | Spawn,level3_0x_a,0,152 34 | level3_00_a,1856,16 35 | Props,level3_00_a,2,4 36 | Spawn,level3_00_a,0,152 37 | level3_02_a,2496,16 38 | Props,level3_02_a,0,0 39 | Spawn,level3_02_a,0,160 40 | Spawn,level3_02_a,152,24 41 | Spawn,level3_02_a,304,128 42 | level3_03_a,2816,16 43 | Props,level3_03_a,0,0 44 | Spawn,level3_03_a,0,128 45 | Spawn,level3_03_a,496,168 46 | Spawn,level3_03_a,472,24 47 | level3_02_b,2496,-224 48 | Props,level3_02_b,0,0 49 | Spawn,level3_02_b,152,160 50 | level3_04_b,3136,-224 51 | Props,level3_04_b,0,0 52 | Spawn,level3_04_b,152,184 53 | level3_05_a,3328,16 54 | Props,level3_05_a,2,4 55 | Spawn,level3_05_a,128,168 56 | Spawn,level3_05_a,432,104 57 | level3_01_b,2176,-224 58 | Props,level3_01_b,0,0 59 | Spawn,level3_01_b,304,176 60 | Spawn,level3_01_b,0,184 61 | level3_06_a,3776,16 62 | Props,level3_06_a,0,0 63 | Spawn,level3_06_a,0,104 64 | Spawn,level3_06_a,304,104 65 | level3_07_a,4096,16 66 | Props,level3_07_a,0,0 67 | Spawn,level3_07_a,0,104 68 | Spawn,level3_07_a,304,128 69 | PaletteOverride,level3_07_a,11,8,3 70 | level3_08_a,4416,16 71 | Props,level3_08_a,0,0 72 | Spawn,level3_08_a,0,128 73 | Spawn,level3_08_a,304,112 74 | level3_09_b,4736,16 75 | Props,level3_09_b,0,0 76 | Spawn,level3_09_b,240,128 77 | Spawn,level3_09_b,0,112 78 | NiceWarp,level3_09_b,level3_09_bc 79 | level3_09_bc,4992,16 80 | Props,level3_09_bc,0,0 81 | Spawn,level3_09_bc,0,128 82 | NiceWarp,level3_09_bc,level3_09_b 83 | Filler,3408,-176,416,0 84 | Filler,3392,208,80,0 85 | Filler,1216,-128,32,144 86 | Filler,1216,256,32,96 87 | -------------------------------------------------------------------------------- /src/level3/metatile.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; Metatile Data for "Celestial Resort" (Level 3) 4 | 5 | ; Metatiles 6 | ; 7 | ; For a single metatile ID, the following properties: 8 | ; - metatiles: The char tiles that make up the visual representation of the metatile 9 | ; - metatile_palette: The palette used for the metatile 10 | ; - metatile_collision: The collision mask for the metatile. 11 | 12 | ; These are the metatiles for the Intro level. 13 | ; Eventually the metatile bank will be swappable with different level banks. 14 | 15 | ;metatiles: 16 | .align $100 17 | .byte $00 ; Air 18 | .byte $60,$61,$72,$73 ; Snow Corners 19 | .byte $6B,$6C,$6D ; Snow Tops 20 | .byte $74,$75,$76 ; Snow Bottoms 21 | .byte $70,$62 ; Snow Left 22 | .byte $71,$63 ; Snow Right 23 | .byte $64,$65,$66,$7E,$6F,$6E,$7B,$7C,$7D ; Snow Middles 24 | .byte $67,$68,$77,$78 ; Snow In-corners 25 | .byte $7F,$CC,$CD,$CE,$CF,$DF ; Snow 26 | .byte $36,$40,$37,$44,$38,$50,$39,$54 ; Stone Corners 27 | .byte $41,$42,$43 ; Stone Tops 28 | .byte $51,$52,$53 ; Stone Bottoms 29 | .byte $47,$48,$49,$4A ; Stone Left 30 | .byte $57,$58,$59,$5A ; Stone Right 31 | .byte $45,$46,$55,$56 ; Stone In-corners 32 | .byte $10,$11,$12 ; Stone Pillar 33 | .byte $20,$21,$22 ; Stone Pillar Top 34 | .byte $30,$31,$32 ; Stone Pillar Bottom 35 | .byte $13,$14,$15 ; Stone Bar Left 36 | .byte $23,$24,$25 ; Stone Bar Right 37 | .byte $33,$34,$35 ; Stone Bar 38 | .byte $4B,$4C,$4D,$4E,$5B,$5C,$5D,$5E ; Stone Middles 39 | .byte $07,$08,$17,$18 ; Stone Piller 40 | .byte $27,$28,$29,$2A ; Stone Piller (Dark) 41 | .byte $06,$16 ; Stone Pillar (1 tile version) 42 | .byte $01,$02 ; Sky 43 | .byte $A0,$A1,$A2,$A3 ; Roof Center 44 | .byte $A4,$A5,$A6,$A7 ; Roof Edge R 45 | .byte $B4,$B5,$B6,$B7 ; Roof Edge L 46 | .byte $69,$6A,$79 ; Jump Through 47 | .byte $C8,$C9,$CA,$CB ; Spikes 48 | .byte $C8,$C9,$CA,$CB ; Spikes (Alt) 49 | .byte $04,$05,$26,$3A,$3D,$3E,$3F,$4F,$5F,$2B,$3B ; Backgrounds 50 | .byte $B0,$B1,$B2,$C0,$C1,$B3,$C3,$D3,$C2,$D0,$D1,$D2 ; Dust Bunnies 51 | .byte $C4,$C5,$C6,$C7,$D4,$D5,$D6,$D7 ; Dust Bunnies 52 | .byte $E0,$E1,$E2,$E3,$E4,$E5,$F0,$F1,$F2,$F3,$F4,$F5 ; Dust Bunnies 53 | .byte $2C,$3C,$0C,$1C ; Dust Bunnies 54 | .byte $80,$83,$90,$93 ; Wood Corners 55 | .byte $81,$82,$84 ; Wood Top + Bar End 56 | .byte $91,$92,$94 ; Wood Bottom + Bar End 57 | .byte $87,$97,$88,$98 ; Wood Left and Right 58 | .byte $89,$8A,$8B,$8C ; Wood Inside 59 | .byte $99,$9A,$9B,$9C ; Wood Bars 60 | .byte $85,$86,$95,$96 ; Wood In-corners 61 | .byte $8D,$9D ; Wood Bar Ends 62 | .byte $8E,$8F,$9E,$9F ; Books 63 | .byte $AE,$AF,$BE,$BF ; Books 64 | .byte $AC,$AD,$BC,$BD ; Books 65 | .byte $AA,$AB,$BA,$BB ; Books 66 | .byte $A8,$A9,$B8,$B9 ; Clothes 67 | .byte $E6,$E7,$F6,$F7 ; Clothes 68 | .byte $E8,$E9,$F8,$F9 ; Clothes 69 | .byte $EA,$EB,$FA,$FB ; Clothes 70 | .byte $09,$0A,$19,$1A ; Box 71 | .byte $0B,$1B ; Box Alt Half 72 | .byte $0D,$0E,$0F,$1D,$1E,$1F,$2D,$2E,$2F ; Big Box 73 | .byte $DA,$DB,$DC,$DD,$DE ; Boxes 74 | 75 | ;metatile_info: 76 | .align $100 77 | .byte ct_none ; Air 78 | .res 33, ct_full ; Snow 79 | .res 52, ct_full ; Stone 80 | .res 10, ct_none ; Stone Pillar 81 | .res 2, ct_none ; Sky 82 | .res 4, ct_full ; Roof 83 | .res 2, ct_none ; Roof 84 | .res 2, ct_full ; Roof 85 | .res 2, ct_none ; Roof 86 | .res 2, ct_full ; Roof 87 | .res 3, ct_jumpthru ; Jump Through 88 | .byte ct_deadlyUP ; Spikes 89 | .byte ct_deadlyRT ; Spikes 90 | .byte ct_deadlyDN ; Spikes 91 | .byte ct_deadlyLT ; Spikes 92 | .byte ct_deadlyUP ; Spikes 93 | .byte ct_deadlyRT ; Spikes 94 | .byte ct_deadlyDN ; Spikes 95 | .byte ct_deadlyLT ; Spikes 96 | .res 11, ct_none ; Backgrounds 97 | .res 36, ct_deadlyXX ; Dust Bunnies 98 | .res 28, ct_full ; Wood 99 | .res 16, ct_full ; Clutter A 100 | .res 16, ct_full ; Clutter B 101 | .res 20, ct_full ; Clutter C 102 | 103 | .align $100 -------------------------------------------------------------------------------- /src/level3/mpalette.txt: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; note : this file is NOT included for the game! only for my level editor. 4 | metatile_palette: 5 | .byte $0 ; Air 6 | .res 33, $2 ; Snow 7 | .res 52, $2 ; Stone 8 | .res 10, $2 ; Stone Pillar 9 | .res 2, $2 ; Sky 10 | .res 12, $0 ; Roof 11 | .res 3, $1 ; Jump Through 12 | .res 4, $0 ; Spikes 13 | .res 4, $1 ; Spikes Alt 14 | .res 11, $0 ; Backgrounds 15 | .res 36, $1 ; Dust Bunnies 16 | .res 28, $1 ; Wood 17 | .res 16, $3 ; Books 18 | .res 16, $0 ; Clothes 19 | .res 20, $1 ; Boxes -------------------------------------------------------------------------------- /src/level3/palette.asm: -------------------------------------------------------------------------------- 1 | 2 | level3_palette: 3 | .byte $0f,$30,$23,$03 ; purp tiles 4 | .byte $0f,$30,$16,$06 ; brown tiles 5 | .byte $0f,$20,$21,$11 ; blue tiles 6 | .byte $0f,$30,$29,$09 ; green tiles 7 | .byte $0f,$37,$14,$21 ; player sprite colors 8 | -------------------------------------------------------------------------------- /src/level3/roomlist.asm: -------------------------------------------------------------------------------- 1 | level3: 2 | .word level3_music ; music table 3 | .word level3_banks ; list of banks for each room 4 | .byte $03 ; environment type 5 | .byte $28 ; warp count 6 | .word level3_w_init 7 | .word level3_w_s0_to_s1 8 | .word level3_w_s1_to_s0 9 | .word level3_w_s1_to_s1u 10 | .word level3_w_s1_to_s2 11 | .word level3_w_s1u_to_s1 12 | .word level3_w_s1u_to_s2u 13 | .word level3_w_s2_to_s1 14 | .word level3_w_s2_to_s2u 15 | .word level3_w_s2_to_s3 16 | .word level3_w_s2u_to_s1u 17 | .word level3_w_s2u_to_s2 18 | .word level3_w_s2u_to_s3 19 | .word level3_w_s3_to_s2 20 | .word level3_w_s3_to_s2u 21 | .word level3_w_s3_to_0x_a 22 | .word level3_w_0x_a_to_s3 23 | .word level3_w_0x_a_to_00_a 24 | .word level3_w_00_a_to_0x_a 25 | .word level3_w_00_a_to_02_a 26 | .word level3_w_02_a_to_03_a 27 | .word level3_w_02_a_to_02_b 28 | .word level3_w_03_a_to_02_a 29 | .word level3_w_03_a_to_04_b 30 | .word level3_w_03_a_to_05_a 31 | .word level3_w_02_b_to_02_a 32 | .word level3_w_02_b_to_01_b 33 | .word level3_w_04_b_to_03_a 34 | .word level3_w_05_a_to_03_a 35 | .word level3_w_05_a_to_06_a 36 | .word level3_w_01_b_to_02_b 37 | .word level3_w_06_a_to_05_a 38 | .word level3_w_06_a_to_07_a 39 | .word level3_w_07_a_to_06_a 40 | .word level3_w_07_a_to_08_a 41 | .word level3_w_08_a_to_07_a 42 | .word level3_w_08_a_to_09_b 43 | .word level3_w_09_b_to_08_a 44 | .word level3_w_09_b_to_09_bc 45 | .word level3_w_09_bc_to_09_b 46 | level3_banks: 47 | .byte prgb_lvl3a ; level3_w_init 48 | .byte prgb_lvl3a ; level3_w_s0_to_s1 49 | .byte prgb_lvl3a ; level3_w_s1_to_s0 50 | .byte prgb_lvl3a ; level3_w_s1_to_s1u 51 | .byte prgb_lvl3a ; level3_w_s1_to_s2 52 | .byte prgb_lvl3a ; level3_w_s1u_to_s1 53 | .byte prgb_lvl3a ; level3_w_s1u_to_s2u 54 | .byte prgb_lvl3a ; level3_w_s2_to_s1 55 | .byte prgb_lvl3a ; level3_w_s2_to_s2u 56 | .byte prgb_lvl3a ; level3_w_s2_to_s3 57 | .byte prgb_lvl3a ; level3_w_s2u_to_s1u 58 | .byte prgb_lvl3a ; level3_w_s2u_to_s2 59 | .byte prgb_lvl3a ; level3_w_s2u_to_s3 60 | .byte prgb_lvl3a ; level3_w_s3_to_s2 61 | .byte prgb_lvl3a ; level3_w_s3_to_s2u 62 | .byte prgb_lvl3a ; level3_w_s3_to_0x_a 63 | .byte prgb_lvl3a ; level3_w_0x_a_to_s3 64 | .byte prgb_lvl3a ; level3_w_0x_a_to_00_a 65 | .byte prgb_lvl3a ; level3_w_00_a_to_0x_a 66 | .byte prgb_lvl3a ; level3_w_00_a_to_02_a 67 | .byte prgb_lvl3a ; level3_w_02_a_to_03_a 68 | .byte prgb_lvl3a ; level3_w_02_a_to_02_b 69 | .byte prgb_lvl3a ; level3_w_03_a_to_02_a 70 | .byte prgb_lvl3a ; level3_w_03_a_to_04_b 71 | .byte prgb_lvl3a ; level3_w_03_a_to_05_a 72 | .byte prgb_lvl3a ; level3_w_02_b_to_02_a 73 | .byte prgb_lvl3a ; level3_w_02_b_to_01_b 74 | .byte prgb_lvl3a ; level3_w_04_b_to_03_a 75 | .byte prgb_lvl3a ; level3_w_05_a_to_03_a 76 | .byte prgb_lvl3b ; level3_w_05_a_to_06_a 77 | .byte prgb_lvl3a ; level3_w_01_b_to_02_b 78 | .byte prgb_lvl3a ; level3_w_06_a_to_05_a 79 | .byte prgb_lvl3a ; level3_w_06_a_to_07_a 80 | .byte prgb_lvl3b ; level3_w_07_a_to_06_a 81 | .byte prgb_lvl3b ; level3_w_07_a_to_08_a 82 | .byte prgb_lvl3a ; level3_w_08_a_to_07_a 83 | .byte prgb_lvl3b ; level3_w_08_a_to_09_b 84 | .byte prgb_lvl3b ; level3_w_09_b_to_08_a 85 | .byte prgb_lvl3b ; level3_w_09_b_to_09_bc 86 | .byte prgb_lvl3b ; level3_w_09_bc_to_09_b 87 | -------------------------------------------------------------------------------- /src/level3/tgroups.txt: -------------------------------------------------------------------------------- 1 | ; BITS: 2 | ; 0 - Up 3 | ; 1 - Down 4 | ; 2 - Left 5 | ; 3 - Right 6 | ; 4 - UpLeft 7 | ; 5 - UpRight 8 | ; 6 - DownLeft 9 | ; 7 - DownRight 10 | ; 11 | ; the bit mask is left to right, so bit 0 corresponds to index 0. 12 | ; 13 | ; - - don't matter 14 | ; 1 - is one 15 | ; 0 - is zero 16 | ; 17 | ; ex. -------- - default mask, -1000000 - up doesn't matter, down must be 1, rest must be zero 18 | ; TODO 19 | group 1 20 | name SNOW 21 | color $21 22 | -------- $01 23 | 0101---- $01 24 | 0110---- $02 25 | 1001---- $03 26 | 1010---- $04 27 | 0111---- $05 $06 $07 28 | 1011---- $08 $09 $0A 29 | 1101---- $0B $0C 30 | 1110---- $0D $0E 31 | 1111---- $0F $10 $11 $12 $13 $14 $15 $16 $17 32 | 1111---0 $18 33 | 1111--0- $19 34 | 1111-0-- $1A 35 | 11110--- $1B 36 | 111-0-0- $1C 37 | 0001---- $1D 38 | 0010---- $1E 39 | 1100---- $1F 40 | 0100---- $20 41 | 1000---- $21 42 | 43 | group 2 44 | name STONE 45 | color $30 46 | -------- $00 47 | 0101---- $22 $23 48 | 0110---- $24 $25 49 | 1001---- $26 $27 50 | 1010---- $28 $29 51 | 0111---- $2A $2B $2C 52 | 1011---- $2D $2E $2F 53 | 1101---- $30 $31 $32 $33 54 | 1110---- $34 $35 $36 $37 55 | 1111---- $4E $4F $50 $51 $52 $53 $54 $55 56 | 1111---0 $38 57 | 1111--0- $39 58 | 1111-0-- $3A 59 | 11110--- $3B 60 | 0001---- $45 $46 $47 61 | 0010---- $48 $49 $4A 62 | 0011---- $4B $4C $4D 63 | 0100---- $3F $40 $41 64 | 1000---- $42 $43 $44 65 | 1100---- $3C $3D $3E 66 | 67 | group 3 68 | name WOOD 69 | color $06 70 | -------- $00 71 | 0101---- $A8 72 | 0110---- $A9 73 | 1001---- $AA 74 | 1010---- $AB 75 | 0111---- $AC $AD 76 | 1011---- $AF $B0 77 | 1101---- $B2 $B3 78 | 1110---- $B4 $B5 79 | 1111---- $B6 $B7 $B8 $B9 80 | 1111---0 $BE 81 | 1111--0- $BF 82 | 1111-0-- $C0 83 | 11110--- $C1 84 | 0100---- $AE 85 | 1000---- $B1 86 | 1100---- $BA $BB 87 | 0001---- $C2 88 | 0010---- $C3 89 | 0011---- $BC $BD 90 | -------------------------------------------------------------------------------- /src/level3/warplist.asm: -------------------------------------------------------------------------------- 1 | level3_w_init: 2 | .byte 0 ; room left offset 3 | .byte 16, 144 ; player spawn X/Y 4 | .word level3_s0 5 | level3_w_s0_to_s1: 6 | .byte 0 ; room left offset 7 | .byte 0, 144 ; player spawn X/Y 8 | .word level3_s1 9 | level3_w_s1_to_s0: 10 | .byte 8 ; room left offset 11 | .byte 240, 144 ; player spawn X/Y 12 | .word level3_s0 13 | level3_w_s1_to_s1u: 14 | .byte 148 ; room left offset 15 | .byte 240, 184 ; player spawn X/Y 16 | .word level3_s1u 17 | level3_w_s1_to_s2: 18 | .byte 0 ; room left offset 19 | .byte 0, 144 ; player spawn X/Y 20 | .word level3_s2 21 | level3_w_s1u_to_s1: 22 | .byte 148 ; room left offset 23 | .byte 240, 144 ; player spawn X/Y 24 | .word level3_s1 25 | level3_w_s1u_to_s2u: 26 | .byte 0 ; room left offset 27 | .byte 0, 184 ; player spawn X/Y 28 | .word level3_s2u 29 | level3_w_s2_to_s1: 30 | .byte 20 ; room left offset 31 | .byte 240, 144 ; player spawn X/Y 32 | .word level3_s1 33 | level3_w_s2_to_s2u: 34 | .byte 128 ; room left offset 35 | .byte 0, 184 ; player spawn X/Y 36 | .word level3_s2u 37 | level3_w_s2_to_s3: 38 | .byte 0 ; room left offset 39 | .byte 0, 168 ; player spawn X/Y 40 | .word level3_s3 41 | level3_w_s2u_to_s1u: 42 | .byte 20 ; room left offset 43 | .byte 240, 184 ; player spawn X/Y 44 | .word level3_s1u 45 | level3_w_s2u_to_s2: 46 | .byte 156 ; room left offset 47 | .byte 240, 72 ; player spawn X/Y 48 | .word level3_s2 49 | level3_w_s2u_to_s3: 50 | .byte 0 ; room left offset 51 | .byte 0, 168 ; player spawn X/Y 52 | .word level3_s3 53 | level3_w_s3_to_s2: 54 | .byte 28 ; room left offset 55 | .byte 240, 72 ; player spawn X/Y 56 | .word level3_s2 57 | level3_w_s3_to_s2u: 58 | .byte 0 ; room left offset 59 | .byte 0, 184 ; player spawn X/Y 60 | .word level3_s2u 61 | level3_w_s3_to_0x_a: 62 | .byte 0 ; room left offset 63 | .byte 0, 152 ; player spawn X/Y 64 | .word level3_0x_a 65 | level3_w_0x_a_to_s3: 66 | .byte 0 ; room left offset 67 | .byte 0, 168 ; player spawn X/Y 68 | .word level3_s3 69 | level3_w_0x_a_to_00_a: 70 | .byte 0 ; room left offset 71 | .byte 0, 152 ; player spawn X/Y 72 | .word level3_00_a 73 | level3_w_00_a_to_0x_a: 74 | .byte 8 ; room left offset 75 | .byte 240, 152 ; player spawn X/Y 76 | .word level3_0x_a 77 | level3_w_00_a_to_02_a: 78 | .byte 0 ; room left offset 79 | .byte 0, 160 ; player spawn X/Y 80 | .word level3_02_a 81 | level3_w_02_a_to_03_a: 82 | .byte 0 ; room left offset 83 | .byte 0, 128 ; player spawn X/Y 84 | .word level3_03_a 85 | level3_w_02_a_to_02_b: 86 | .byte 4 ; room left offset 87 | .byte 120, 160 ; player spawn X/Y 88 | .word level3_02_b 89 | level3_w_03_a_to_02_a: 90 | .byte 8 ; room left offset 91 | .byte 240, 128 ; player spawn X/Y 92 | .word level3_02_a 93 | level3_w_03_a_to_04_b: 94 | .byte 4 ; room left offset 95 | .byte 120, 184 ; player spawn X/Y 96 | .word level3_04_b 97 | level3_w_03_a_to_05_a: 98 | .byte 0 ; room left offset 99 | .byte 128, 168 ; player spawn X/Y 100 | .word level3_05_a 101 | level3_w_02_b_to_02_a: 102 | .byte 4 ; room left offset 103 | .byte 120, 24 ; player spawn X/Y 104 | .word level3_02_a 105 | level3_w_02_b_to_01_b: 106 | .byte 8 ; room left offset 107 | .byte 240, 176 ; player spawn X/Y 108 | .word level3_01_b 109 | level3_w_04_b_to_03_a: 110 | .byte 32 ; room left offset 111 | .byte 216, 24 ; player spawn X/Y 112 | .word level3_03_a 113 | level3_w_05_a_to_03_a: 114 | .byte 32 ; room left offset 115 | .byte 240, 168 ; player spawn X/Y 116 | .word level3_03_a 117 | level3_w_05_a_to_06_a: 118 | .byte 0 ; room left offset 119 | .byte 0, 104 ; player spawn X/Y 120 | .word level3_06_a 121 | level3_w_01_b_to_02_b: 122 | .byte 4 ; room left offset 123 | .byte 120, 160 ; player spawn X/Y 124 | .word level3_02_b 125 | level3_w_06_a_to_05_a: 126 | .byte 24 ; room left offset 127 | .byte 240, 104 ; player spawn X/Y 128 | .word level3_05_a 129 | level3_w_06_a_to_07_a: 130 | .byte 0 ; room left offset 131 | .byte 0, 104 ; player spawn X/Y 132 | .word level3_07_a 133 | level3_w_07_a_to_06_a: 134 | .byte 8 ; room left offset 135 | .byte 240, 104 ; player spawn X/Y 136 | .word level3_06_a 137 | level3_w_07_a_to_08_a: 138 | .byte 0 ; room left offset 139 | .byte 0, 128 ; player spawn X/Y 140 | .word level3_08_a 141 | level3_w_08_a_to_07_a: 142 | .byte 8 ; room left offset 143 | .byte 240, 128 ; player spawn X/Y 144 | .word level3_07_a 145 | level3_w_08_a_to_09_b: 146 | .byte 0 ; room left offset 147 | .byte 0, 112 ; player spawn X/Y 148 | .word level3_09_b 149 | level3_w_09_b_to_08_a: 150 | .byte 8 ; room left offset 151 | .byte 240, 112 ; player spawn X/Y 152 | .word level3_08_a 153 | level3_w_09_b_to_09_bc: 154 | .byte 128 ; room left offset 155 | .byte 0, 128 ; player spawn X/Y 156 | .word level3_09_bc 157 | level3_w_09_bc_to_09_b: 158 | .byte 128 ; room left offset 159 | .byte 240, 128 ; player spawn X/Y 160 | .word level3_09_b 161 | -------------------------------------------------------------------------------- /src/levels.txt: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; This file is NOT a source code file, only included for my level editor. 4 | ; This file describes a level and its constituent files. 5 | 6 | ; Note: Commands starting with BANK_ mean, that the word in the bank list in roomlist.asm connects to rooms_$.asm 7 | 8 | level0: 9 | palette_path: level0/palette.asm 10 | roomlist_path: level0/roomlist.asm 11 | warplist_path: level0/warplist.asm 12 | metatile_path: level0/metatile.asm 13 | metapale_path: level0/mpalette.txt 14 | tilegroups_path: level0/tgroups.txt 15 | layout_path: level0/layout.txt 16 | spr0_path: chr/sp_player.chr 17 | spr1_path: chr/sp_level0.chr 18 | spr2_path: chr/sp_gener.chr 19 | spr3_path: chr/sp_anim.chr 20 | bg_path: chr/b_lvl0.chr 21 | roomdata_path: level0/rooms/$.asm 22 | BANK_prgb_lvl0a: 0 23 | 24 | level1: 25 | palette_path: level1/palette.asm 26 | roomlist_path: level1/roomlist.asm 27 | warplist_path: level1/warplist.asm 28 | metatile_path: level1/metatile.asm 29 | metapale_path: level1/mpalette.txt 30 | tilegroups_path: level1/tgroups.txt 31 | layout_path: level1/layout.txt 32 | spr0_path: chr/sp_player.chr 33 | spr1_path: chr/sp_level1.chr 34 | spr2_path: chr/sp_gener.chr 35 | spr3_path: chr/sp_anim.chr 36 | bg_path: chr/b_lvl1.chr 37 | roomdata_path: level1/rooms/$.asm 38 | BANK_prgb_lvl1a: 0 39 | BANK_prgb_lvl1b: 1 40 | BANK_prgb_lvl1c: 2 41 | BANK_prgb_lvl1d: 3 42 | 43 | level2: 44 | palette_path: level2/palette.asm 45 | roomlist_path: level2/roomlist.asm 46 | warplist_path: level2/warplist.asm 47 | metatile_path: level2/metatile.asm 48 | metapale_path: level2/mpalette.txt 49 | tilegroups_path: level2/tgroups.txt 50 | layout_path: level2/layout.txt 51 | spr0_path: chr/sp_player.chr 52 | spr1_path: chr/sp_level2.chr 53 | spr2_path: chr/sp_gener.chr 54 | spr3_path: chr/sp_anim.chr 55 | bg_path: chr/b_lvl2.chr 56 | roomdata_path: level2/rooms/$.asm 57 | BANK_prgb_lvl2a: 0 58 | BANK_prgb_lvl2b: 1 59 | BANK_prgb_lvl2c: 2 60 | BANK_prgb_lvl2d: 3 61 | BANK_prgb_lvl2e: 4 62 | BANK_prgb_lvl2f: 5 63 | 64 | level3: 65 | palette_path: level3/palette.asm 66 | roomlist_path: level3/roomlist.asm 67 | warplist_path: level3/warplist.asm 68 | metatile_path: level3/metatile.asm 69 | metapale_path: level3/mpalette.txt 70 | tilegroups_path: level3/tgroups.txt 71 | layout_path: level3/layout.txt 72 | spr0_path: chr/sp_player.chr 73 | spr1_path: chr/sp_level3.chr 74 | spr2_path: chr/sp_gener.chr 75 | spr3_path: chr/sp_anim.chr 76 | bg_path: chr/b_lvl3.chr 77 | roomdata_path: level3/rooms/$.asm 78 | BANK_prgb_lvl3a: 0 79 | BANK_prgb_lvl3b: 1 80 | -------------------------------------------------------------------------------- /src/lvltable.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | level_table: 4 | .word level0 5 | .word level1 ; 1 6 | .word level2 ; 2 7 | .word level3 ; 3 8 | .word level0 ; 4 9 | .word level0 ; 5 10 | .word level0 ; 6 11 | .word level0 ; 7 12 | 13 | level_banks2: 14 | .byte prgb_lvl0a 15 | .byte prgb_lvl1b 16 | .byte prgb_lvl2b 17 | .byte prgb_lvl3b 18 | .byte prgb_lvl0a 19 | .byte prgb_lvl0a 20 | .byte prgb_lvl0a 21 | .byte prgb_lvl0a 22 | 23 | level_banks_mus: 24 | .byte prgb_lvl0a 25 | .byte prgb_lvl1c 26 | .byte prgb_lvl2e 27 | .byte prgb_lvl3a 28 | .byte prgb_lvl0a 29 | .byte prgb_lvl0a 30 | .byte prgb_lvl0a 31 | .byte prgb_lvl0a 32 | 33 | level_banks_spr: 34 | .byte chrb_splvl0 35 | .byte chrb_splvl1 36 | .byte chrb_splvl2 37 | .byte chrb_splvl0 38 | .byte chrb_splvl0 39 | .byte chrb_splvl0 40 | .byte chrb_splvl0 41 | .byte chrb_splvl0 42 | 43 | level_palettes: 44 | .word level0_palette 45 | .word level1_palette 46 | .word level2_palette 47 | .word level3_palette 48 | .word level0_palette 49 | .word level0_palette 50 | .word level0_palette 51 | .word level0_palette 52 | 53 | level_berry_counts: 54 | .byte 0 55 | .byte 20 56 | .byte 17 ; 18 -- the "Awake" section doesn't exist yet. 57 | .byte 25 58 | .byte 29 59 | .byte 31 60 | .byte 0 61 | .byte 47 62 | .byte 5 63 | 64 | level_bg_banks_1: 65 | .byte chrb_lvl0 66 | .byte chrb_lvl1 67 | .byte chrb_lvl2 68 | .byte chrb_lvl3 69 | ;.byte chrb_lvl0 70 | ;.byte chrb_lvl0 71 | ;.byte chrb_lvl0 72 | ;.byte chrb_lvl0 73 | 74 | level_bg_banks_2: 75 | .byte chrb_lvl0+2 76 | .byte chrb_lvl1+2 77 | .byte chrb_lvl2+2 78 | .byte chrb_lvl3+2 79 | ;.byte chrb_lvl0+2 80 | ;.byte chrb_lvl0+2 81 | ;.byte chrb_lvl0+2 82 | ;.byte chrb_lvl0+2 83 | -------------------------------------------------------------------------------- /src/m_auxil.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; This file belongs in the main segment, and is located between the two IRQ alignments 4 | ; ** SUBROUTINE: far_call 5 | ; arguments: 6 | ; Y - the bank index this code resides in 7 | ; (temp2, temp1) - address of the function at hand. 8 | ; desc: Calls a function residing in a bank at $A000-$BFFF. Cannot call functions residing 9 | ; in other banks. 10 | far_call: 11 | lda currA000bank 12 | pha ; push the current bank number 13 | 14 | ; change the bank 15 | lda #mmc3bk_prg1 16 | jsr mmc3_set_bank 17 | 18 | ; bank switched, now call 19 | jsr @doTheCall 20 | 21 | ; change the bank back 22 | pla 23 | tay 24 | lda #mmc3bk_prg1 25 | jmp mmc3_set_bank 26 | 27 | @doTheCall: 28 | ; redirect execution to (farcalladdr) 29 | ; this function SHOULD return. this is why we do the jsr indirection 30 | jmp (farcalladdr) 31 | 32 | ; ** SUBROUTINE: vblank_wait 33 | ; arguments: none 34 | ; clobbers: A 35 | vblank_wait: 36 | lda #$00 37 | : bit ppu_status 38 | bpl :- ; check bit 7, equal to zero means not in vblank 39 | rts 40 | 41 | ; ** SUBROUTINE: nmi_wait 42 | ; arguments: none 43 | ; clobbers: A 44 | nmi_wait: 45 | lda nmicount 46 | : cmp nmicount 47 | beq :- 48 | rts 49 | 50 | ; ** SUBROUTINE: mmc3_set_bank 51 | ; arguments: 52 | ; A - the bank index to switch 53 | ; Y - the bank number to switch to 54 | ; desc: Programs the MMC3 such that, after the execution of this subroutine, the 55 | ; bank specified in Y is loaded at the bank address whose index is A. 56 | ; assumes: That this function does not run inside of an NMI. To perform a bank 57 | ; switch during an NMI, use mmc3_set_bank_nmi. 58 | 59 | mmc3_set_bank: 60 | ; note: I don't think we will switch the $A000-$BFFF bank during an NMI. 61 | cmp #mmc3bk_prg1 62 | bne :+ 63 | sty currA000bank 64 | : ora #def_mmc3_bn ; OR the default MMC3 configuration. 65 | sta mmc3_shadow ; Store to the MMC3 shadow global variable. 66 | sta mmc3_bsel ; Write this selector to the MMC3 chip. 67 | sty mmc3_bdat ; Write the specified bank index to the MMC3 chip. 68 | rts 69 | 70 | ; Explanation on why we also store the mmc3 selector in mmc3_shadow. 71 | ; 72 | ; This is done to avoid a race condition, in the case of game lag, that an 73 | ; NMI might be fired while this function is executed, after the selector is 74 | ; written, but before the data is written, and the NMI wants to perform a 75 | ; bank switch of its own. 76 | ; 77 | ; Basically, the mmc3 shadow register is written back to the mmc3 chip when 78 | ; exiting an NMI in case of such a race, thereby undoing the NMI's potential 79 | ; effects. 80 | 81 | ; ** SUBROUTINE: mmc3_set_bank_nmi 82 | ; arguments: See mmc3_set_bank 83 | ; desc: Programs the MMC3 such that, after the execution of this subroutine, the 84 | ; bank specified in Y is loaded at the bank address whose index is A. 85 | ; This function restores the mmc3 selector from the shadow global variable 86 | ; one this bank switch is performed. 87 | ; assumes: That this function is running inside an NMI. To perform a bank switch 88 | ; during regular game execution, use mmc3_set_bank. 89 | 90 | mmc3_set_bank_nmi: 91 | ora #def_mmc3_bn ; OR the default MMC3 configuration. 92 | sta mmc3_bsel 93 | sty mmc3_bdat 94 | lda mmc3_shadow ; Restore the old selector. 95 | sta mmc3_bsel 96 | rts 97 | 98 | ; ** SUBROUTINE: load_palette 99 | ; arguments: 100 | ; paladdr[0, 1] -- the address of the palette to upload 101 | ; clobbers: A, X 102 | ; assumes: PPUCTRL increment bit is zero (+1 instead of +32) 103 | load_palette: 104 | lda #$3F 105 | ldy #$00 106 | sta ppu_addr 107 | sty ppu_addr 108 | @loop: 109 | lda (paladdr), y 110 | sta ppu_data 111 | iny 112 | cpy #$20 113 | bne @loop 114 | jmp reset_ppuaddr 115 | 116 | ; ** SUBROUTINE: soft_nmi_on 117 | ; desc: Enable racey NMIs in software. 118 | ; purpose: Most of the NMI routine is racey against the main thread. However, we want to run 119 | ; audio every frame regardless of lag. This is why we block racey NMIs in software. 120 | ; clobbers: A 121 | soft_nmi_on: 122 | lda #1 123 | sta nmienable 124 | rts 125 | 126 | ; ** SUBROUTINE: soft_nmi_off 127 | ; desc: Disable racey NMIs in software. 128 | ; clobbers: A 129 | soft_nmi_off: 130 | lda #0 131 | sta nmienable 132 | rts 133 | 134 | ; ** SUBROUTINE: ppu_nmi_on 135 | ; arguments: none 136 | ; clobbers: A 137 | ppu_nmi_on: 138 | lda ctl_flags 139 | ora #pctl_nmi_on 140 | sta ctl_flags 141 | sta ppu_ctrl 142 | rts 143 | 144 | ; ** SUBROUTINE: mmc3_initialize 145 | ; desc: Initializes the MMC3 mapper chip. 146 | mmc3_initialize: 147 | ; load PRG ROM banks 148 | lda #(def_mmc3_bn | 6) 149 | sta mmc3_bsel 150 | lda prgb_lvl0a 151 | sta mmc3_bdat 152 | 153 | lda #(def_mmc3_bn | 7) 154 | sta mmc3_bsel 155 | lda prgb_lvl0a 156 | sta mmc3_bdat 157 | 158 | ; note: don't need to load default banks, the title screen init code will do that for me. 159 | 160 | ;jsr mmc3_horzarr 161 | lda #0 162 | sta mmc3_mirror 163 | sta mmc3_irqdi ; disable IRQs for now 164 | 165 | lda #%10000000 ; enable PRG RAM, disable write protection 166 | sta mmc3_pram 167 | rts 168 | -------------------------------------------------------------------------------- /src/m_fade.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: fade_prepare_vmcpy 4 | ; desc: Set the video memory copy operation's address to the temprow1 array's, 5 | ; set the count to 32, set the dest to $3F00, and return zero. 6 | .proc fade_prepare_vmcpy 7 | lda #temprow1 10 | sta vmcsrc+1 11 | lda #$3F 12 | sta vmcaddr+1 13 | lda #$00 14 | sta vmcaddr 15 | rts 16 | .endproc 17 | 18 | ; ** SUBROUTINE: fade_copy_palette 19 | ; desc: Copies the selected palette from [paladdr] to temprow1. 20 | .proc fade_copy_palette 21 | ldy vmccount 22 | dey 23 | @loopCopy: 24 | lda (paladdr), y 25 | sta temprow1, y 26 | dey 27 | bpl @loopCopy ; it has to go to $FF first 28 | rts 29 | .endproc 30 | 31 | ; ** SUBROUTINE: fade_in 32 | ; desc: Fades in to a palette. 33 | ; parameters: paladdr - The palette to fade into 34 | .proc fade_in 35 | lda #32 36 | differentPaletteSize: 37 | sta vmccount 38 | inc fade_active 39 | jsr fade_copy_palette 40 | jsr fade_prepare_vmcpy 41 | 42 | sta ppu_mask 43 | sta tempmaskover 44 | 45 | jsr vblank_wait 46 | 47 | ldx #24 48 | @loop: 49 | stx transtimer 50 | txa 51 | and #%00000111 52 | bne @dontfade 53 | 54 | jsr fade_copy_palette 55 | cpx #%00001000 56 | beq @fade0x 57 | cpx #%00010000 58 | beq @fade1x 59 | ; #%00011000 -- fade2x 60 | 61 | @fade2x: 62 | jsr fade_fade_temp_row 63 | @fade1x: 64 | jsr fade_fade_temp_row 65 | @fade0x: 66 | jsr fade_set_vmc_flag 67 | @dontfade: 68 | 69 | ; Well, as it turns out, we have to do it the dumb way. 70 | ; We need to prepare ppuaddrHR1, ppuaddrHR2 71 | 72 | ; every 4 frames, determine whether the emphasis bits are set 73 | ldy #0 74 | lda transtimer 75 | sec 76 | sbc #1 77 | and #%00000100 78 | beq :+ 79 | ldy #%11100000 80 | : sty tempmaskover 81 | lda nmictrl 82 | ora #nc_turnon 83 | sta nmictrl 84 | 85 | jsr fade_call_update_func 86 | jsr fade_wait_one_frame 87 | 88 | ldx transtimer 89 | dex 90 | 91 | cpx #0 92 | bne @loop 93 | 94 | jsr fade_copy_palette 95 | jsr fade_set_vmc_flag 96 | jsr fade_call_update_func 97 | dec fade_active 98 | jmp fade_wait_one_frame 99 | .endproc 100 | 101 | fade_in_smaller_palette := fade_in::differentPaletteSize 102 | 103 | ; ** SUBROUTINE: fade_fade_temp_row 104 | ; desc: Fades all colors inside temprow1. 105 | .proc fade_fade_temp_row 106 | ldx #0 107 | : lda temprow1, x 108 | jsr fade_twice_if_high 109 | sta temprow1, x 110 | inx 111 | cpx vmccount 112 | bne :- 113 | rts 114 | .endproc 115 | 116 | ; ** SUBROUTINE: fade_set_vmc_flag 117 | ; desc: Requests a video memory copy operation. 118 | .proc fade_set_vmc_flag 119 | lda nmictrl2 120 | ora #nc2_vmemcpy 121 | sta nmictrl2 122 | rts 123 | .endproc 124 | 125 | ; ** SUBROUTINE: fade_call_update_func 126 | ; desc: Calls the update subroutine. 127 | .proc fade_call_update_func 128 | lda fadeupdrt+1 129 | beq :+ 130 | jmp (fadeupdrt) 131 | : rts 132 | .endproc 133 | 134 | ; ** SUBROUTINE: fade_wait_one_frame 135 | ; desc: Waits a single frame. 136 | .proc fade_wait_one_frame 137 | jsr soft_nmi_on 138 | jsr nmi_wait 139 | jmp soft_nmi_off 140 | .endproc 141 | 142 | ; ** SUBROUTINE: fade_out 143 | ; desc: Fades to black. This is a synchronous routine. 144 | .proc fade_out 145 | lda #32 146 | sta vmccount 147 | inc fade_active 148 | jsr fade_prepare_vmcpy 149 | jsr fade_copy_palette 150 | 151 | ; it will take us 31 frames to do the fade out. 152 | ldy #31 153 | @loopFadeOut: 154 | sty transtimer 155 | 156 | tya 157 | and #%00000111 158 | bne @dontFadePalette 159 | 160 | jsr fade_fade_temp_row 161 | jsr fade_set_vmc_flag 162 | 163 | @dontFadePalette: 164 | jsr fade_call_update_func 165 | jsr fade_wait_one_frame 166 | 167 | ldy transtimer 168 | dey 169 | 170 | ; every 4 frames, determine whether the emphasis bits are set 171 | ldx #def_ppu_msk 172 | tya 173 | and #%00000100 174 | bne :+ 175 | ldx #(def_ppu_msk | %11100000) 176 | : stx ppu_mask 177 | 178 | cpy #0 179 | bne @loopFadeOut 180 | 181 | ; everything is black, also disable rendering 182 | 183 | sty ppu_mask 184 | 185 | ; the fade out is complete - everything's black now 186 | ; and rendering is disabled 187 | dec fade_active 188 | rts 189 | .endproc 190 | -------------------------------------------------------------------------------- /src/overwld.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | gamemode_overwd_update_NEAR: 4 | jmp gamemode_overwd_update_FAR 5 | 6 | ; ** GAMEMODE: gamemode_overwd 7 | gamemode_overwd: 8 | lda #os_1stfr 9 | bit owldctrl 10 | bne gamemode_overwd_update_NEAR 11 | 12 | jsr aud_reset 13 | 14 | ; Load the title bank. 15 | lda #mmc3bk_prg0 16 | ldy #prgb_ttle 17 | jsr mmc3_set_bank 18 | 19 | jmp gamemode_overwd_init_FAR 20 | -------------------------------------------------------------------------------- /src/p_trace.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | 4 | ; ** SUBROUTINE: ph_shifttrace 5 | ; desc: Shifts the player X trace left by an amount of pixels. 6 | ; parameters: 7 | ; A - the amount of pixels to decrease the player X trace by 8 | ; note: The player X trace is capped to 0. It will never overflow. 9 | .proc ph_shifttrace 10 | sta temp1 11 | 12 | lda #g2_notrace 13 | bit gamectrl2 14 | bne return 15 | 16 | lda temp1 17 | cmp #0 18 | bmi actuallyNegative 19 | nocheck: 20 | pha 21 | ldx #0 22 | loop: 23 | lda plr_trace_x, x 24 | sec 25 | sbc temp1 26 | bcs :+ 27 | lda #0 28 | : sta plr_trace_x, x 29 | inx 30 | cpx #$40 31 | bne loop 32 | pla 33 | return: 34 | rts 35 | actuallyNegative: 36 | sta temp1 37 | lda #0 38 | sec 39 | sbc temp1 40 | jmp ph_shiftrighttrace_nocheck 41 | .endproc 42 | 43 | ; ** SUBROUTINE: ph_shiftrighttrace 44 | ; desc: Shifts the player X trace right by an amount of pixels. 45 | ; parameters: 46 | ; A - the amount of pixels to increase the player X trace by 47 | ; note: The player X trace is capped to $FF. It will never overflow. 48 | .proc ph_shiftrighttrace 49 | sta temp1 50 | 51 | lda #g2_notrace 52 | bit gamectrl2 53 | bne return 54 | 55 | lda temp1 56 | cmp #0 57 | bmi actuallyNegative 58 | nocheck: 59 | pha 60 | ldx #0 61 | sta temp1 62 | : lda plr_trace_x, x 63 | clc 64 | adc temp1 65 | bcc :+ 66 | lda #$FF 67 | : sta plr_trace_x, x 68 | inx 69 | cpx #$40 70 | bne :-- 71 | pla 72 | return: 73 | rts 74 | actuallyNegative: 75 | sta temp1 76 | lda #0 77 | sec 78 | sbc temp1 79 | jmp ph_shifttrace::nocheck 80 | .endproc 81 | 82 | ph_shiftrighttrace_nocheck := ph_shiftrighttrace::nocheck 83 | 84 | ; ** SUBROUTINE: ph_shifttraceYP 85 | ; desc: Shifts the player Y trace down by an amount of pixels 86 | ; parameters: 87 | ; A - the amount of pixels to increase the player Y trace by 88 | ; note: The player X trace is capped to $F0. It will never overflow. 89 | .proc ph_shifttraceYP 90 | sta temp1 91 | 92 | lda #g2_notrace 93 | bit gamectrl2 94 | bne return 95 | 96 | lda temp1 97 | cmp #0 98 | bmi actuallyNegative 99 | nocheck: 100 | pha 101 | ldx #0 102 | sta temp1 103 | loop: 104 | lda plr_trace_y, x 105 | clc 106 | adc temp1 107 | bcc :+ 108 | lda #$F0 109 | : cmp #$F0 110 | bcc :+ 111 | lda #$F0 112 | : sta plr_trace_y, x 113 | inx 114 | cpx #$40 115 | bne loop 116 | pla 117 | return: 118 | rts 119 | actuallyNegative: 120 | sta temp1 121 | lda #0 122 | sec 123 | sbc temp1 124 | jmp ph_shifttraceYN_nocheck 125 | .endproc 126 | 127 | ; ** SUBROUTINE: ph_shifttraceYN 128 | ; desc: Shifts the player Y trace up by an amount of pixels 129 | ; parameters: 130 | ; A - the amount of pixels to increase the player Y trace by 131 | ; note: The player X trace is capped to 0. It will never overflow. 132 | .proc ph_shifttraceYN 133 | sta temp1 134 | 135 | lda #g2_notrace 136 | bit gamectrl2 137 | bne return 138 | 139 | lda temp1 140 | bmi actuallyNegative 141 | nocheck: 142 | pha 143 | ldx #0 144 | sta temp1 145 | loop: 146 | lda plr_trace_y, x 147 | sec 148 | sbc temp1 149 | bcs :+ 150 | lda #0 151 | : sta plr_trace_y, x 152 | inx 153 | cpx #$40 154 | bne loop 155 | pla 156 | return: 157 | rts 158 | actuallyNegative: 159 | sta temp1 160 | lda #0 161 | sec 162 | sbc temp1 163 | jmp ph_shifttraceYP::nocheck 164 | .endproc 165 | 166 | ph_shifttraceYN_nocheck := ph_shifttraceYN::nocheck 167 | 168 | ph_altshifttrace: 169 | lda temp12 170 | jmp ph_shifttrace 171 | ph_altshiftrighttrace: 172 | lda temp12 173 | jmp ph_shiftrighttrace 174 | ph_altshifttraceYN: 175 | lda temp12 176 | jmp ph_shifttraceYN 177 | ph_altshifttraceYP: 178 | lda temp12 179 | jmp ph_shifttraceYP 180 | -------------------------------------------------------------------------------- /src/prg_dial.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024-2025 iProgramInCpp 2 | 3 | ; some defines: 4 | dialog_char_timer = 3 5 | dialog_border = 16 6 | dialog_border_upp = 20 7 | dialog_port_size = 40 8 | dialog_port_brdr = 8 9 | 10 | dialog_upper_space = 24 ; 16 11 | dialog_total_height = 41 ; height until next IRQ 12 | 13 | .segment "DLGRAM" 14 | dlg_chartimer: .res 1 ; when this timer ticks down to zero, show a new character 15 | dlg_cursor_x: .res 1 ; the X position of the cursor 16 | dlg_cursor_y: .res 1 ; the Y position of the cursor 17 | dlg_crsr_home: .res 1 ; the home X position (on the $0A/'\n' character, will go here and advance row) 18 | dlg_port_pal: .res 1 ; the palette used by the portrait 19 | dlg_port_pala: .res 1 ; the allocated palette 20 | dlg_temporary: .res 1 21 | dlg_skipping: .res 1 ; is the cutscene being skipped 22 | dlg_havenext: .res 1 ; if this dialog has a "next" dialog after it 23 | dlg_upds1: .res 32 24 | dlg_upds2: .res 32 25 | dlg_upds3: .res 32 26 | dlg_walkdstx: .res 1 27 | dlg_walkdsty: .res 1 28 | dlg_speaker: .res 1 29 | dlg_colnum: .res 1 ; used by dlg_nmi_clear_256 30 | 31 | .segment "DLGTEMP" 32 | 33 | ; 768 bytes - 256 for each row of text. 34 | dlg_bitmap: .res 32*24 35 | 36 | .align $100 37 | ; columns to be updated 38 | 39 | dlg_updpaddrlo: .res 32*3 40 | dlg_updpaddrhi: .res 32*3 41 | 42 | ; update count 43 | dlg_updc1: .res 1 44 | dlg_updc2: .res 1 45 | dlg_updc3: .res 1 46 | dlg_updccurr: .res 1 47 | dlg_endnoclear: .res 1 48 | dlg_waittimer: .res 1 49 | dlg_speaktimer: .res 1 50 | dlg_portraitx: .res 1 51 | dlg_portraitid: .res 1 52 | dlg_facing: .res 1 ; 0 - right, non-zero - left 53 | dlg_portrait: .res 25 54 | 55 | .segment "PRG_DIAL" 56 | .include "d_font.asm" 57 | .include "d_update.asm" 58 | .include "d_portra.asm" 59 | .include "d_nmi.asm" 60 | -------------------------------------------------------------------------------- /src/prg_ents.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | .segment "PRG_ENTS" 3 | 4 | .include "s_entity.asm" 5 | .include "s_pldraw.asm" 6 | .include "s_bgfx.asm" 7 | .include "s_title.asm" 8 | -------------------------------------------------------------------------------- /src/prg_game.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_GAME" 4 | 5 | .include "game.asm" 6 | .include "lvltable.asm" 7 | .include "dialogif.asm" -------------------------------------------------------------------------------- /src/prg_phys.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; This bank relates itself to Player Physics. 4 | .segment "PRG_PHYS" 5 | 6 | .include "p_physic.asm" 7 | .include "p_trace.asm" 8 | .include "p_scroll.asm" 9 | 10 | .proc ph_leaveroomU 11 | ldx #gm_leaveroomU_FAR 13 | lda #prgb_xtra 14 | jmp far_call2 15 | .endproc 16 | 17 | .proc ph_leaveroomD 18 | ldx #gm_leaveroomD_FAR 20 | lda #prgb_xtra 21 | jmp far_call2 22 | .endproc 23 | 24 | .proc ph_leaveroomL 25 | ldx #gm_leaveroomL_FAR 27 | lda #prgb_xtra 28 | jsr far_call2 29 | lda temp12 30 | rts 31 | .endproc 32 | 33 | .proc ph_leaveroomR 34 | ldx #gm_leaveroomR_FAR 36 | lda #prgb_xtra 37 | jmp far_call2 38 | .endproc 39 | -------------------------------------------------------------------------------- /src/prg_ttle.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_TTLE" 4 | 5 | .include "title/rle.asm" 6 | .include "title/title.asm" 7 | .include "title/overwld.asm" 8 | .include "title/prologue.asm" 9 | .include "title/titlescr.asm" 10 | .include "title/mountain.asm" 11 | .include "title/helper.asm" 12 | -------------------------------------------------------------------------------- /src/prg_xtra.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | .segment "PRG_XTRA" 4 | 5 | .include "extra/lettergfx.asm" 6 | .include "extra/levelend.asm" 7 | .include "extra/letter.asm" 8 | .include "extra/chcomp.asm" 9 | .include "x_rmtran.asm" 10 | .include "x_rle.asm" 11 | -------------------------------------------------------------------------------- /src/prologue.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | gamemode_prologue_update_NEAR: 4 | jmp gamemode_prologue_update_FAR 5 | 6 | gamemode_prologue: 7 | lda #ps_1stfr 8 | bit prolctrl 9 | bne gamemode_prologue_update_NEAR 10 | 11 | jsr aud_reset 12 | 13 | ; Load the title bank. 14 | lda #mmc3bk_prg0 15 | ldy #prgb_ttle 16 | jsr mmc3_set_bank 17 | 18 | jmp gamemode_prologue_init_FAR 19 | -------------------------------------------------------------------------------- /src/s_bgfx.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: s_init_starry_night 4 | ; desc: Initializes the starry night background. This is not meant to be called 5 | ; by itself, because it falls through to s_update_starry_night. 6 | .proc s_init_starry_night 7 | ldy #0 8 | loopInit: 9 | jsr rand 10 | sta stars_x, y 11 | 12 | jsr rand 13 | sta stars_y, y 14 | 15 | jsr rand 16 | and #31 17 | sta stars_state, y 18 | 19 | iny 20 | cpy #max_stars 21 | bne loopInit 22 | 23 | lda #1 24 | sta starsbgctl 25 | ; fallthrough 26 | .endproc 27 | 28 | ; ** SUBROUTINE: s_update_starry_night 29 | ; desc: Updates Chapter 2's starry night background. 30 | .proc s_update_starry_night 31 | lda starsbgctl 32 | beq s_init_starry_night 33 | 34 | lda roomflags2 35 | and #r2_outside 36 | beq return 37 | 38 | jsr s_bg_allocate_palette 39 | ora #obj_backgd 40 | sta temp3 41 | 42 | ; Updates and draws all of the starry particles. 43 | ldy #0 44 | loopDraw: 45 | sty temp1 46 | 47 | lda stars_x, y 48 | sta x_crd_temp 49 | lda stars_y, y 50 | sta y_crd_temp 51 | 52 | ; occlusion check!! 53 | jsr s_bg_check_occluded 54 | bne @continue 55 | 56 | ; compute the sprite 57 | 58 | ldx temp1 59 | ldy stars_state, x 60 | lda star_sprites, y 61 | tay 62 | 63 | ldx oam_wrhead 64 | lda y_crd_temp 65 | sta oam_buf, x 66 | inx 67 | 68 | tya 69 | sta oam_buf, x 70 | inx 71 | 72 | lda temp3 73 | sta oam_buf, x 74 | inx 75 | 76 | lda x_crd_temp 77 | sta oam_buf, x 78 | inx 79 | 80 | stx oam_wrhead 81 | 82 | @continue: 83 | ldy temp1 84 | iny 85 | cpy #max_stars 86 | bne loopDraw 87 | 88 | ; If we're on the 8th frame, then increment each star's state. 89 | ; Add gravity to them. If they fall off screen, then respawn with 90 | ; a new X (0-255) and Y (0) coordinate. 91 | 92 | ldx #0 93 | loopUpdate: 94 | lda dbenable 95 | cmp #3 96 | bcs @dontApplyGravity 97 | 98 | txa 99 | and #1 100 | 101 | ; set carry to add +1 102 | sec 103 | adc stars_y, x 104 | bcc @notOffScreen 105 | 106 | jsr rand 107 | sta stars_x, x 108 | lda #0 109 | 110 | @notOffScreen: 111 | sta stars_y, x 112 | 113 | @dontApplyGravity: 114 | lda framectr 115 | and #%00000111 116 | bne @continue 117 | 118 | ldy stars_state, x 119 | lda stars_successors, y 120 | sta stars_state, x 121 | 122 | @continue: 123 | inx 124 | cpx #max_stars 125 | bne loopUpdate 126 | 127 | return: 128 | rts 129 | 130 | star_sprites: 131 | .byte $A7,$A7,$A9,$A9,$A7,$A7,$A9,$A9 ; type 1 132 | 133 | .byte $AB,$AD,$AF,$A7,$A9,$AF,$AD,$AB ; type 2 134 | .byte $A9,$AF,$AD,$AB,$AB,$AD,$AF,$A7 ; type 3 135 | 136 | .byte $A1,$A3,$A5,$A7,$A5,$A3,$A1,$A1 ; type 4 137 | 138 | stars_successors: 139 | .byte $01,$02,$03,$04,$05,$06,$07,$00 140 | .byte $09,$0A,$0B,$0C,$0D,$0E,$0F,$08 141 | .byte $11,$12,$13,$14,$15,$16,$17,$10 142 | .byte $19,$1A,$1B,$1C,$1D,$1E,$19,$19 143 | .endproc 144 | 145 | ; ** SUBROUTINE: s_bg_check_occluded 146 | ; desc: Checks if this star is being occluded by a solid tile. 147 | ; parameters: x_crd_temp, y_crd_temp 148 | .proc s_bg_check_occluded 149 | lda dialogsplit 150 | beq :+ 151 | 152 | lda y_crd_temp 153 | cmp #60 154 | bcs :+ 155 | lda #1 156 | rts 157 | 158 | : lda x_crd_temp 159 | clc 160 | adc #3 161 | sta temp4 162 | lda #0 163 | adc #0 164 | sta temp5 165 | 166 | lda temp4 167 | clc 168 | adc camera_x 169 | sta temp4 170 | 171 | lda camera_x_pg 172 | adc temp5 173 | ror 174 | 175 | lda temp4 176 | ror 177 | lsr 178 | lsr 179 | ; [0-63] 180 | tax 181 | 182 | lda y_crd_temp 183 | clc 184 | adc #8 185 | clc 186 | adc camera_y_sub 187 | lsr 188 | lsr 189 | lsr 190 | clc 191 | adc vertoffshack 192 | cmp #30 193 | bcc :+ 194 | sbc #30 195 | : tay 196 | 197 | jsr h_comp_addr 198 | lda (lvladdr), y 199 | rts 200 | .endproc 201 | 202 | ; ** SUBROUTINE: s_bg_allocate_palette 203 | ; desc: Attempts to allocate a palette for the starry background. 204 | ; If fails, just returns the player's palette. 205 | .proc s_bg_allocate_palette 206 | lda sprpalcount 207 | cmp #3 208 | bcs @returnZero 209 | 210 | ; it's go time! 211 | lda #pal_blue 212 | jmp gm_allocate_palette 213 | 214 | @returnZero: 215 | ; return 0 to prevent flickering (normally, we'd return 1, but 1 may oscillate) 216 | lda #0 217 | rts 218 | .endproc 219 | 220 | ; ** SUBROUTINE: s_update_bg_effects 221 | ; desc: Updates background effects in the game. 222 | .proc s_update_bg_effects 223 | lda levelnumber 224 | cmp #2 225 | beq @level2 226 | rts 227 | 228 | @level2: 229 | jmp s_update_starry_night 230 | .endproc 231 | -------------------------------------------------------------------------------- /src/s_title.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; This just gets more insane. Now, title code inside of PRG_PAUS? Gimme a break. 4 | 5 | 6 | ; This looks bad, but trust me 7 | .proc s_check_select_a 8 | lda p1_cont 9 | and #(cont_select | cont_a) 10 | beq @return 11 | 12 | lda p1_conto 13 | and #(cont_select | cont_a) 14 | bne @returnZero 15 | 16 | lda #1 17 | rts 18 | 19 | @returnZero: 20 | lda #0 21 | @return: 22 | rts 23 | .endproc 24 | 25 | .proc s_check_select_a_b 26 | lda p1_cont 27 | and #(cont_select | cont_a | cont_b) 28 | beq @return 29 | 30 | lda p1_conto 31 | and #(cont_select | cont_a | cont_b) 32 | bne @returnZero 33 | 34 | lda #1 35 | rts 36 | 37 | @returnZero: 38 | lda #0 39 | @return: 40 | rts 41 | .endproc 42 | 43 | .proc s_check_b 44 | lda p1_cont 45 | and #cont_b 46 | beq @return 47 | 48 | lda p1_conto 49 | and #cont_b 50 | bne @returnZero 51 | 52 | lda #1 53 | rts 54 | 55 | @returnZero: 56 | lda #0 57 | @return: 58 | rts 59 | .endproc 60 | 61 | .proc s_update_title_aux 62 | lda tl_cschctrl 63 | bne isControlSchemeStuffOpen 64 | 65 | ; well, it's closed 66 | jsr s_check_select_a_b 67 | beq @dontOpen 68 | jmp s_open_control_scheme 69 | 70 | @dontOpen: 71 | rts 72 | 73 | isControlSchemeStuffOpen: 74 | ; well, it's open 75 | jsr s_check_b 76 | beq @dontExit 77 | jmp s_close_control_scheme 78 | 79 | @dontExit: 80 | jsr s_check_select_a 81 | beq @dontSwitch 82 | 83 | inc ctrlscheme 84 | lda ctrlscheme 85 | cmp #(cns_max+1) 86 | bne @doneSwitch 87 | 88 | lda #cns_min 89 | sta ctrlscheme 90 | 91 | @doneSwitch: 92 | jsr s_update_control_scheme 93 | 94 | @dontSwitch: 95 | rts 96 | .endproc 97 | 98 | .proc s_open_control_scheme 99 | inc tl_cschctrl 100 | jmp s_update_control_scheme 101 | .endproc 102 | 103 | .proc s_close_control_scheme 104 | dec tl_cschctrl 105 | 106 | lda #$20 107 | sta vmcaddr+1 108 | lda #$A0 109 | sta vmcaddr 110 | lda #$01 111 | sta vmcsrc 112 | sta vmcsrc+1 113 | lda #$20 114 | sta vmccount 115 | 116 | lda nmictrl2 117 | ora #nc2_vmemcpy 118 | sta nmictrl2 119 | rts 120 | .endproc 121 | 122 | .proc s_update_control_scheme 123 | ldy #0 124 | : lda text_control_scheme_main, y 125 | sta temprow1, y 126 | iny 127 | cpy #32 128 | bne :- 129 | 130 | ; depending on the current control scheme 131 | lda ctrlscheme 132 | asl 133 | asl 134 | tay 135 | 136 | ldx #0 137 | : lda text_ctrl_schemes, y 138 | sta temprow1+25, x 139 | inx 140 | iny 141 | cpx #4 142 | bne :- 143 | 144 | lda #$20 145 | sta vmcaddr+1 146 | lda #$A0 147 | sta vmcaddr 148 | lda #temprow1 151 | sta vmcsrc+1 152 | lda #$20 153 | sta vmccount 154 | 155 | lda nmictrl2 156 | ora #nc2_vmemcpy 157 | sta nmictrl2 158 | 159 | rts 160 | .endproc 161 | 162 | text_control_scheme_main: 163 | .byte $00,$00,$00,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$00 164 | .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$00,$00,$00 165 | 166 | text_ctrl_schemes: 167 | .byte $FF,$FF,$FF,$FF ; [indeterminate] 168 | .byte $2B,$2C,$2D,$2E ; cns_console 169 | .byte $2B,$2C,$2D,$2F ; cns_emulat 170 | .byte $27,$28,$29,$2A ; cns_snes 171 | -------------------------------------------------------------------------------- /src/title.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | gamemode_title: 4 | lda #ts_1stfr 5 | bit titlectrl ; might need to update the screen buffer 6 | bne gamemode_title_update_NEAR ; in PRG_TTLE 7 | 8 | ; have to reset audio data because DPCM samples are loaded in at $C000 9 | ; and we want to use that bank for title screen and overworld data. 10 | ; We have 8K at our disposal. 11 | jsr aud_reset 12 | 13 | ; Load said bank. 14 | lda #mmc3bk_prg0 15 | ldy #prgb_ttle 16 | jsr mmc3_set_bank 17 | 18 | jmp gamemode_title_init_FAR 19 | 20 | gamemode_title_update_NEAR: 21 | jmp gamemode_title_update_FAR 22 | 23 | tl_gameswitchpcard: 24 | ; We will want to show the postcard. 25 | ; Since the bank with the postcard code is already loaded, indeed we can 26 | ; just call it. 27 | stx levelnumber 28 | 29 | jsr fade_out 30 | 31 | jsr postcard 32 | 33 | ; Fall through to tl_gameswitch 34 | ldx levelnumber 35 | 36 | tl_gameswitch_nofade: 37 | lda #gm_game 38 | sta gamemode 39 | lda #0 40 | sta gamectrl 41 | sta musictable 42 | sta musictable+1 43 | jsr gm_set_level 44 | jsr ow_clear_irq 45 | rts 46 | 47 | tl_prolswitch: 48 | jsr fade_out 49 | 50 | tl_prolswitch_nofade: 51 | lda #gm_prologue 52 | sta gamemode 53 | lda #0 54 | sta prolctrl 55 | jsr ow_clear_irq 56 | rts 57 | 58 | tl_gameswitch: 59 | stx levelnumber 60 | lda #0 61 | sta fadeupdrt+1 62 | jsr fade_out 63 | ldx levelnumber 64 | jmp tl_gameswitch_nofade 65 | 66 | .proc ow_clear_irq 67 | sei 68 | lda #irq_idle 71 | sta irqaddr+1 72 | lda #0 73 | sta miscsplit 74 | cli 75 | rts 76 | .endproc 77 | 78 | ; These belong in PRG_TTLE, but I don't have enough space there. 79 | p_text0: .byte " This is it, Made{ne. " 80 | p_text1: .byte " Just breathe. " 81 | p_text2: .byte " Why are you so nervous? " 82 | p_text3: .byte " You can do this. " 83 | p_texttable: 84 | .word p_text0 85 | .word p_text1 86 | .word p_text2 87 | .word p_text3 88 | -------------------------------------------------------------------------------- /src/title/helper.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | .proc postcard 4 | ldx #postcard_XTRA 6 | lda #prgb_xtra 7 | jmp far_call2 8 | .endproc 9 | -------------------------------------------------------------------------------- /src/title/mountain.asm: -------------------------------------------------------------------------------- 1 | 2 | MTN_data: 3 | .byte $30,$00,$30,$0d,$01,$00,$30,$1d,$02,$03,$04,$00,$30,$1c,$05,$06 4 | .byte $07,$00,$30,$1b,$08,$09,$0a,$0b,$0c,$00,$30,$1a,$0d,$0e,$0a,$0f 5 | .byte $10,$00,$30,$02,$11,$12,$00,$30,$15,$13,$14,$15,$0f,$16,$00,$00 6 | .byte $08,$17,$18,$00,$30,$15,$13,$19,$1a,$1b,$1c,$00,$00,$1d,$0e,$0f 7 | .byte $1e,$00,$30,$0b,$fd,$1f,$20,$6d,$23,$30,$03,$24,$13,$19,$25,$26 8 | .byte $1c,$27,$23,$28,$14,$0f,$10,$23,$20,$29,$2a,$2b,$fe,$00,$30,$05 9 | .byte $fd,$1f,$2c,$2d,$1f,$30,$02,$2e,$13,$13,$2f,$f0,$f1,$f2,$f3,$f4 10 | .byte $f5,$f6,$0f,$16,$f7,$f7,$f8,$f9,$3a,$fe,$00,$30,$05,$fd,$3b,$3b 11 | .byte $3c,$1f,$1f,$f7,$3d,$0f,$3a,$1c,$3e,$3f,$40,$e0,$e1,$e2,$e3,$e4 12 | .byte $0f,$e5,$e6,$e7,$e8,$e9,$fe,$00,$30,$05,$fd,$f7,$30,$03,$ea,$eb 13 | .byte $ec,$0f,$3a,$ed,$3f,$3f,$ee,$fa,$9a,$66,$21,$f7,$0f,$84,$cd,$ef 14 | .byte $dd,$2b,$fe,$00,$30,$05,$fd,$de,$df,$df,$22,$5b,$5c,$5d,$5e,$5f 15 | .byte $60,$3f,$3f,$61,$62,$63,$64,$65,$f7,$67,$68,$69,$6a,$6b,$6c,$fe 16 | .byte $00,$30,$05,$fd,$1f,$6e,$6f,$70,$71,$72,$73,$74,$75,$76,$77,$78 17 | .byte $79,$7a,$7b,$7c,$7d,$7e,$7f,$80,$81,$82,$83,$1f,$fe,$00,$30,$05 18 | .byte $fd,$3c,$85,$86,$87,$88,$f7,$89,$8a,$8b,$8c,$3a,$3a,$0f,$8d,$8e 19 | .byte $66,$8f,$90,$7f,$7f,$91,$92,$93,$94,$fe,$00,$30,$05,$fd,$95,$f7 20 | .byte $1f,$96,$97,$83,$f7,$98,$98,$99,$3a,$3a,$0f,$9b,$9c,$9d,$9e,$9f 21 | .byte $a0,$a1,$a2,$a3,$a4,$a5,$fe,$00,$30,$05,$fd,$a6,$3a,$a7,$f7,$a8 22 | .byte $a9,$aa,$ab,$ac,$ad,$ae,$0f,$0f,$9b,$af,$b0,$8a,$8b,$b1,$b2,$b3 23 | .byte $f7,$29,$29,$fe,$00,$30,$05,$fd,$f7,$b4,$b5,$f7,$f7,$83,$f7,$b6 24 | .byte $0f,$b7,$f7,$b8,$b9,$ba,$bb,$bc,$bd,$f7,$be,$bf,$c0,$a9,$c1,$c2 25 | .byte $fe,$00,$30,$05,$fd,$c3,$30,$05,$c4,$c5,$c6,$3a,$c4,$3a,$c7,$c8 26 | .byte $c9,$c7,$ca,$f7,$de,$cb,$de,$cc,$1f,$0f,$fe,$00,$30,$05,$fd,$3a 27 | .byte $30,$03,$cc,$ce,$cf,$d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$3a,$d9 28 | .byte $1f,$1f,$da,$db,$cc,$dc,$fe,$00,$30,$06,$ff,$30,$17,$00,$30,$03 29 | .byte $30,$00 30 | 31 | MTN_attr: 32 | .byte $00,$00,$00,$00,$00,$00,$00,$00 33 | .byte $00,$00,$50,$50,$50,$50,$00,$00 34 | .byte $00,$00,$00,$54,$00,$00,$00,$00 35 | .byte $00,$00,$00,$55,$51,$51,$00,$00 36 | .byte $00,$00,$84,$55,$a5,$75,$a8,$00 37 | .byte $00,$00,$84,$69,$aa,$ff,$21,$00 38 | .byte $00,$00,$08,$0a,$02,$0a,$00,$00 39 | .byte $00,$00,$00,$00,$00,$00,$00,$00 40 | 41 | OWL_drawer_data: 42 | .byte $01,$00,$01,$07,$86,$8c,$01,$0d,$87,$00,$01,$0f,$8a,$00,$01,$0d 43 | .byte $8b,$00,$01,$0f,$8a,$00,$01,$0d,$8b,$00,$01,$0f,$8a,$00,$01,$0d 44 | .byte $8b,$00,$01,$0f,$8a,$00,$01,$0d,$8b,$00,$01,$0f,$8a,$00,$01,$05 45 | .byte $82,$00,$00,$20,$81,$00,$20,$00,$8b,$00,$01,$0f,$8a,$00,$01,$0d 46 | .byte $8b,$00,$01,$0f,$8a,$00,$01,$02,$73,$74,$75,$00,$01,$07,$8b,$00 47 | .byte $01,$0f,$8a,$00,$01,$02,$83,$84,$85,$82,$00,$00,$80,$00,$01,$03 48 | .byte $8b,$00,$01,$0f,$8a,$00,$01,$02,$00,$94,$00,$00,$01,$07,$8b,$00 49 | .byte $01,$0f,$8a,$00,$01,$0d,$8b,$00,$01,$0f,$8a,$00,$01,$04,$39,$3a 50 | .byte $3b,$3c,$00,$01,$04,$8b,$00,$01,$0f,$8a,$00,$01,$0d,$8b,$00,$01 51 | .byte $0f,$88,$8d,$01,$0d,$89,$00,$01,$47,$01,$00 52 | 53 | -------------------------------------------------------------------------------- /src/title/prologue.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | defwaittimer = 120 4 | deffadetimer = 8 5 | text_address = $21E0 6 | defcameray = 4 7 | 8 | pl_load_text: 9 | lda p_textnum 10 | asl 11 | tax 12 | lda p_texttable, x 13 | sta p_textaddr 14 | inx 15 | lda p_texttable, x 16 | sta p_textaddr+1 17 | 18 | lda #32 19 | sta p_textlen 20 | 21 | ; start clearing 22 | lda nmictrl 23 | ora #nc_prolclr 24 | sta nmictrl 25 | 26 | lda #0 27 | sta p_textoffs 28 | sta pl_ppudata 29 | lda #text_address 32 | sta pl_ppuaddr + 1 33 | rts 34 | 35 | ; ** SUBROUTINE: pl_select_banks 36 | ; desc: Selects the correct graphics banks for the prologue intro sequence. 37 | pl_select_banks: 38 | ldy #chrb_gensp1 39 | sty spr2_bknum 40 | 41 | ldy #chrb_dmain 42 | sty bg0_bknum 43 | rts 44 | 45 | gamemode_prologue_init_FAR: 46 | lda #0 47 | sta p_textnum 48 | sta p_textlen 49 | sta p_texttimer 50 | sta pl_ppuaddr 51 | sta pl_state 52 | sta ppu_mask ; disable rendering 53 | sta scroll_x 54 | sta scroll_y 55 | sta scroll_flags 56 | sta camera_x 57 | sta camera_y 58 | sta camera_x_pg 59 | sta camera_y_hi 60 | jsr vblank_wait 61 | 62 | lda prolctrl 63 | and #ps_candoit 64 | beq :+ 65 | 66 | lda #3 67 | sta p_textnum 68 | 69 | : ldy #init_palette 72 | sty paladdr+1 73 | jsr load_palette 74 | 75 | lda #$20 76 | jsr clear_nt 77 | jsr pl_select_banks 78 | jsr tl_init_snow 79 | 80 | lda prolctrl 81 | ora #ps_1stfr 82 | sta prolctrl 83 | 84 | lda nmictrl 85 | ora #nc_turnon 86 | sta nmictrl 87 | 88 | jsr vblank_wait 89 | 90 | gamemode_prologue_update_FAR: 91 | ; just a regular update 92 | jsr tl_update_snow 93 | jsr tl_render_snow 94 | 95 | lda #defcameray 96 | sta camera_y 97 | 98 | lda p1_conto 99 | eor #$FF 100 | and p1_cont 101 | and #(cont_start|cont_a) 102 | bne @gameswitch_ ; allow skipping by pressing START 103 | 104 | lda pl_state 105 | cmp #pls_wrtext 106 | beq @writeText 107 | cmp #pls_wait 108 | beq @wait 109 | cmp #pls_fade 110 | beq @fade 111 | 112 | ; default state: load text 113 | ldx #3 114 | lda prolctrl 115 | and #ps_candoit 116 | beq :+ 117 | ldx #4 118 | : stx temp11 119 | 120 | ldx p_textnum 121 | cpx temp11 122 | beq @gameswitch 123 | 124 | jsr pl_load_text 125 | 126 | inc p_textnum 127 | 128 | inc pl_state 129 | rts 130 | 131 | @fade: 132 | lda p_texttimer 133 | and #1 134 | bne :+ 135 | lda #ps_dofade 136 | ora prolctrl 137 | sta prolctrl 138 | 139 | : dec p_texttimer 140 | bne @updateReturn 141 | 142 | lda #0 143 | sta pl_state 144 | sta p_texttimer 145 | beq @updateReturn 146 | 147 | @gameswitch_: 148 | jmp @gameswitch 149 | 150 | @wait: 151 | dec p_texttimer 152 | bne @updateReturn 153 | 154 | ; increment state to fadeout 155 | lda #deffadetimer 156 | sta p_texttimer 157 | inc pl_state 158 | bne @updateReturn 159 | 160 | @writeText: 161 | lda #0 162 | sta pl_ppuaddr 163 | sta pl_ppuaddr + 1 164 | 165 | lda p_textlen 166 | bne :+ 167 | 168 | ; set wait timer 169 | lda #defwaittimer 170 | sta p_texttimer 171 | 172 | ; increment state 173 | inc pl_state 174 | @updateReturn: 175 | rts 176 | 177 | : inc p_texttimer 178 | lda p_texttimer 179 | and #1 180 | beq @updateReturn 181 | 182 | ; push a character of text 183 | ldy #0 184 | lda (p_textaddr), y 185 | sta pl_ppudata 186 | 187 | inc p_textaddr 188 | bne :+ 189 | inc p_textaddr + 1 190 | 191 | : dec p_textlen 192 | 193 | clc 194 | lda #text_address 199 | adc #0 200 | sta pl_ppuaddr + 1 201 | 202 | inc p_textoffs 203 | rts 204 | 205 | @gameswitch: 206 | lda prolctrl 207 | and #ps_candoit 208 | bne @exitToOverworld 209 | 210 | ldx #0 ; select level zero 211 | jmp tl_gameswitch 212 | 213 | @exitToOverworld: 214 | jmp tl_owldswitch 215 | -------------------------------------------------------------------------------- /src/title/rle.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: nexxt_rle_decompress 4 | ; desc: Decompresses the NEXXT RLE format. 5 | ; assumes: rendering is disabled 6 | ; parameters: 7 | ; X - high byte of data 8 | ; A - low byte of data 9 | .proc nexxt_rle_decompress 10 | _RLE_LOW = temp1 11 | _RLE_HIGH = temp2 12 | _RLE_TAG = temp3 13 | _RLE_BYTE = temp4 14 | 15 | ; Set up 16 | tay 17 | stx <_RLE_HIGH 18 | lda #0 19 | sta <_RLE_LOW 20 | ; Read byte that does not appear in data, used to signal a run 21 | lda (_RLE_LOW),y 22 | sta <_RLE_TAG 23 | iny 24 | bne @tag_nowrap 25 | inc <_RLE_HIGH 26 | @tag_nowrap: 27 | @decodeloop: 28 | ; Read a byte from the stream 29 | lda (_RLE_LOW),y 30 | iny 31 | bne @main_nowrap 32 | inc <_RLE_HIGH 33 | @main_nowrap: 34 | ; If it doesn't match the run marker, output it 35 | cmp <_RLE_TAG 36 | beq @is_rle 37 | @is_literal: 38 | sta ppu_data 39 | sta <_RLE_BYTE 40 | bne @decodeloop 41 | @is_rle: 42 | ; We just saw a run marker. Load the length, stopping if zero 43 | lda (_RLE_LOW),y 44 | beq @done 45 | iny 46 | bne @len_nowrap 47 | inc <_RLE_HIGH 48 | @len_nowrap: 49 | ; The run marker followed by $01 means itself 50 | cmp #$01 51 | bcs @is_run 52 | lda <_RLE_TAG 53 | bcc @is_literal 54 | @is_run: 55 | tax ; X = length of run 56 | ; Output the most recent byte X times 57 | lda <_RLE_BYTE 58 | @runloop: 59 | sta ppu_data 60 | dex 61 | bne @runloop 62 | beq @decodeloop 63 | @done: 64 | rts 65 | .endproc 66 | -------------------------------------------------------------------------------- /src/title/title.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: print_logo 4 | ; clobbers: a, x, y 5 | ; assumes: video output disabled 6 | print_logo: 7 | ; write the actual logo, in 4 parts. 8 | lda #$20 9 | sta ppu_addr 10 | lda #$00 11 | sta ppu_addr 12 | lda #tscr_canvas 14 | jsr nexxt_rle_decompress 15 | 16 | lda #$23 17 | sta ppu_addr 18 | lda #$C0 19 | sta ppu_addr 20 | ldx #tscr_attrs 22 | lda #64 23 | jsr ppu_wrstring 24 | 25 | ; write the "PRESS START" text 26 | lda #$22 27 | sta ppu_addr 28 | lda #$CB 29 | sta ppu_addr 30 | ldx #logo_pressstart 32 | lda #9 33 | jsr ppu_wrstring 34 | 35 | ; write iProgramInCpp's name 36 | lda #$23 37 | sta ppu_addr 38 | lda #$28 39 | sta ppu_addr 40 | ldx #logo_iprogram 42 | lda #15 43 | jsr ppu_wrstring 44 | 45 | ; write "(C)2018 EXOK" 46 | lda #$23 47 | sta ppu_addr 48 | lda #$4B 49 | sta ppu_addr 50 | ldx #logo_exok 52 | lda #9 53 | jsr ppu_wrstring 54 | 55 | ; write the "DEMO V1.XX" text. 56 | lda #$20 57 | sta ppu_addr 58 | lda #$62 59 | sta ppu_addr 60 | ldx #logo_version 62 | lda #7 63 | jmp ppu_wrstring 64 | 65 | tl_owldswitch: 66 | lda #0 67 | sta fadeupdrt+1 68 | jsr fade_out 69 | 70 | lda #gm_overwld 71 | sta gamemode 72 | lda #0 73 | sta owldctrl 74 | 75 | jsr vblank_wait 76 | ;lda #0 77 | sta ppu_mask ; disable rendering 78 | rts 79 | 80 | gamemode_title_init_FAR: 81 | lda #$00 82 | sta scroll_x ; clear some fields 83 | sta scroll_y 84 | sta scroll_flags 85 | sta camera_x 86 | sta camera_y 87 | sta camera_x_pg 88 | sta camera_y_hi 89 | sta tl_cschctrl 90 | sta ppu_mask ; disable rendering 91 | sta fadeupdrt+1 92 | 93 | jsr vblank_wait ; wait for vblank 94 | 95 | ; Set the title screen palette address, we'll fade in to it. 96 | lda #title_palette 99 | sta paladdr+1 100 | 101 | lda #$20 102 | jsr clear_nt ; clear the screen 103 | 104 | jsr print_logo ; print the logo and the "PRESS BUTTON" text 105 | jsr tl_init_snow ; initialize snow 106 | 107 | lda titlectrl 108 | ora #ts_1stfr 109 | sta titlectrl 110 | 111 | jsr tl_select_banks 112 | 113 | jsr fade_in 114 | 115 | gamemode_title_update_FAR: 116 | jsr tl_update_snow 117 | jsr tl_render_snow 118 | 119 | ldx #s_update_title_aux 121 | lda #prgb_ents 122 | jsr far_call2 123 | 124 | lda #cont_start 125 | bit p1_cont 126 | beq tl_no_transition 127 | lda #gm_titletra 128 | sta gamemode 129 | lda #8 130 | sta tl_timer 131 | lda #tm_gametra 132 | sta tl_gametime 133 | tl_no_transition: 134 | rts 135 | 136 | gamemode_titletr: 137 | jsr tl_update_snow 138 | jsr tl_render_snow 139 | 140 | ldx tl_gametime 141 | dex 142 | beq tl_owldswitch 143 | stx tl_gametime 144 | rts 145 | 146 | alt_colors: 147 | .byte $27, $29 148 | .byte $17, $19 149 | .byte $07, $09 150 | -------------------------------------------------------------------------------- /src/title/titlescr.asm: -------------------------------------------------------------------------------- 1 | tscr_canvas: 2 | .byte $00,$80,$00,$fe,$80,$00,$0f,$81,$80,$00,$1e,$82,$83,$80,$00,$1c 3 | .byte $84,$85,$86,$87,$80,$00,$1a,$88,$89,$8a,$8b,$8c,$80,$00,$1a,$8d 4 | .byte $8e,$80,$8f,$90,$91,$80,$00,$12,$92,$93,$94,$92,$95,$96,$97,$98 5 | .byte $94,$92,$99,$9a,$9b,$93,$9c,$92,$93,$94,$92,$93,$80,$00,$0a,$9d 6 | .byte $9e,$9f,$a0,$9e,$a1,$a2,$a3,$80,$a4,$9e,$a5,$a6,$a7,$a8,$a9,$9f 7 | .byte $aa,$ab,$9e,$a5,$ac,$80,$00,$09,$ad,$ae,$af,$b0,$b1,$b2,$b3,$b4 8 | .byte $b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$ad,$b7,$b8,$80,$00,$0a 9 | .byte $bf,$c0,$c1,$c2,$c3,$c0,$c4,$c0,$c0,$c5,$c0,$c0,$c6,$c0,$c7,$c8 10 | .byte $c9,$ca,$cb,$cc,$cd,$ce,$80,$00,$09,$cf,$d0,$d1,$d2,$d3,$80,$00 11 | .byte $08,$d4,$d5,$d6,$d7,$d8,$d9,$da,$80,$00,$0a,$db,$dc,$dd,$80,$de 12 | .byte $df,$80,$00,$0a,$e0,$e1,$e2,$e3,$80,$00,$09,$e4,$e5,$e6,$80,$e7 13 | .byte $e8,$e9,$ea,$80,$00,$0b,$eb,$ec,$ed,$80,$00,$05,$ee,$ef,$f0,$f1 14 | .byte $f2,$f3,$f4,$f5,$80,$80,$f6,$80,$00,$0c,$f7,$f8,$f9,$fa,$80,$00 15 | .byte $06,$e1,$80,$fb,$80,$00,$14,$fc,$80,$00,$fe,$80,$00,$03,$00,$00 16 | tscr_attrs: 17 | .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 18 | .byte $00,$00,$00,$f4,$33,$00,$00,$00,$00,$aa,$fe,$b7,$ad,$aa,$aa,$00 19 | .byte $00,$5a,$da,$0a,$0a,$8e,$9b,$00,$06,$05,$09,$00,$00,$00,$0a,$02 20 | .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 21 | -------------------------------------------------------------------------------- /src/update.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | gamemodes_LO: 4 | .byte gamemode_game 12 | .byte >gamemode_title 13 | .byte >gamemode_titletr 14 | .byte >gamemode_overwd 15 | .byte >gamemode_prologue 16 | 17 | ; ** SUBROUTINE: jump_engine 18 | ; desc: Jumps to the address corresponding to the current game mode. 19 | jump_engine: 20 | ldx gamemode 21 | lda gamemodes_LO, x 22 | sta temp1 23 | lda gamemodes_HI, x 24 | sta temp1+1 25 | jmp (temp1) 26 | 27 | ; ** SUBROUTINE: rand_m2_to_p1 28 | ; desc: Gets a random value between [-2, 1] 29 | rand_m2_to_p1: 30 | ldx #0 31 | jsr rand 32 | and #3 33 | sec 34 | sbc #2 35 | bpl :+ 36 | ldx #$FF 37 | : stx temp5 38 | rts 39 | 40 | ; ** SUBROUTINE: rand_m1_to_p2 41 | ; desc: Gets a random value between [-1, 2] 42 | rand_m1_to_p2: 43 | ldx #0 44 | jsr rand 45 | and #3 46 | sec 47 | sbc #1 48 | bpl :+ 49 | ldx #$FF 50 | : stx temp5 51 | rts 52 | 53 | .include "weather.asm" 54 | .include "title.asm" 55 | .include "overwld.asm" 56 | .include "prologue.asm" 57 | 58 | ; ** SUBROUTINE: game_update 59 | ; arguments: none 60 | ; clobbers: all registers 61 | game_update: 62 | jsr com_clear_oam ; clear OAM 63 | jsr jump_engine ; jump to the corresponding game mode 64 | jmp com_calc_camera ; calculate the visual camera position 65 | 66 | ; ** SUBROUTINE: tl_select_banks 67 | ; desc: Selects the banks required to display the title screen. 68 | tl_select_banks: 69 | ldy #chrb_bgttl 70 | sty bg0_bknum 71 | 72 | ldy #chrb_bgttl+2 73 | sty bg1_bknum 74 | 75 | ldy #chrb_plrsp0 76 | sty spr0_bknum 77 | 78 | ;ldy #chrb_gensp2 79 | ;sty spr1_bknum 80 | 81 | ldy #chrb_gensp1 82 | sty spr2_bknum 83 | 84 | ;ldy #chrb_anisp0 85 | ;sty spr3_bknum 86 | rts 87 | 88 | ; ** SUBROUTINE: com_clear_oam 89 | ; arguments: none 90 | ; clobbers: A, X 91 | ; desc: clears CPU's copy of OAM 92 | com_clear_oam: 93 | lda #$FF 94 | ldx #$00 95 | stx oam_wrhead 96 | @loop: 97 | sta oam_buf, x 98 | inx 99 | inx 100 | inx 101 | inx 102 | bne @loop 103 | rts 104 | 105 | ; ** SUBROUTINE: com_calc_camera 106 | ; desc: Calculate the default scroll X/Y to cameraX/cameraY. 107 | ; This routine is called on every game mode that isn't gm_game. 108 | com_calc_camera: 109 | lda gamemode 110 | cmp #gm_game 111 | beq @return 112 | 113 | lda camera_x 114 | sta scroll_x 115 | lda camera_y 116 | sta scroll_y 117 | 118 | lda camera_x_pg 119 | and #1 120 | beq :+ 121 | lda #pctl_highx 122 | 123 | : ldx camera_y_hi 124 | beq :+ 125 | ora #pctl_highy 126 | : sta scroll_flags 127 | @return: 128 | rts 129 | -------------------------------------------------------------------------------- /src/weather.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; ** SUBROUTINE: tl_adjust_y 4 | ; arguments: a - the Y coordinate to adjust 5 | ; returns: a - the adjusted Y coordinate 6 | ; clobbers: x 7 | ; desc: adjusts a Y coordinate to fit in a [0, 224] range 8 | tl_adjust_y: 9 | tax 10 | cpx #$E0 11 | bcc tl_adjusret 12 | sbc #$E0 13 | asl 14 | asl 15 | asl 16 | asl 17 | and #%11011111 18 | tl_adjusret: 19 | rts 20 | 21 | ; ** SUBROUTINE: tl_init_snow 22 | tl_init_snow: 23 | ldy #$00 ; initialize Y coordinates 24 | tl_initloop1: 25 | jsr rand 26 | sta tl_snow_y, y 27 | iny 28 | cpy #$10 29 | bne tl_initloop1 30 | 31 | ldy #$00 ; initialize X coordinates 32 | tl_initloop2: 33 | jsr rand 34 | sta tl_snow_x, y 35 | iny 36 | cpy #$10 37 | bne tl_initloop2 38 | 39 | rts 40 | 41 | osciltable: 42 | .byte $FF,$FF,$00,$00,$00,$00,$01,$01,$01,$01,$00,$00,$00,$00,$FF,$FF 43 | 44 | ; ** SUBROUTINE: tl_update_snow 45 | tl_update_snow: 46 | inc tl_timer 47 | ldy #$00 48 | 49 | ; update Y coordinate to oscillate 50 | tl_updaupdloop: 51 | tya 52 | adc tl_timer 53 | and #$07 54 | bne tl_updadontosci 55 | tya 56 | adc tl_timer 57 | lsr 58 | lsr 59 | lsr 60 | and #$0F 61 | tax 62 | lda tl_snow_y, y 63 | clc 64 | adc osciltable, x 65 | sta tl_snow_y, y 66 | tl_updadontosci: 67 | 68 | ; update X coordinate to go left 69 | ldx tl_snow_x, y 70 | dex 71 | beq tl_updatrespawn 72 | tya 73 | and #$01 74 | bne tl_updadontdecr 75 | dex 76 | beq tl_updatrespawn 77 | tl_updadontdecr: 78 | txa 79 | sta tl_snow_x, y 80 | tl_updacontinue: 81 | 82 | ; move on to the next particle 83 | iny 84 | cpy #$10 85 | bne tl_updaupdloop 86 | rts 87 | tl_updatrespawn: ; respawn this particle 88 | lda #$FF 89 | sta tl_snow_x, y 90 | jsr rand 91 | jsr tl_adjust_y 92 | sta tl_snow_y, y 93 | jmp tl_updacontinue 94 | 95 | snow_sprites: .byte $90, $92 96 | 97 | ; ** SUBROUTINE: tl_render_snow 98 | tl_render_snow: 99 | ldy #$00 100 | tl_render_loop: 101 | lda tl_snow_y, y 102 | sta y_crd_temp 103 | lda tl_snow_x, y 104 | sta x_crd_temp 105 | tya 106 | pha 107 | and #$01 108 | tay 109 | lda snow_sprites, y 110 | tay 111 | lda #3 112 | jsr oam_putsprite 113 | pla 114 | tay 115 | iny 116 | cpy #$10 117 | bne tl_render_loop 118 | rts 119 | -------------------------------------------------------------------------------- /src/x_rle.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2025 iProgramInCpp 2 | 3 | ; This belongs in the PRG_XTRA bank. It deals with outputting the 4 | ; postcard and level end graphics. 5 | 6 | ; ** SUBROUTINE: nexxt_rle_decompress_XTRA 7 | ; desc: Decompresses the NEXXT RLE format. 8 | ; assumes: rendering is disabled 9 | ; NOTE: EXACT copy of src/title/rle.asm! Must be synched at all times! 10 | ; parameters: 11 | ; X - high byte of data 12 | ; A - low byte of data 13 | .proc nexxt_rle_decompress_XTRA 14 | _RLE_LOW = temp1 15 | _RLE_HIGH = temp2 16 | _RLE_TAG = temp3 17 | _RLE_BYTE = temp4 18 | 19 | ; Set up 20 | tay 21 | stx <_RLE_HIGH 22 | lda #0 23 | sta <_RLE_LOW 24 | ; Read byte that does not appear in data, used to signal a run 25 | lda (_RLE_LOW),y 26 | sta <_RLE_TAG 27 | iny 28 | bne @tag_nowrap 29 | inc <_RLE_HIGH 30 | @tag_nowrap: 31 | @decodeloop: 32 | ; Read a byte from the stream 33 | lda (_RLE_LOW),y 34 | iny 35 | bne @main_nowrap 36 | inc <_RLE_HIGH 37 | @main_nowrap: 38 | ; If it doesn't match the run marker, output it 39 | cmp <_RLE_TAG 40 | beq @is_rle 41 | @is_literal: 42 | sta ppu_data 43 | sta <_RLE_BYTE 44 | bne @decodeloop 45 | @is_rle: 46 | ; We just saw a run marker. Load the length, stopping if zero 47 | lda (_RLE_LOW),y 48 | beq @done 49 | iny 50 | bne @len_nowrap 51 | inc <_RLE_HIGH 52 | @len_nowrap: 53 | ; The run marker followed by $01 means itself 54 | cmp #$01 55 | bcs @is_run 56 | lda <_RLE_TAG 57 | bcc @is_literal 58 | @is_run: 59 | tax ; X = length of run 60 | ; Output the most recent byte X times 61 | lda <_RLE_BYTE 62 | @runloop: 63 | sta ppu_data 64 | dex 65 | bne @runloop 66 | beq @decodeloop 67 | @done: 68 | rts 69 | .endproc 70 | 71 | -------------------------------------------------------------------------------- /src/xtraif.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2024 iProgramInCpp 2 | 3 | ; This code belongs in the MAIN segment and is an 4 | ; interface to things in the PRG_XTRA bank. 5 | 6 | .proc xt_gener_col_r 7 | lda #h_gener_col_r 10 | sta farcalladdr+1 11 | ldy lvldatabank 12 | jmp far_call 13 | .endproc 14 | 15 | .proc xt_palette_data_column 16 | lda #h_palette_data_column 19 | sta farcalladdr+1 20 | ldy lvldatabank 21 | jmp far_call 22 | .endproc 23 | 24 | .proc xt_gener_tiles_below 25 | lda #gm_gener_tiles_below 28 | sta farcalladdr+1 29 | ldy lvldatabank 30 | jmp far_call 31 | .endproc 32 | 33 | .proc xt_gener_tiles_above 34 | lda #gm_gener_tiles_above 37 | sta farcalladdr+1 38 | ldy lvldatabank 39 | jmp far_call 40 | .endproc 41 | 42 | .proc xt_gener_mts_ents_r 43 | lda #x_gener_mts_ents_r_fixed 46 | sta farcalladdr+1 47 | ldy lvldatabank 48 | jmp far_call 49 | .endproc 50 | 51 | .proc xt_leave_doframe 52 | lda #gm_leave_doframe 55 | sta farcalladdr+1 56 | ldy lvldatabank 57 | jmp far_call 58 | .endproc 59 | 60 | .proc xt_gener_row_u 61 | lda #h_gener_row_u 64 | sta farcalladdr+1 65 | ldy lvldatabank 66 | jmp far_call 67 | .endproc 68 | 69 | .proc xt_set_room 70 | tya 71 | tax ; save room # in X 72 | 73 | ldy lvldatabank 74 | lda #mmc3bk_prg1 75 | jsr mmc3_set_bank ; change bank 76 | 77 | txa 78 | tay ; restore room # in X 79 | jsr gm_set_room 80 | 81 | ldy #prgb_xtra 82 | lda #mmc3bk_prg1 83 | jmp mmc3_set_bank ; change bank back 84 | .endproc 85 | 86 | .proc x_gener_mts_ents_r_fixed 87 | jsr h_gener_ents_r 88 | jmp h_gener_mts_r 89 | .endproc 90 | 91 | .proc gm_update_bg_effects 92 | ldx #s_update_bg_effects 94 | lda #prgb_ents 95 | jmp far_call2 96 | .endproc 97 | 98 | .proc gm_draw_player 99 | ldx #sgm_draw_player 101 | lda #prgb_ents 102 | jmp far_call2 103 | .endproc 104 | 105 | .proc gm_set_panting 106 | ldx #sgm_set_panting 108 | lda #prgb_ents 109 | jmp far_call2 110 | .endproc 111 | 112 | .proc gm_level_end 113 | ; stop music from playing - this will free up the $C000 bank 114 | jsr aud_reset 115 | 116 | ; declare the level ended with the save file also 117 | jsr save_file_level_end 118 | 119 | lda #mmc3bk_prg1 120 | ldy #prgb_xtra 121 | jsr mmc3_set_bank 122 | 123 | jmp level_end 124 | .endproc 125 | 126 | .proc gm_anim_and_draw_player 127 | ldx #sgm_anim_and_draw_player 129 | lda #prgb_ents 130 | jmp far_call2 131 | .endproc 132 | 133 | .proc sgm_anim_and_draw_player 134 | jsr sgm_anim_player 135 | jsr sgm_anim_banks 136 | jsr sgm_check_chaser 137 | jmp sgm_draw_player 138 | .endproc 139 | 140 | .proc sgm_check_chaser 141 | ; If there is a chaser active, allocate her palette. She takes priority over other entities. 142 | lda advtracesw 143 | beq :+ 144 | lda #pal_chaser 145 | jsr gm_allocate_palette 146 | : rts 147 | .endproc 148 | 149 | ; generate palette data for vertical transition 150 | xt_generate_palette_data_V: 151 | @loadCount := trantmp5 152 | ldy lvldatabank 153 | lda #mmc3bk_prg1 154 | jsr mmc3_set_bank ; change bank 155 | 156 | ; pre-generate all palette data 157 | ldy #0 158 | @palloop: 159 | sty temp6 160 | 161 | lda ntwrhead 162 | pha 163 | tya 164 | asl 165 | asl 166 | clc 167 | adc ntwrhead 168 | sta ntwrhead 169 | 170 | jsr h_palette_data_column 171 | 172 | pla 173 | sta ntwrhead 174 | 175 | ldy temp6 176 | iny 177 | cpy @loadCount 178 | bne @palloop 179 | 180 | ldy #prgb_xtra 181 | lda #mmc3bk_prg1 182 | jmp mmc3_set_bank ; change bank back 183 | --------------------------------------------------------------------------------