Commit: 78a8ebfe254f7ca07df95ad70da4bb41af1d1323 Author: Vi Grey Date: 2019-08-11 04:10 UTC Summary: Initial Commit .gitignore | 2 + CHANGELOG.md | 6 + DOCUMENTATION.txt | 120 ++++++++++ Makefile | 49 ++++ README.md | 64 ++++++ src/defs.asm | 29 +++ src/discord-nes.asm | 972 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/graphics/tileset.chr | Bin 0 -> 8192 bytes src/ram.asm | 33 +++ src/tables.asm | 17 ++ 10 files changed, 1292 insertions(+) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c745919 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin +build diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b84b981 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +# Change Log +All notable changes to this project will be documented in this file. + +## 0.0.1 - 2019-08-10 +### Added +- Initial release diff --git a/DOCUMENTATION.txt b/DOCUMENTATION.txt new file mode 100644 index 0000000..516e808 --- /dev/null +++ b/DOCUMENTATION.txt @@ -0,0 +1,120 @@ +Discord NES Content Input Expectations +By ViGreyTech (2019-07-10) + +Controller 1 will be polled 16 times per frame for input. +The new input data will print on the screen every 2nd frame. +That means 32 bytes will potentially be printed every 2nd frame. +You do not need to worry about if you are sending data on an even or +odd frame. If you do not have data to send at that moment, then send +a 0x00 byte. The data you send MUST be 8-bit Latin-1 encoded. + +7 bit 0 +---- ---- +|||| |||| +|||| |||+- Right +|||| ||+-- Left +|||| |+--- Down +|||| +---- Up +|||+------ Start +||+------- Select +|+-------- B ++--------- A + +Example ASCII byte: + Uppercase Letter A: 7 bit 0 + 0100 0001 + ---- ---- + | | + | +- Right + +-------- B + +Example Latin-1 byte: + Copyright Symbol: 7 bit 0 + 1010 1001 + ---- ---- + | | | | + | | | +- Right + | | +---- Up + | +------- Select + +--------- A + +The bytes this game will accept from Controller 1 are: + - Newline Character (0x0A) + - ASCII Printable Characters (0x20 - 0x7E) + - Latin-1 Characters (0xA0-0xFF) + with the exception of NBSP (0xA0) and Soft Hyphen (0xAD) + - Paperclip (0x80 for this application) + - User Silhouette (0x81 for this application) + and only on the start of a new line + + +Verbose list of accepted bytes from Controller 1: + - ASCII Control Characters + ------+------------------------------------------------- + 0x0X | 0x00 + 0x0X | 0x0A + ------+------------------------------------------------- + - ASCII Printable Characters + ------+------------------------------------------------- + 0x2X | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 + 0x2X | 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F + ------+------------------------------------------------- + 0x3X | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 + 0x3X | 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F + ------+------------------------------------------------- + 0x4X | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 + 0x4X | 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F + ------+------------------------------------------------- + 0x5X | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 + 0x5X | 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F + ------+------------------------------------------------- + 0x6X | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67 + 0x6X | 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F + ------+------------------------------------------------- + 0x7X | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 + 0x7X | 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E + ------+------------------------------------------------- + - Special Characters (Paperclip and User Silhouette) + ------+------------------------------------------------- + 0x8X | 0x80 + 0x8X | 0x81 (Only allowed if at start of new line) + ------+------------------------------------------------- + - Latin-1 Characters + ------+------------------------------------------------- + 0xAX | 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7 + 0xAX | 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAE, 0xAF + ------+------------------------------------------------- + 0xBX | 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7 + 0xBX | 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF + ------+------------------------------------------------- + 0xCX | 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7 + 0xCX | 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + ------+------------------------------------------------- + 0xDX | 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7 + 0xDX | 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF + ------+------------------------------------------------- + 0xEX | 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7 + 0xEX | 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF + ------+------------------------------------------------- + 0xFX | 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7 + 0xFX | 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + ------+------------------------------------------------- + +Anything other than the characters in the accepted characters list will +be converted to a 0x00 byte, including 0x81 if it is not at the start of +a new line. + +!!!!!!!!!!!!!!!!!!! +! ! +! ############# ! +! # IMPORTANT # ! +! ############# ! +! ! +!!!!!!!!!!!!!!!!!!! + +At the end of someone's message, send a Newline character (0x0A). If +you send a newline character, the remaining characters of the 32 +character print buffer WILL be discarded by the payload. To prevent +issues with this functionality, send 31 0x00 bytes after sending a +newline character. This way, you do not need to keep track of frames +or where in the frame button inputs are happening. diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..1ec30ea --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +# Copyright (C) 2018, Vi Grey +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +PKG_NAME := discord-nes +CURRENTDIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +all: + mkdir -p $(CURRENTDIR)bin; \ + rm -rf -- $(CURRENTDIR)build/*; \ + mkdir -p $(CURRENTDIR)build/$(PKG_NAME); \ + cp -r $(CURRENTDIR)src $(CURRENTDIR)build/$(PKG_NAME); \ + cp $(CURRENTDIR)* $(CURRENTDIR)build/$(PKG_NAME); \ + cd $(CURRENTDIR)build; \ + zip -r $(PKG_NAME).zip $(PKG_NAME); \ + cd $(CURRENTDIR)src; \ + asm $(PKG_NAME).asm ../build/$(PKG_NAME).nes; \ + cd $(CURRENTDIR)build; \ + ZIPSIZE=$$(stat -L -c %s $(PKG_NAME).zip); \ + head -c $$((32778 - $$ZIPSIZE)) $(PKG_NAME).nes > new.nes; \ + cat $(PKG_NAME).zip >> new.nes; \ + zip -F new.nes --out new.zip; \ + head -c 40976 $(PKG_NAME).nes | tail -c 8198 >> new.zip; \ + mv new.zip ../bin/$(PKG_NAME).nes; \ + +clean: + rm -rf -- $(CURRENTDIR)bin; \ + rm -rf -- $(CURRENTDIR)build; \ diff --git a/README.md b/README.md new file mode 100644 index 0000000..9c6cd13 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# Discord for NES (Requires TAS Replay Device) + +NES game that is also a Discord chat client + +**_Discord for NES was created by Vi Grey Vi Grey (https://vigrey.com) and is licensed under the BSD 2-Clause License._** + +### Description: +This is an NROM NES ROM that is also a Discord chat client that connects to Discord using a TAS replay device like TASBot. + +### Platforms: +- GNU/Linux + +### Build Dependencies: +- asm6 _(You'll probably have to build asm6 from source. Make sure the asm6 binary is named **asm** and that the binary is executable and accessible in your PATH. The source code can be found at **http://3dscapture.com/NES/asm6.zip**)_ +- zip + +### Build NES ROM: +From a terminal, go to the the main directory of this project (the directory this README.md file exists in), you can then build the NES ROM with the following command. + + $ make + +The resulting NES ROM will be located at **bin/discord-nes.nes** + +### Cleaning Build Environment: +If you used `make` to build the payload binary, you can run the following command to clean up the build environment. + + $ make clean + +### Controller Input Documentation +Included in this repository is a file called DOCUMENTATION.txt, which will explain what is expected from a controller input replay device system like TASBot for printing messages on the screen. + +### NES-ZIP Polyglot File +After building the NES ROM, you may notice that it is also a functioning ZIP file. Unzipping the NES ROM will extract the source code for the NES ROM. This allows the NES ROM to be a Quine of sorts, where everything required to create the NES ROM from scratch is self contained in the NES ROM. You can unzip the NES ROM with the following command. + + $ unzip discord-nes.nes + +Unzipping the NES ROM will result in a directory called **discord-nes**, which will include all of the source code for the NES ROM. + +### License: + Copyright (C) 2019, Vi Grey + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS \`\`AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + diff --git a/src/defs.asm b/src/defs.asm new file mode 100644 index 0000000..6e14de5 --- /dev/null +++ b/src/defs.asm @@ -0,0 +1,29 @@ +BUTTON_A = 1 << 7 +BUTTON_B = 1 << 6 +BUTTON_SELECT = 1 << 5 +BUTTON_START = 1 << 4 +BUTTON_UP = 1 << 3 +BUTTON_DOWN = 1 << 2 +BUTTON_LEFT = 1 << 1 +BUTTON_RIGHT = 1 << 0 + +PPU_CTRL = $2000 +PPU_MASK = $2001 +PPU_STATUS = $2002 +PPU_OAM_ADDR = $2003 +PPU_OAM_DATA = $2004 +PPU_SCROLL = $2005 +PPU_ADDR = $2006 +PPU_DATA = $2007 + +OAM_DMA = $4014 +CONTROLLER1 = $4016 +CONTROLLER2 = $4017 + +CALLBACK = $FFFA + +SCREEN_TITLE = 0 +SCREEN_CHAT = 1 + +SECONDS = 5 +FPS = 60 diff --git a/src/discord-nes.asm b/src/discord-nes.asm new file mode 100644 index 0000000..5b1b09b --- /dev/null +++ b/src/discord-nes.asm @@ -0,0 +1,972 @@ +; Copyright (C) 2019, Vi Grey +; All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; 1. Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; 2. Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +; SUCH DAMAGE. + +; Version 0.0.1 + + .db "NES", $1A + .db $02 + .db $01 + .db $01 + .db $00 + .db 0, 0, 0, 0, 0, 0, 0, 0 + +.include "ram.asm" +.include "defs.asm" + +.base $8000 + +RESET: + sei + cld + ldx #$40 + stx $4017 + ldx #$FF + txs + inx + lda #%00000110 + sta PPU_MASK + lda #$00 + sta PPU_CTRL + stx $4010 + ldy #$00 + +InitialVWait: + ldx #$02 +InitialVWaitLoop: + lda PPU_STATUS + bpl InitialVWaitLoop + dex + bne InitialVWaitLoop + +InitializeRAM: + ldx #$00 +InitializeRAMLoop: + lda #$00 + sta Variables, x + sta DrawBuffer, x + lda #$FE + sta $0200, x + inx + bne InitializeRAMLoop + jsr ClearPPURAM + jsr ClearScreen + jsr SetPalette + jsr DrawTitleScreen + jsr ResetScroll + +Forever: + jmp Forever + +NMI: + lda #$00 + sta PPU_OAM_ADDR + lda #$02 + sta OAM_DMA + lda PPU_STATUS + jsr DrawLastFrame + jsr Draw + jsr ResetScroll + jsr Update +NMICheckSprite0: + lda screen + cmp #SCREEN_CHAT + bne NMIDone +Sprite0ClearWait: + bit $2002 + bvs Sprite0ClearWait +Sprite0HitWait: + bit $2002 + bvc Sprite0HitWait: + lda #%00000100 + sta PPU_ADDR + lda #$06 + sta PPU_SCROLL + ldx #$0A + HBlankWait: + dex + bne HBlankWait + lda #$00 + sta PPU_SCROLL + lda #$00 + sta PPU_ADDR +NMIDone: + ldy drawbufferoffset + lda #$10 + sta (drawbuffer), y + rti + +DrawLastFrame: + ldx #$00 + stx drawbufferoffset + ldy #$02 + lda drawbuffer, x + cmp #$10 + beq DrawLastFrameDone + cmp #$00 + bne DrawLastFrameDone + lda #$10 + sta drawbuffer, x +DrawLastFrameSetAddrLoop: + inx + lda drawbuffer, x + sta PPU_ADDR + dey + bne DrawLastFrameSetAddrLoop +DrawLastFrameLoop: + ldy #$02 + inx + lda drawbuffer, x + bne DrawLastFrameNotNewAddress + lda #$10 + sta drawbuffer, x + jmp DrawLastFrameSetAddrLoop +DrawLastFrameNotNewAddress: + cmp #$10 + bne DrawLastFrameLoopContinue + jsr ResetScroll + jmp DrawLastFrameDone +DrawLastFrameLoopContinue: + sta PPU_DATA + jmp DrawLastFrameLoop +DrawLastFrameDone: + rts + +Update: + lda screen + cmp #SCREEN_TITLE + bne UpdateNotTitleScreen +UpdateTitleScreenFrames: + dec frames + bne UpdateDone + lda #FPS + sta frames + dec seconds + bne UpdateDone + jsr Blank + jsr ClearScreen + jsr SetPalette + jsr DrawChatScreen + jsr ResetScroll + jmp UpdateDone +UpdateNotTitleScreen: + jsr UpdateCursor + lda frames + and #$01 + asl + asl + asl + asl + tax + lda #$10 + sta tmp + cpx #$10 + bne Controller1PollLoop + jsr LatchControllers + jsr PollControllers + inx + dec tmp +Controller1PollLoop: + jsr LatchControllers + jsr PollController1 + inx + dec tmp + bne Controller1PollLoop + inc frames + lda frames + and #$01 + bne HandleController2Buttons + jsr CharacterInputDraw + lda newlines + cmp #$02 + bne UpdateDone + jsr OddFrameClearLine + jmp UpdateDone + HandleController2Buttons: + ;jsr CheckA + ;jsr CheckB + ;jsr CheckStart + ;jsr CheckUp + ;jsr CheckDown + jsr EvenFrameClearLine +UpdateDone: + rts + +EvenFrameClearLine: + lda textaddr + sta tmp + lda (textaddr + 1) + sta (tmp + 1) + lda (textaddr + 1) + and #%11100000 + clc + adc #$A0 + sta (textaddr + 1) + lda textaddr + adc #$00 + sta textaddr + jsr UpdateTextAddr + ldy drawbufferoffset + lda #$00 + sta (drawbuffer), y + iny + lda textaddr + sta (drawbuffer), y + iny + lda (textaddr + 1) + sta (drawbuffer), y + iny + lda #$20 + tax +EvenFrameClearLineLoop: + sta (drawbuffer), y + iny + dex + bne EvenFrameClearLineLoop + sty drawbufferoffset + lda tmp + sta textaddr + lda (tmp + 1) + sta (textaddr + 1) + rts + +OddFrameClearLine: + lda textaddr + sta tmp + lda (textaddr + 1) + sta (tmp + 1) + lda (textaddr + 1) + and #%11100000 + clc + adc #$80 + sta (textaddr + 1) + lda textaddr + adc #$00 + sta textaddr + jsr UpdateTextAddr + ldy drawbufferoffset + lda #$00 + sta (drawbuffer), y + iny + lda textaddr + sta (drawbuffer), y + iny + lda (textaddr + 1) + sta (drawbuffer), y + iny + lda #$20 + tax +OddFrameClearLineLoop: + sta (drawbuffer), y + iny + dex + bne OddFrameClearLineLoop + sty drawbufferoffset + lda tmp + sta textaddr + lda (tmp + 1) + sta (textaddr + 1) + rts + +UpdateTextAddr: + lda textaddr + cmp #$23 + bcc UpdateTextAddrDone + bne UpdateTextAddrReset + lda (textaddr + 1) + cmp #$C0 + bcc UpdateTextAddrDone +UpdateTextAddrReset: + lda (textaddr + 1) + sec + sbc #$C0 + sta (textaddr + 1) + lda textaddr + sbc #$03 + sta textaddr +UpdateTextAddrDone: + rts + +LatchControllers: + ldy #$01 + sty CONTROLLER1 + dey + sty CONTROLLER1 + rts + +PollControllers: + lda controller2 + sta controller2lastframe + ldy #$08 +PollControllersLoop: + lda CONTROLLER1 + lsr A + rol characters, x + lda CONTROLLER2 + lsr A + rol controller2 + dey + bne PollControllersLoop + rts + +PollController1: + ldy #$08 +PollController1Loop: + lda CONTROLLER1 + lsr A + rol characters, x + dey + bne PollController1Loop + rts + +CheckUp: + lda controller2 + cmp #BUTTON_UP + bne CheckUpDone + and controller2lastframe + bne CheckUpDone + ldx chatinputoffset + inc chatinputbuffer, x + lda chatinputbuffer, x + cmp #189 + bne CheckUpDraw + lda #$00 + sta chatinputbuffer, x +CheckUpDraw: + jsr DrawChatInput +CheckUpDone: + rts + +CheckDown: + lda controller2 + cmp #BUTTON_DOWN + bne CheckDownDone + and controller2lastframe + bne CheckDownDone + ldx chatinputoffset + dec chatinputbuffer, x + lda chatinputbuffer, x + cmp #$FF + bne CheckDownDraw + lda #188 + sta chatinputbuffer, x +CheckDownDraw: + jsr DrawChatInput +CheckDownDone: + rts + +CheckA: + lda controller2 + cmp #BUTTON_A + bne CheckADone + and controller2lastframe + bne CheckADone + inc chatinputoffset + lda chatinputoffset + cmp #$80 + bne CheckADraw + dec chatinputoffset +CheckADraw: + jsr DrawChatInput +CheckADone: + rts + +CheckB: + lda controller2 + cmp #BUTTON_B + bne CheckBDone + and controller2lastframe + bne CheckBDone + ldx chatinputoffset + beq CheckBDone + lda #$00 + sta chatinputbuffer, x + dec chatinputoffset +CheckBDraw: + jsr DrawChatInput +CheckBDone: + rts + +CheckStart: + lda controller2 + cmp #BUTTON_START + bne CheckStartDone + and controller2lastframe + bne CheckStartDone + jsr ClearChatInput +CheckStartDone: + rts + +ClearChatInput: + lda #$00 + ldx #$7F +ClearChatInputLoop: + sta chatinputbuffer, x + dex + bpl ClearChatInputLoop + sta chatinputoffset + jsr DrawChatInput + rts + +DrawChatInput: + ldy drawbufferoffset + lda #$00 + sta (drawbuffer), y + iny + lda #$24 + sta (drawbuffer), y + iny + lda #$42 + sta (drawbuffer), y + iny + lda chatinputoffset + sec + sbc #27 + bpl DrawChatInputSbcChatInputOffsetContinue + lda #$00 +DrawChatInputSbcChatInputOffsetContinue: + sta (tmp + 1) + lda #28 + sta tmp +DrawChatInputLineLoop: + ldx (tmp + 1) + lda chatinputbuffer, x + tax + lda Controller1CharacterOrder, x + sta (drawbuffer), y + iny + inc (tmp + 1) + dec tmp + bne DrawChatInputLineLoop + sty drawbufferoffset + lda chatinputoffset + cmp #28 + bcc DrawChatInputCursor + lda #27 +DrawChatInputCursor: + clc + adc #$02 + asl + asl + asl + sta $207 +DrawChatInputDone: + rts + + +ResetScroll: + lda #$00 + sta PPU_SCROLL + lda yscroll + sta PPU_SCROLL + jsr EnableNMI + rts + +Draw: + lda #%11111110 + sta PPU_MASK + rts + +DisableNMI: + lda #$00 + sta PPU_CTRL + rts + +EnableNMI: + lda #%10000000 + clc + adc nametable + adc patterntable + sta PPU_CTRL + rts + +Blank: + lda #%11100110 + sta PPU_MASK + jsr DisableNMI + rts + +ClearPPURAM: + lda #$20 + sta PPU_ADDR + lda #$00 + sta PPU_ADDR + ldy #$10 + ldx #$00 + txa +ClearPPURAMLoop: + sta PPU_DATA + dex + bne ClearPPURAMLoop + ldx #$00 + dey + bne ClearPPURAMLoop + rts + +ClearScreen: + ldx #$00 + lda #$20 + sta addr + jmp ClearScreenStartNametableLoop +ClearScreenLoop: + lda addr + clc + adc #$04 + sta addr +ClearScreenStartNametableLoop: + sta PPU_ADDR + lda #$00 + sta PPU_ADDR + ldx #$1E + ldy #$20 + lda #$01 +ClearScreenNametableLoop: + sta PPU_DATA + dex + bne ClearScreenNametableLoop + ldx #$1E + dey + bne ClearScreenNametableLoop + lda addr + cmp #$2C + bne ClearScreenLoop + rts + +SetPalette: + lda #$3F + sta PPU_ADDR + lda #$00 + sta PPU_ADDR + ldx #$08 +SetPaletteLoop: + lda #$2D + sta PPU_DATA + sta PPU_DATA + lda #$22 + sta PPU_DATA + lda #$30 + sta PPU_DATA + dex + bne SetPaletteLoop + rts + +DrawTitleScreen: +DrawLogo: + lda #$21 + sta PPU_ADDR + lda #$2D + sta PPU_ADDR + ldx #$81 + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + lda #$21 + sta PPU_ADDR + lda #$4D + sta PPU_ADDR + ldx #$91 + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + lda #$21 + sta PPU_ADDR + lda #$6D + sta PPU_ADDR + ldx #$A1 + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + lda #$21 + sta PPU_ADDR + lda #$8D + sta PPU_ADDR + ldx #$B1 + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + lda #$21 + sta PPU_ADDR + lda #$AD + sta PPU_ADDR + ldx #$C1 + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA +DrawDiscordText: + lda #$21 + sta PPU_ADDR + lda #$EC + sta PPU_ADDR + ldx #$D0 + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + lda #$22 + sta PPU_ADDR + lda #$0C + sta PPU_ADDR + ldx #$E0 + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA + inx + stx PPU_DATA +DrawConnecting: + lda #$22 + sta PPU_ADDR + lda #$CD + sta PPU_ADDR + ldx #$EA +DrawConnectingLoop: + stx PPU_DATA + inx + cpx #$F0 + bne DrawConnectingLoop +DrawCredits: + lda #$23 + sta PPU_ADDR + lda #$42 + sta PPU_ADDR + ldx #$F0 +DrawCreditsLoop: + stx PPU_DATA + inx + bne DrawCreditsLoop +DrawLoadingText: + lda #$22 + sta PPU_ADDR + lda #$84 + sta PPU_ADDR + lda #<(LoadingText) + sta addr + lda #>(LoadingText) + sta (addr + 1) + ldy #$00 +DrawLoadingTextLoop: + lda (addr), y + sta PPU_DATA + iny + cpy #24 + bne DrawLoadingTextLoop +DrawVersion: + lda #$20 + sta PPU_ADDR + lda #$79 + sta PPU_ADDR + ldx #$DB +DrawVersionLoop: + stx PPU_DATA + inx + cpx #$E0 + bne DrawVersionLoop +SetTitleScreenTimer: + lda #SECONDS + sta seconds + lda #FPS + sta frames +SetTitleScreenScreenValue: + lda #SCREEN_TITLE + sta screen +SetTitleScreenNametable: + lda #$00 + sta nametable +SetTitleScreenPatterntable: + lda #%00000000 + sta patterntable + rts + +DrawChatScreen: +DrawChatBar: + lda #$24 + sta PPU_ADDR + lda #$00 + sta PPU_ADDR + lda #$0F + ldx #$20 +DrawChatBarLoop: + sta $ + sta PPU_DATA + dex + bne DrawChatBarLoop +SetChatScreenScreenVariable: + lda #SCREEN_CHAT + sta screen +SetChatScreenNametable: + lda #$00 + sta nametable +SetChatScreenCursor: + lda #225 + sta $204 + lda #$0E + sta $205 + lda #$00 + sta $206 + lda #16 + sta $207 + lda #$00 + sta cursorframes +SetChatScreenPatterntable: + lda #%00011000 + sta patterntable +DrawChatScreenSprite0: + lda #198 + sta $200 + lda #$0D + sta $201 + lda #$00 + sta $202 + lda #$40 + sta $203 +ResetChatInputBuffer: + ldx #$00 + stx chatinputoffset + lda #$00 +ResetChatInputBufferLoop: + sta chatinputbuffer, x + inx + cpx #$80 + bne ResetChatInputBufferLoop +ResetChatTextAddr: + lda #$20 + sta textaddr + lda #$41 + sta (textaddr + 1) + rts + +UpdateCursor: + inc cursorframes + lda #FPS + lsr + cmp cursorframes + bne UpdateCursorDone + lda #$00 + sta cursorframes + lda $205 + bne UpdateCursorNotBlank + lda #$0E + sta $205 + jmp UpdateCursorDone + UpdateCursorNotBlank: + lda #$00 + sta $205 +UpdateCursorDone: + rts + +CharacterInputDraw: + ldy drawbufferoffset + lda #$00 + sta newlines + sta (drawbuffer), y + iny + lda textaddr + sta (drawbuffer), y + iny + lda (textaddr + 1) + sta (drawbuffer), y + iny + ldx #$00 +CharacterInputLoop: + lda characters, x + sta tmp + jsr CheckAllowedCharacter + sta tmp + lda tmp + bne CharacterInputLoopAllowedCharacter + inx + cpx #$20 + bne CharacterInputLoop + jmp CharacterInputDrawDone +CharacterInputLoopAllowedCharacter: + lda (textaddr + 1) + and #%00011111 + cmp #$01 + bne CharacterInputLoopNotStartOfLine + lda tmp + cmp #$81 + beq CharacterInputLoopNotStartOfLine + lda #$20 + sta (drawbuffer), y + iny + inc (textaddr + 1) +CharacterInputLoopNotStartOfLine: + lda tmp + cmp #$0A + bne CharacterInputNotNewLineCharacter + inc $B0 + ldx #$20 + jmp CharacterInputNewLine +CharacterInputNotNewLineCharacter: + sta (drawbuffer), y + iny + inx + lda (textaddr + 1) + clc + adc #$01 + sta (textaddr + 1) + lda textaddr + adc #$00 + sta textaddr + jsr UpdateTextAddr + lda (textaddr + 1) + and #%00011111 + cmp #$1E + bne CharacterInputNotNewLine +CharacterInputNewLine: + inc newlines + lda (textaddr + 1) + and #%11100000 + clc + adc #$21 + sta (textaddr + 1) + lda textaddr + adc #$00 + sta textaddr + jsr UpdateTextAddr + lda #$00 + sta (drawbuffer), y + iny + lda textaddr + sta (drawbuffer), y + iny + lda (textaddr + 1) + sta (drawbuffer), y + iny + inc textrow + lda textrow + cmp #23 + bcc CharacterInputNotNewLine + lda #22 + sta textrow + lda yscroll + clc + adc #$08 + sta yscroll + cmp #240 + bne CharacterInputNotNewLine + lda #$00 + sta yscroll +CharacterInputNotNewLine: + cpx #$20 + beq CharacterInputDrawDone + jmp CharacterInputLoop +CharacterInputDrawDone: + sty drawbufferoffset + rts + +CheckAllowedCharacter: + lda tmp + cmp #$0A + beq CheckAllowedCharacterDone + cmp #$20 + bcc CheckAllowedCharacterNotAllowed + cmp #$AD + beq CheckAllowedCharacterNotAllowed + cmp #$7F + bcc CheckAllowedCharacterDone + cmp #$A1 + bcs CheckAllowedCharacterDone + lda (textaddr + 1) + and #%00011111 + cmp #$01 + bne CheckAllowedCharacterNotAllowed + lda tmp + cmp #$81 + beq CheckAllowedCharacterDone +CheckAllowedCharacterNotAllowed: + lda #$00 +CheckAllowedCharacterDone: + rts + +.include "tables.asm" + + .pad CALLBACK, #$FF + + .dw NMI + .dw RESET + .dw 0 + +.base $0000 + .incbin "graphics/tileset.chr" diff --git a/src/graphics/tileset.chr b/src/graphics/tileset.chr new file mode 100644 index 0000000..b329d23 Binary files /dev/null and b/src/graphics/tileset.chr differ diff --git a/src/ram.asm b/src/ram.asm new file mode 100644 index 0000000..f7a8ba5 --- /dev/null +++ b/src/ram.asm @@ -0,0 +1,33 @@ +.enum $0000 +Variables: + textaddr dsb 2 + characters dsb 32 + newlines dsb 1 + yscroll dsb 1 + textrow dsb 1 + addr dsb 2 + cursorframes dsb 1 + nametable dsb 1 + patterntable dsb 1 + nmi dsb 1 + mergedvalue dsb 1 + addrtmp dsb 2 + tmp dsb 2 + nametableaddrtmp dsb 2 + controller2 dsb 1 + controller2lastframe dsb 1 + screen dsb 1 + seconds dsb 1 + frames dsb 1 +.ende + +.enum $300 +DrawBuffer: + drawbufferoffset dsb 1 + drawbuffer dsb 255 +.ende + +.enum $700 + chatinputoffset dsb 1 + chatinputbuffer dsb 128 +.ende diff --git a/src/tables.asm b/src/tables.asm new file mode 100644 index 0000000..9e42cdf --- /dev/null +++ b/src/tables.asm @@ -0,0 +1,17 @@ +LoadingText: + .byte "EXPERIENCING TRANQUILITY" + +Controller1CharacterOrder: + .byte " .,@AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" + .byte "0123456789" + .byte "!\"#$%&'()*+-/:;<=>?[\\]^_`{|}~" + .byte $C0, $E0, $C1, $E1, $C2, $E2, $C3, $E3, $C4, $E4, $C5, $E5 + .byte $C6, $E6, $C7, $E7, $C8, $E8, $C9, $E9, $CA, $EA, $CB, $EB + .byte $CC, $EC, $CD, $ED, $CE, $EE, $CF, $EF, $D0, $F0, $D1, $F1 + .byte $D2, $F2, $D3, $F3, $D4, $F4, $D5, $F5, $D6, $F6 + .byte $D8, $F8, $D9, $F9, $DA, $FA, $DB, $FB, $DC, $FC, $DD, $FD + .byte $DE, $FE, $DF, $FF, $D7, $F7 + .byte $A1, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $BA, $AB, $BB + .byte $AC, $AE, $AF + .byte $B0, $B1, $B9, $B2, $B3, $B4, $B5, $B6, $B7, $B8 + .byte $BC, $BD, $BE, $BF