├── README.md ├── license.md ├── loveiskind.nes └── source ├── background1.nam ├── background2.nam ├── background3.nam ├── background4.nam ├── gfx.chr ├── loveiskind.asm └── music.nsf /README.md: -------------------------------------------------------------------------------- 1 | # computers-are-easy 2 | 3 | ![GIF](https://hxlntblob.blob.core.windows.net/nbm/easykind2.gif) 4 | 5 | ♥ ♥ ♥ 6 | 7 | Computers Are Easy, Love is Kind (v. 2.0) Rachel Simone Weil/Electronic Love Operation 2015 8 | 9 | "Computers Are Easy, Love is Kind" is an NES ROM that demonstrates basic music, sprite animation, user input, and color cycling. The ROM was made in one day, on the occasion of the US Supreme Court ruling on marriage equality (June 26, 2015). Fully-commented 6502 ASM source code and updates to the sparkle animation were released on September 11, 2015. 10 | 11 | Playing the ROM: Press up and down to change colors. Press B to toggle glitching. Press A to toggle sparkle animation. 12 | 13 | Source code: Hopefully the commented source code is of help to those wishing to know more about how NES games are written. In the FCEUX emulator (Windows only), you can watch variables update by loading the compiled ROM and choosing Debug > Hex editor. Watch values $0000 through $0015. To compile from source, use NESASM3 (not included). NESASM3 usage is nesasm3 loveiskind.asm 14 | 15 | Artist statement: What is the video-game equivalent of a love song? In my work, I seek to use obsolete technology in whimsical and romantic ways to bring people closer to one another. And while assembly language programming might seem intimidating to the newcomer, it's important to keep in mind that computers are easy! Love is kind! You can do it! 16 | 17 | As this program was written quickly, there likely remain errors or opportunities to make the code even more efficient. Perhaps you can find them. Have fun, traveler! 18 | 19 | RSW 20 | 21 | ♥ ♥ ♥ 22 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Rachel Simone Weil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /loveiskind.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hxlnt/computers-are-easy/b2d77f2733392a25f07bc2362115e360c387a357/loveiskind.nes -------------------------------------------------------------------------------- /source/background1.nam: -------------------------------------------------------------------------------- 1 | WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV012345678V976V698:VVVVVVV -------------------------------------------------------------------------------- /source/background2.nam: -------------------------------------------------------------------------------- 1 | VVVVVVV@ABCDEFGHVIGFVFIHJVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVP1Q6VR8VSRTUVVVVVVVVVV -------------------------------------------------------------------------------- /source/background3.nam: -------------------------------------------------------------------------------- 1 | VVVVVVVVVV`AaFVbHVcbdeVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -------------------------------------------------------------------------------- /source/background4.nam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hxlnt/computers-are-easy/b2d77f2733392a25f07bc2362115e360c387a357/source/background4.nam -------------------------------------------------------------------------------- /source/gfx.chr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hxlnt/computers-are-easy/b2d77f2733392a25f07bc2362115e360c387a357/source/gfx.chr -------------------------------------------------------------------------------- /source/loveiskind.asm: -------------------------------------------------------------------------------- 1 | ;♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥; 2 | ;♥ . _ _ __ . ♥; 3 | ;♥ * ( | )/_/ ; Computers Are Easy ♥; 4 | ;♥ . __( >O< ) * ; Love is Kind v. 2.0 ♥; 5 | ;♥ \_\(_|_) + ; Electronic Love Operation 2015 ♥; 6 | ;♥ + . . ♥; 7 | ;♥ ♥; 8 | ;♥ ; Playing the ROM: Press up and down to ♥; 9 | ;♥ ; change colors. Press B to toggle ♥; 10 | ;♥ ; glitching. Press A to toggle sparkle ♥; 11 | ;♥ ; animation. ♥; 12 | ;♥ ♥; 13 | ;♥ ; This source code is fully commented. ♥; 14 | ;♥ ; Hopefully it is of help to those wishing ♥; 15 | ;♥ ; to know more about how NES code is ♥; 16 | ;♥ ; written. In the FCEUX emulator (Windows ♥; 17 | ;♥ ; only), you can watch variables update by ♥; 18 | ;♥ ; loading the compiled ROM and choosing ♥; 19 | ;♥ ; Debug > Hex editor. Watch values $0000 ♥; 20 | ;♥ ; through $0015. To compile from source, ♥; 21 | ;♥ ; use NESASM3 (not included). NESASM3 usage ♥; 22 | ;♥ ; is nesasm3 loveiskind.asm ♥; 23 | ;♥ ♥; 24 | ;♥ ; This program was written in one day, on ♥; 25 | ;♥ ; the occasion of the US Supreme Court ♥; 26 | ;♥ ; ruling on marriage equality. Version 2.0 ♥; 27 | ;♥ ; has additional code commenting, and the ♥; 28 | ;♥ ; sparkle animation was changed to sync ♥; 29 | ;♥ ; with the music. As this program was ♥; 30 | ;♥ ; written quickly, there likely remain ♥; 31 | ;♥ ; errors or opportunities to make the code ♥; 32 | ;♥ ; even more efficient. Perhaps you can find ♥; 33 | ;♥ ; them. Have fun, traveler! ♥; 34 | ;♥ ♥; 35 | ;♥ ; Rachel Simone Weil ♥; 36 | ;♥ ; http://nobadmemories.com ♥; 37 | ;♥ ; http://github.com/hxlnt ♥; 38 | ;♥ ♥; 39 | ;♥ ♥; 40 | ;♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥; 41 | 42 | 43 | 44 | ;;;;;;;; + 1.0 NESASM3.0 HEADER + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 45 | ;; 46 | .inesprg 2 ; 2 16-KB banks PRG data (32KB total) ;; 47 | .ineschr 1 ; 1 8-KB bank CHR data (8KB total) ;; 48 | .inesmap 0 ; No mapper ;; 49 | .inesmir 0 ; Vertical mirroring ;; 50 | ;; 51 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 52 | 53 | 54 | ;;;;;;;; + 2.0 VARIABLES + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 55 | ;; 56 | .rsset $0000 ; Start variables at $0000 (zero page) ;; 57 | music .rs 16 ; Leave the first 16 bytes free for music ;; 58 | buttons1 .rs 1 ; Buttons pressed (P1) ;; 59 | buttons1pending .rs 1 ; Buttons pressed but not read (P1) ;; 60 | buttons1read .rs 1 ; Buttons pressed that need to be read (P1) ;; 61 | framecounter .rs 1 ; General-purpose frame counter ;; 62 | gamesetting .rs 1 ; #%76543210 ;; 63 | ; |||||||+ Glitching on (1) or off (0) ;; 64 | ; ||||||+- Sparkles on (1) or off (0) ;; 65 | ; ||||++-- Cycle through palettes: ;; 66 | ; |||| dark (00), pastel (01), ;; 67 | ; |||| default (10), or bright (11) ;; 68 | ; |||+---- Color cycle on (1) or off (0) ;; 69 | ; +++----- Not used ;; 70 | oldgamesetting .rs 1 ; Compare this against gamesetting to see ;; 71 | ; if updates are needed ;; 72 | ;; 73 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 74 | 75 | 76 | ;;;;;;;; + 3.0 CONSTANTS + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 77 | ;; 78 | INITADDR = $A999 ; Init address for music ;; 79 | LOADADDR = $A6E0 ; Load address for music ;; 80 | PLAYADDR = $A99C ; Play address for music ;; 81 | ;; 82 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 83 | 84 | 85 | ;;;;;;;; + 4.0 GAME CODE: BANK 0 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 86 | ;; 87 | .bank 0 ; Bank 0 ;; 88 | .org $8000 ; begins at address $8000 ;; 89 | ;; 90 | ;;;;;;;;;; 4.1 Console initialization ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 91 | ;; 92 | Reset: ; This code runs when console is reset ;; 93 | SEI ;; 94 | CLD ;; 95 | LDX #$40 ;; 96 | STX $4017 ;; 97 | LDX #$FF ;; 98 | TXS ;; 99 | INX ;; 100 | STX $2000 ;; 101 | STX $2001 ;; 102 | STX $4010 ;; 103 | Vblank1: ; Wait for first V-blank ;; 104 | BIT $2002 ;; 105 | BPL Vblank1 ;; 106 | ClearMem: ; Clear memory ;; 107 | LDA #$00 ;; 108 | STA $0000, x ;; 109 | STA $0100, x ;; 110 | STA $0300, x ;; 111 | STA $0400, x ;; 112 | STA $0500, x ;; 113 | STA $0600, x ;; 114 | STA $0700, x ;; 115 | LDA #$FE ;; 116 | STA $0200, x ;; 117 | INX ;; 118 | BNE ClearMem ;; 119 | Vblank2: ; Wait for second V-blank ;; 120 | BIT $2002 ;; 121 | BPL Vblank2 ;; 122 | ;; 123 | ;;;;;;;;; 4.2 Game initialization ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 124 | ;; 125 | LDA #$00 ; Initialize sound registers ;; 126 | LDX #$00 ;; 127 | ClearSoundLoop: ;; 128 | STA $4000,x ;; 129 | INX ;; 130 | CPX #$0F ;; 131 | BNE ClearSoundLoop ;; 132 | LDA #$10 ;; 133 | STA $4010 ;; 134 | LDA #$00 ;; 135 | STA $4011 ;; 136 | STA $4012 ;; 137 | STA $4013 ;; 138 | LDA #%00001111 ;; 139 | STA $4015 ;; 140 | LDA #$00 ;; 141 | LDX #$00 ;; 142 | JSR INITADDR ;; 143 | LDA #$00 ; Reset framecounter ;; 144 | STA framecounter ;; 145 | LDA #%00001000 ; Set default palette, disable glitching ;; 146 | ; and sparkles ;; 147 | STA gamesetting ;; 148 | STA oldgamesetting ;; 149 | JSR TurnScreenOff ; Disable screen rendering ;; 150 | JSR LoadBG ; Load background ;; 151 | JSR LoadSpr ; Load sprites ;; 152 | JSR TurnScreenOn ; Enable screen rendering ;; 153 | ;; 154 | ;;;;;;;;;;;; 4.3 Game loop ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 155 | ;; 156 | GameLoop: ;; 157 | JMP GameLoop ; Infinite main game loop ;; 158 | ;; 159 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 160 | 161 | 162 | ;;;;;;;; + 5.0 GAME CODE: BANK 1 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 163 | ;; 164 | .bank 1 ; Bank 1 ;; 165 | .org LOADADDR ; Starts at music LOADADDR ;; 166 | .incbin "music.nsf" ; Include binary NSF music file ;; 167 | ;; 168 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 169 | 170 | 171 | ;;;;;;;; + 6.0 GAME CODE: BANK 2 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 172 | ;; 173 | .bank 2 ; Bank 2 ;; 174 | .org $C000 ; Starts at memory address $C000 ;; 175 | ;; 176 | ;;;;;;;;;;;; 6.1 NMI ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 177 | ;; 178 | NMI: ; Non-maskable interrupt ;; 179 | PHA ; Back up registers ;; 180 | TXA ;; 181 | PHA ;; 182 | TYA ;; 183 | PHA ;; 184 | LDX framecounter ; Add one to the frame counter ;; 185 | INX ;; 186 | STX framecounter ;; 187 | JSR SpriteDMA ; Bring in sprite data (heart and sparkles) ;; 188 | LDA framecounter ; Use the framecounter to delay frames ;; 189 | AND #%00000011 ; in heart sprite animation ;; 190 | CMP #%00000011 ; When the framecounter hits #%xxxxxx11, ;; 191 | BEQ NMIAnimateHeart ; Go to the heart animation routine ;; 192 | JMP NMISparkles ; Otherwise, check if sparkles should be on ;; 193 | NMIAnimateHeart: ; Heart animation subroutine ;; 194 | LDA $0301 ; Check if the first heart tile is $00 ;; 195 | BEQ NMIAnimateHeart2; If so, go to second-frame routine ;; 196 | NMIAnimateHeart1: ; Otherwise, do the first-frame routine ;; 197 | LDA #$00 ; The animated stripes on the heart are ;; 198 | STA $0301 ; acheived by cycling through two sets of ;; 199 | LDA #$01 ; heart tiles--this is the first set ;; 200 | STA $0305 ;; 201 | LDA #$10 ;; 202 | STA $0309 ;; 203 | LDA #$11 ;; 204 | STA $030D ;; 205 | JMP NMIColorizeHeart; Jump to heart color cycling ;; 206 | NMIAnimateHeart2: ; The second-frame routine ;; 207 | LDA #$02 ; The animated stripes on the heart are ;; 208 | STA $0301 ; acheived by cycling through two sets of ;; 209 | LDA #$03 ; heart tiles--this is the second set ;; 210 | STA $0305 ;; 211 | LDA #$12 ;; 212 | STA $0309 ;; 213 | LDA #$13 ;; 214 | STA $030D ;; 215 | NMIColorizeHeart: ; Heart color-cycling subroutine ;; 216 | LDA framecounter ; Based on the framecounter value, the ;; 217 | AND #%00001100 ; heart should be assigned different ;; 218 | LSR A ; attribute values to acheive the color ;; 219 | LSR A ; cycling effect ;; 220 | STA $0302 ;; 221 | STA $0306 ;; 222 | STA $030A ;; 223 | STA $030E ;; 224 | STA $0312 ;; 225 | STA $0316 ;; 226 | STA $031A ;; 227 | STA $031E ;; 228 | NMISparkles: ; Sparkles routine ;; 229 | JSR ReadController1 ; Read P1 controller ;; 230 | LDA buttons1read ; If B is pressed ;; 231 | AND #%10000000 ;; 232 | BNE NMISparkleCheck ; Go to "Sparkle toggle" routine ;; 233 | LDA gamesetting ; Otherwise, check gamesetting ;; 234 | AND #%00000010 ; If sparkles are on, go to anim. routine ;; 235 | BNE NMISparkleAnimate2 ;; 236 | JMP NMISparkleStop ; If sparkles are off, keep 'em off ;; 237 | NMISparkleCheck: ; "Sparkle toggle" subroutine ;; 238 | LDA gamesetting ; Turn sparkles on or off depending on ;; 239 | AND #%00000010 ; "sparkle bit" of gamesetting (#%xxxxxx1x) ;; 240 | BNE NMISparkleStop ; If they should be off, turn 'em off ;; 241 | NMISparkleAnimate: ; Otherwise, turn 'em on ;; 242 | LDA gamesetting ; Update gamesetting "sparkle bit" ;; 243 | ORA #%00000010 ; (#%xxxxxx1x) ;; 244 | STA gamesetting ;; 245 | LDA #$04 ; Update sparkle tile frames ;; 246 | STA $0311 ;; 247 | LDA #$05 ;; 248 | STA $0315 ;; 249 | LDA #$14 ;; 250 | STA $0319 ;; 251 | LDA #$15 ;; 252 | STA $031D ;; 253 | NMISparkleAnimate2: ; Update sparkle tile positions ;; 254 | LDA $0310 ;; 255 | SEC ;; 256 | SBC $0234 ; Note: $0234 is a value in RAM that ;; 257 | STA $0310 ; corresponds to the melody playing on a ;; 258 | LDA $0313 ; square-wave channel, so adding or ;; 259 | SEC ; subtracting this value from the sparkle ;; 260 | SBC $0234 ; tiles' X- and Y-coordinates will create ;; 261 | STA $0313 ; an audio visualizer effect ;; 262 | LDA $0314 ;; 263 | SEC ;; 264 | SBC $0234 ;; 265 | STA $0314 ;; 266 | LDA $0317 ;; 267 | CLC ;; 268 | ADC $0234 ;; 269 | STA $0317 ;; 270 | LDA $0318 ;; 271 | CLC ;; 272 | ADC $0234 ;; 273 | STA $0318 ;; 274 | LDA $031B ;; 275 | SEC ;; 276 | SBC $0234 ;; 277 | STA $031B ;; 278 | LDA $031C ;; 279 | CLC ;; 280 | ADC $0234 ;; 281 | STA $031C ;; 282 | LDA $031F ;; 283 | CLC ;; 284 | ADC $0234 ;; 285 | STA $031F ;; 286 | JMP NMIColorSetting ; Sparkles are done, jump to palette updates;; 287 | NMISparkleStop: ; "Disable sparkles" routine ;; 288 | LDA gamesetting ; Update "sparkle bit" (#%xxxxxx1x) to ;; 289 | AND #%11111101 ; reflect that sparkles are off ;; 290 | STA gamesetting ;; 291 | LDA #$06 ; Load all sparkle tiles with a blank ($06) ;; 292 | STA $0311 ;; 293 | STA $0315 ;; 294 | STA $0319 ;; 295 | STA $031D ;; 296 | NMISparkleReset: ; Reset motion cycle for sparkles ;; 297 | LDA #$5C ; Reset Y-positions for tiles ;; 298 | STA $0310 ;; 299 | STA $0314 ;; 300 | STA $0318 ;; 301 | STA $031C ;; 302 | LDA #$7B ; Reset X-positions for tiles ;; 303 | STA $0313 ;; 304 | STA $0317 ;; 305 | STA $031B ;; 306 | STA $031F ;; 307 | NMIColorSetting: ; Check color palette setting ;; 308 | LDA buttons1read ; If up is pressed ;; 309 | AND #%00001100 ;; 310 | CMP #%00001000 ;; 311 | BEQ NMIColorInc ; Go to "Make colors darker" routine ;; 312 | CMP #%00000100 ; If down is pressed ;; 313 | BEQ NMIColorDec ; Go to "Make colors lighter" routine ;; 314 | JMP NMIGlitch ; Otherwise, go to glitch updates ;; 315 | NMIColorInc: ; "Make colors darker" routine ;; 316 | LDA gamesetting ; If colors are at darkest setting already, ;; 317 | AND #%00001100 ;; 318 | BEQ NMIGlitch ; We're done here, skip to glitch updates ;; 319 | CMP #%00001000 ; If color bits are set to Default, ;; 320 | BEQ NMIColorBright ; Go to "Make it Bright" routine ;; 321 | CMP #%00000100 ; If color bits are set to Pastel, ;; 322 | BEQ NMIColorDefault ; Go to "Make it Default" routine ;; 323 | JMP NMIColorDark ; Otherwise, go to "Make it Dark" routine ;; 324 | NMIColorDec: ; "Make colors lighter" routine ;; 325 | LDA gamesetting ; If colors are at lightest setting already,;; 326 | AND #%00001100 ;; 327 | CMP #%00000100 ;; 328 | BEQ NMIGlitch ; We're done here, skip to glitch updates ;; 329 | CMP #%00001100 ; If color bits are set to Bright, ;; 330 | BEQ NMIColorDefault ; Go to "Make it Default" routine ;; 331 | CMP #%00001000 ; If color bits are set to Default, ;; 332 | BEQ NMIColorPastel ; Go to "Make it Pastel" routine ;; 333 | JMP NMIColorBright ; Else, go to "Make it Bright" routine ;; 334 | NMIColorDefault: ; "Make it Default" subroutine ;; 335 | JSR LoadDefaultPal ; Do "Load Default palette" subroutine ;; 336 | LDA gamesetting ; Update color bits to reflect new palette ;; 337 | ORA #%00001000 ;; 338 | AND #%11111011 ;; 339 | STA gamesetting ;; 340 | JMP NMIGlitch ; Skip to glitch updates ;; 341 | NMIColorDark: ; "Make it Dark" routine ;; 342 | JSR LoadDarkPal ; Do "Load Dark palette" subroutine ;; 343 | LDA gamesetting ; Update color bits to reflect new palette ;; 344 | AND #%11110011 ;; 345 | STA gamesetting ;; 346 | JMP NMIGlitch ; Skip to glitch updates ;; 347 | NMIColorBright: ; "Make it Bright" routine ;; 348 | JSR LoadBrightPal ; Do "Load Bright palette" subroutine ;; 349 | LDA gamesetting ; Update color bits to reflect new palette ;; 350 | ORA #%00001100 ;; 351 | STA gamesetting ;; 352 | JMP NMIGlitch ; Skip to glitch updates ;; 353 | NMIColorPastel: ; "Make it Pastel" routine ;; 354 | JSR LoadPastelPal ; Do "Load Pastel palette" subroutine ;; 355 | LDA gamesetting ; Update color bits to reflect new palette ;; 356 | ORA #%00000100 ;; 357 | AND #%11110111 ;; 358 | STA gamesetting ;; 359 | NMIGlitch: ; Check whether screen should be glitching ;; 360 | LDA #$00 ; Disable scrolling ;; 361 | STA $2005 ;; 362 | STA $2005 ;; 363 | JSR TurnScreenOn ; Turn on screen rendering ;; 364 | LDA buttons1read ; If A is pressed ;; 365 | AND #%01000000 ; Go to "Glitch toggle" routine ;; 366 | BNE NMICheckForGlitch ;; 367 | LDA gamesetting ; If "glitch bit" (#%xxxxxxx1) is on, ;; 368 | AND #%00000001 ;; 369 | BNE NMIGlitch2 ; Go get glitchy ;; 370 | JMP NMIDone ; Otherwise, jump to end of NMI routine ;; 371 | NMICheckForGlitch: ; "Glitch toggle" routine ;; 372 | LDA gamesetting ; Check gamesetting "glitch bit" ;; 373 | AND #%00000001 ; If it's off, ;; 374 | CMP #%00000001 ;; 375 | BEQ NMINoGlitch ; Don't glitch ;; 376 | NMIGlitch2: ; Otherwise, get glitchy ;; 377 | LDA framecounter ; Load value in framecounter ;; 378 | STA $2006 ; Throw it in graphics registers ;; 379 | STA $2007 ; (When this is done with rendering on, ;; 380 | STA $2007 ; things get glitchy) ;; 381 | LDA gamesetting ; Set "glitch bit" to on ;; 382 | ORA #%00000001 ;; 383 | STA gamesetting ;; 384 | JMP NMIDone ; Finish up NMI routine ;; 385 | NMINoGlitch: ; "Don't glitch" routine ;; 386 | LDA gamesetting ; Set "glitch bit" to off ;; 387 | AND #%11111110 ;; 388 | STA gamesetting ;; 389 | NMIDone: ; Final actions in NMI ;; 390 | JSR PLAYADDR ; Update audio ;; 391 | PLA ; Restore registers ;; 392 | TAY ;; 393 | PLA ;; 394 | TAX ;; 395 | PLA ;; 396 | RTI ; NMI is done ;; 397 | ;; 398 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 399 | ;; 400 | ;;;;;;;;;;;; 6.2 Subroutines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 401 | ;; 402 | SpriteDMA: ; Sprite DMA subroutine ;; 403 | LDA #$00 ;; 404 | STA $2003 ;; 405 | LDA #$03 ;; 406 | STA $4014 ;; 407 | RTS ;; 408 | LoadDefaultPal: ; "Load Default palette" subroutine ;; 409 | LDA $2002 ;; 410 | LDA #$3F ;; 411 | STA $2006 ;; 412 | LDA #$00 ;; 413 | STA $2006 ;; 414 | LDX #$00 ;; 415 | LoadDefaultPalLoop: ;; 416 | LDA defaultpal, x ;; 417 | STA $2007 ;; 418 | INX ;; 419 | CPX #$20 ;; 420 | BNE LoadDefaultPalLoop ;; 421 | RTS ;; 422 | LoadDarkPal: ; "Load Dark palette" subroutine ;; 423 | LDA $2002 ;; 424 | LDA #$3F ;; 425 | STA $2006 ;; 426 | LDA #$00 ;; 427 | STA $2006 ;; 428 | LDX #$00 ;; 429 | LoadDarkPalLoop: ;; 430 | LDA darkpal, x ;; 431 | STA $2007 ;; 432 | INX ;; 433 | CPX #$20 ;; 434 | BNE LoadDarkPalLoop ;; 435 | RTS ;; 436 | LoadBrightPal: ; "Load Bright palette" subroutine ;; 437 | LDA $2002 ;; 438 | LDA #$3F ;; 439 | STA $2006 ;; 440 | LDA #$00 ;; 441 | STA $2006 ;; 442 | LDX #$00 ;; 443 | LoadBrightPalLoop: ;; 444 | LDA brightpal, x ;; 445 | STA $2007 ;; 446 | INX ;; 447 | CPX #$20 ;; 448 | BNE LoadBrightPalLoop ;; 449 | RTS ;; 450 | LoadPastelPal: ; "Load Pastel palette" subroutine ;; 451 | LDA $2002 ;; 452 | LDA #$3F ;; 453 | STA $2006 ;; 454 | LDA #$00 ;; 455 | STA $2006 ;; 456 | LDX #$00 ;; 457 | LoadPastelPalLoop: ;; 458 | LDA pastelpal, x ;; 459 | STA $2007 ;; 460 | INX ;; 461 | CPX #$20 ;; 462 | BNE LoadPastelPalLoop ;; 463 | RTS ;; 464 | LoadBG: ; "Load background" subroutine ;; 465 | LDA $2002 ;; 466 | LDA #$3F ;; 467 | STA $2006 ;; 468 | LDA #$00 ;; 469 | STA $2006 ;; 470 | LDX #$00 ;; 471 | LoadPalLoop: ; Default palette is loaded on reset ;; 472 | LDA defaultpal, x ;; 473 | STA $2007 ;; 474 | INX ;; 475 | CPX #$20 ;; 476 | BNE LoadPalLoop ;; 477 | LDA $2002 ;; 478 | LDA #$20 ;; 479 | STA $2006 ;; 480 | LDA #$00 ;; 481 | STA $2006 ;; 482 | LDX #$00 ;; 483 | LoadTitleNewNam1: ; Load first set of 256 background tiles ;; 484 | LDA background1,x ;; 485 | STA $2007 ;; 486 | INX ;; 487 | BNE LoadTitleNewNam1 ;; 488 | LoadTitleNewNam2: ; Load second set of 256 background tiles ;; 489 | LDA background2,x ;; 490 | STA $2007 ;; 491 | INX ;; 492 | BNE LoadTitleNewNam2 ;; 493 | LoadTitleNewNam3: ; Load third set of 256 background tiles ;; 494 | LDA background3,x ;; 495 | STA $2007 ;; 496 | INX ;; 497 | BNE LoadTitleNewNam3 ;; 498 | LoadTitleNewNam4: ; Load fourth set of background tiles ;; 499 | LDA background4,x ;; 500 | STA $2007 ;; 501 | INX ;; 502 | CPX #$E0 ; (Don't have to load all 256) ;; 503 | BNE LoadTitleNewNam4 ;; 504 | LoadAttr: ; Load initial attribute values for BG ;; 505 | LDA #$23 ;; 506 | STA $2006 ;; 507 | LDA #$c0 ;; 508 | STA $2006 ;; 509 | LDX #$00 ;; 510 | LoadAttrLoop: ;; 511 | LDA attr, x ;; 512 | STA $2007 ;; 513 | INX ;; 514 | CPX #$40 ;; 515 | BNE LoadAttrLoop ;; 516 | RTS ;; 517 | LoadSpr: ; Load initial sprite values ;; 518 | LDX #$00 ;; 519 | LoadSprLoop: ;; 520 | LDA heart,x ;; 521 | STA $0300,x ;; 522 | INX ;; 523 | CPX #$20 ;; 524 | BNE LoadSprLoop ;; 525 | RTS ;; 526 | TurnScreenOn: ; Enable screen rendering ;; 527 | LDA #%10010000 ;; 528 | STA $2000 ;; 529 | LDA #%00011010 ;; 530 | STA $2001 ;; 531 | RTS ;; 532 | TurnScreenOff: ; Disable screen rendering ;; 533 | LDA #$00 ;; 534 | STA $2000 ;; 535 | STA $2001 ;; 536 | RTS ;; 537 | ReadController1: ; Read the P1 controller ;; 538 | LDA #$01 ;; 539 | STA $4016 ;; 540 | LDA #$00 ;; 541 | STA $4016 ;; 542 | LDX #$08 ;; 543 | ReadController1Loop: ;; 544 | LDA $4016 ;; 545 | LSR A ;; 546 | ROL buttons1 ;; 547 | DEX ;; 548 | BNE ReadController1Loop ;; 549 | LDA buttons1pending ; Note: This code is helpful in helping to ;; 550 | EOR #%11111111 ; distinguish between reading a continuous ;; 551 | AND buttons1 ; button press and a single button press ;; 552 | STA buttons1read ; Often, we want to read the first button ;; 553 | LDA buttons1 ; value sent and then ignore subsequent ;; 554 | STA buttons1pending ; reads until the button is released ;; 555 | RTS ;; 556 | ;; 557 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 558 | ;; 559 | ;;;;;;;;;;;; 6.3 Binary data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 560 | ;; 561 | background1: ; First 256-tile set of background ;; 562 | .incbin "background1.nam" ;; 563 | background2: ; Second 256-tile set of background ;; 564 | .incbin "background2.nam" ;; 565 | background3: ; Third 256-tile set of background ;; 566 | .incbin "background3.nam" ;; 567 | background4: ; Fourth 256-tile set of background ;; 568 | .incbin "background4.nam" ;; 569 | defaultpal: ; Default color palette ;; 570 | .db $38,$30,$26,$25 ; Background colors ;; 571 | .db $38,$30,$2B,$21 ;; 572 | .db $38,$30,$23,$21 ;; 573 | .db $38,$30,$30,$30 ;; 574 | .db $38,$23,$22,$21 ; Sprite colors ;; 575 | .db $38,$2C,$2B,$2A ;; 576 | .db $38,$29,$28,$27 ;; 577 | .db $38,$26,$25,$24 ;; 578 | darkpal: ; Dark color palette ;; 579 | .db $18,$30,$06,$05 ; Background colors ;; 580 | .db $18,$30,$0B,$01 ;; 581 | .db $18,$30,$03,$01 ;; 582 | .db $18,$30,$30,$30 ;; 583 | .db $18,$03,$02,$01 ; Sprite colors ;; 584 | .db $18,$0C,$0B,$0A ;; 585 | .db $18,$09,$08,$07 ;; 586 | .db $18,$06,$05,$04 ;; 587 | brightpal: ; Bright color palette ;; 588 | .db $28,$30,$16,$15 ; Background colors ;; 589 | .db $28,$30,$1B,$11 ;; 590 | .db $28,$30,$13,$11 ;; 591 | .db $28,$30,$30,$30 ;; 592 | .db $28,$13,$12,$11 ; Sprite colors ;; 593 | .db $28,$1C,$1B,$1A ;; 594 | .db $28,$19,$18,$17 ;; 595 | .db $28,$16,$15,$14 ;; 596 | pastelpal: ; Pastel color palette ;; 597 | .db $37,$30,$36,$35 ; Background colors ;; 598 | .db $37,$30,$3B,$31 ;; 599 | .db $37,$30,$33,$31 ;; 600 | .db $37,$30,$30,$30 ;; 601 | .db $37,$33,$32,$31 ; Sprite colors ;; 602 | .db $37,$3C,$3B,$3A ;; 603 | .db $37,$39,$38,$37 ;; 604 | .db $37,$36,$35,$34 ;; 605 | attr: ; Color attribute table ;; 606 | .db $00,$00,$00,$00,$00,$00,$00,$00 ;; 607 | .db $00,$00,$00,$00,$00,$00,$00,$00 ;; 608 | .db $50,$50,$50,$50,$50,$50,$50,$50 ;; 609 | .db $56,$56,$56,$56,$56,$56,$56,$56 ;; 610 | .db $55,$55,$55,$55,$55,$55,$55,$55 ;; 611 | .db $A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5 ;; 612 | .db $AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA ;; 613 | .db $0A,$0A,$0A,$0A,$0A,$0A,$AA,$AA ;; 614 | heart: ; Heart and sparkle sprite tile data ;; 615 | .db $58,$00,$00,$78 ; Heart tiles ;; 616 | .db $58,$01,$00,$80 ;; 617 | .db $60,$10,$00,$78 ;; 618 | .db $60,$11,$00,$80 ;; 619 | .db $5C,$04,$00,$7C ; Sparkle tiles ;; 620 | .db $5C,$05,$00,$7C ;; 621 | .db $5C,$14,$00,$7C ;; 622 | .db $5C,$15,$00,$7C ;; 623 | ;; 624 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 625 | 626 | 627 | ;;;;;;;; + 7.0 GAME CODE: BANK 2 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 628 | ;; 629 | .bank 3 ; Bank 3 ;; 630 | .org $E000 ; Begins at memory address $E000 ;; 631 | .org $FFFA ; Final three bytes (vectors): ;; 632 | .dw NMI ; When an NMI happens, jump to NMI ;; 633 | .dw Reset ; On reset/power on, jump to Reset ;; 634 | .dw 0 ; IRQ disabled ;; 635 | ;; 636 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 637 | 638 | 639 | ;;;;;;;; + 8.0 GRAPHICS DATA: BANK 4 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 640 | ;; 641 | .bank 4 ; Bank 4 ;; 642 | .org $0000 ; Starts at $0000 (CHR) ;; 643 | .incbin "gfx.chr" ; Include graphics binary ;; 644 | ;; 645 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 646 | -------------------------------------------------------------------------------- /source/music.nsf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hxlnt/computers-are-easy/b2d77f2733392a25f07bc2362115e360c387a357/source/music.nsf --------------------------------------------------------------------------------