diff --git a/.gitignore b/.gitignore index 82cc879..419b327 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ -/bin/ /obj/ /dep/ /res/ /tools/** /src/res/sources/*.z80 /src/res/sources/*.inc -DMGTRIS.sav +/bin/*.map +/bin/*.sym +/bin/*.sav diff --git a/.vscode/launch.json b/.vscode/launch.json index 38a3f7a..f009285 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,6 @@ "request": "launch", "name": "Launch in Emulicious", "program": "${workspaceFolder}\\bin\\DMGTRIS.gbc", - "emuliciousPath": "K:\\TGM\\dmgtris\\tools", "port": 58870, "stopOnEntry": false, "preLaunchTask": "buildrom" diff --git a/DMGTRIS.GBC b/DMGTRIS.GBC deleted file mode 100644 index acee397..0000000 Binary files a/DMGTRIS.GBC and /dev/null differ diff --git a/Makefile b/Makefile index 5f17674..22155ef 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ INCDIRS = src/ src/include/ WARNINGS = all extra ASFLAGS = -p 0xFF $(addprefix -i,$(INCDIRS)) $(addprefix -W,$(WARNINGS)) LDFLAGS = -p 0xFF -FIXFLAGS = -p 0xFF -l 0x33 -r 0x02 -v -i $(GAMEID) -k $(LICENSEE) -t $(TITLE) -n $(VERSION) -m $(MAPPER) +FIXFLAGS = -p 0xFF -l 0x33 -r 0x04 -v -i $(GAMEID) -k $(LICENSEE) -t $(TITLE) -n $(VERSION) -m $(MAPPER) # The list of "root" ASM files that RGBASM will be invoked on SRCS = $(wildcard src/*.asm) @@ -52,11 +52,7 @@ SRCS = $(wildcard src/*.asm) # Use this to override the above include project.mk -################################################ -# # -# TARGETS # -# # -################################################ + # `all` (Default target): build the ROM all: $(ROM) @@ -77,52 +73,12 @@ rebuild: $(MAKE) all .PHONY: rebuild -################################################ -# # -# RESOURCE FILES # -# # -################################################ -# By default, asset recipes convert files in `res/` into other files in `res/` -# This line causes assets not found in `res/` to be also looked for in `src/res/` -# "Source" assets can thus be safely stored there without `make clean` removing them -VPATH := src - -res/%.1bpp: res/%.png - @$(MKDIR_P) $(@D) - $(RGBGFX) -d 1 -o $@ $< - -# Define how to compress files using the PackBits16 codec -# Compressor script requires Python 3 -res/%.pb16: res/% src/tools/pb16.py - @$(MKDIR_P) $(@D) - $(PY) src/tools/pb16.py $< res/$*.pb16 - -res/%.pb16.size: res/% - @$(MKDIR_P) $(@D) - $(call filesize,$<,16) > res/$*.pb16.size - -# Define how to compress files using the PackBits8 codec -# Compressor script requires Python 3 -res/%.pb8: res/% src/tools/pb8.py - @$(MKDIR_P) $(@D) - $(PY) src/tools/pb8.py $< res/$*.pb8 - -res/%.pb8.size: res/% - @$(MKDIR_P) $(@D) - $(call filesize,$<,8) > res/$*.pb8.size - -############################################### -# # -# COMPILATION # -# # -############################################### # How to build a ROM $(BINDIR)/%.$(ROMEXT) $(BINDIR)/%.sym $(BINDIR)/%.map: $(patsubst src/%.asm,$(OBJDIR)/%.o,$(SRCS)) @$(MKDIR_P) $(@D) - $(RGBASM) $(ASFLAGS) -o $(OBJDIR)/build_date.o src/res/build_date.asm - $(RGBLINK) $(LDFLAGS) -m $(BINDIR)/$*.map -n $(BINDIR)/$*.sym -o $(BINDIR)/$*.$(ROMEXT) $^ $(OBJDIR)/build_date.o \ + $(RGBLINK) $(LDFLAGS) -m $(BINDIR)/$*.map -n $(BINDIR)/$*.sym -o $(BINDIR)/$*.$(ROMEXT) $^ \ && $(RGBFIX) -v $(FIXFLAGS) $(BINDIR)/$*.$(ROMEXT) # `.mk` files are auto-generated dependency lists of the "root" ASM files, to save a lot of hassle. diff --git a/README.md b/README.md index 5cbd270..3a480ab 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ ScoreIncrement points are then awarded. ## Playing -You can build the game yourself, or use the binary [here](https://git.villadelfia.org/villadelfia/dmgtris/raw/branch/master/DMGTRIS.GBC) or [here](https://github.com/Villadelfia/DMGTRIS/raw/master/DMGTRIS.GBC). +You can build the game yourself, or use the binary [here](https://git.villadelfia.org/villadelfia/dmgtris/raw/branch/master/bin/DMGTRIS.GBC) or [here](https://github.com/Villadelfia/DMGTRIS/raw/master/bin/DMGTRIS.GBC). The game should run in any accurate emulator. For Windows or Linux using Wine [bgb](https://bgb.bircd.org/) is generally regarded as the best option. For macOS [SameBoy](https://sameboy.github.io/) comes recommended. diff --git a/bin/DMGTRIS.GBC b/bin/DMGTRIS.GBC new file mode 100644 index 0000000..309339f Binary files /dev/null and b/bin/DMGTRIS.GBC differ diff --git a/project.mk b/project.mk index a106ecc..ddf59e6 100644 --- a/project.mk +++ b/project.mk @@ -15,16 +15,12 @@ ROMNAME := DMGTRIS ROMEXT := GBC # Mapper -MAPPER := 0x03 +MAPPER := 0x1B # Extra assembler flags # Do not insert nop after halt ASFLAGS += -h -# Extra linker flags -# Tiny Rom -LDFLAGS += -t - # Extra fix flags # Set as gbc compatible FIXFLAGS += -c diff --git a/src/bankid.asm b/src/bankid.asm new file mode 100644 index 0000000..71ba494 --- /dev/null +++ b/src/bankid.asm @@ -0,0 +1,32 @@ +; DMGTRIS +; Copyright (C) 2023 - Randy Thiemann + +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. + +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. + +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . + + +IF !DEF(BANKID_ASM) +DEF BANKID_ASM EQU 1 + + +SECTION "Bank ID 0", ROM0[$0] + db $00 + +SECTION "Bank ID 1", ROMX[$4000], BANK[1] + db $01 + +SECTION "Bank ID 2", ROMX[$4000], BANK[2] + db $02 + + +ENDC diff --git a/src/constants.asm b/src/constants.asm index 44116b0..e219018 100644 --- a/src/constants.asm +++ b/src/constants.asm @@ -65,7 +65,7 @@ CHARMAP "|", 126 CHARMAP "#", 125 -SECTION "Static Data", ROM0 +SECTION "Static Data", ROMX, BANK[1] sLeady:: db " READY? " sGo:: db " GO " sPause:: diff --git a/src/include/globals.asm b/src/include/globals.asm index 39eb04b..c4f0e80 100644 --- a/src/include/globals.asm +++ b/src/include/globals.asm @@ -93,6 +93,10 @@ MACRO lb ld \1, (LOW(\2) << 8) | LOW(\3) ENDM +DEF SAVE_MAGIC_0 EQU "D" +DEF SAVE_MAGIC_1 EQU "M" +DEF SAVE_MAGIC_2 EQU "G" +DEF SAVE_MAGIC_3 EQU "3" DEF PALETTE_REGULAR EQU %11100100 DEF PALETTE_INVERTED EQU %00011011 @@ -211,5 +215,7 @@ DEF FIELD_TOP_LEFT EQU $9800+1 DEF EASTER_0 EQU $9845 DEF EASTER_1 EQU $9865 +DEF rBANKID EQU $4000 + ENDC diff --git a/src/main.asm b/src/main.asm index f83d15f..acf9f8c 100644 --- a/src/main.asm +++ b/src/main.asm @@ -45,17 +45,6 @@ wInitialH:: ds 1 wInitialL:: ds 1 -SECTION "Persistent Globals", SRAM -rMagic:: ds 4 -rSwapABState:: ds 1 -rRNGModeState:: ds 1 -rRotModeState:: ds 1 -rDropModeState:: ds 1 -rSpeedCurveState:: ds 1 -rAlways20GState:: ds 1 -rSelectedStartLevel:: ds 2 - - SECTION "Stack", WRAM0 wStack:: ds STACK_SIZE + 1 @@ -95,6 +84,13 @@ Main:: ldh [rKEY1], a stop .notgbc + ; Initialize the mapper. + ld a, CART_SRAM_ENABLE + ld [rRAMG], a + xor a, a + ld [rRAMB], a + ld a, BANK("Static Data") + ld [rROMB0], a ; We use a single set of tiles for the entire game, so we copy it at the start. ld de, Tiles @@ -107,91 +103,8 @@ Main:: call SetNumberSpritePositions call CopyOAMHandler - ; Enable RAM. (Not actually needed since we don't ACTUALLY use an MBC, but without this emulators shit the bed.) - ld hl, rRAMG - ld a, CART_SRAM_ENABLE - ld [hl], a - - ; Check for save data. - ld a, [rMagic] - cp a, "D" - jr nz, .nosavedata - ld a, [rMagic+1] - cp a, "M" - jr nz, .nosavedata - ld a, [rMagic+2] - cp a, "G" - jr nz, .nosavedata - ld a, [rMagic+3] - cp a, "2" - jr nz, .nosavedata - -.savedata - ld a, [rSwapABState] - ld [wSwapABState], a - ld a, [rRNGModeState] - ld [wRNGModeState], a - ld a, [rRotModeState] - ld [wRotModeState], a - ld a, [rDropModeState] - ld [wDropModeState], a - ld a, [rSpeedCurveState] - ld [wSpeedCurveState], a - ld a, [rAlways20GState] - ld [wAlways20GState], a - ld a, [rSelectedStartLevel] - ldh [hStartSpeed], a - ld a, [rSelectedStartLevel+1] - ldh [hStartSpeed+1], a - jr .otherinit - -.nosavedata - ld a, "D" - ld [rMagic], a - ld a, "M" - ld [rMagic+1], a - ld a, "G" - ld [rMagic+2], a - ld a, "2" - ld [rMagic+3], a - - ld a, BUTTON_MODE_NORM - ld [rSwapABState], a - ld [wSwapABState], a - - ld a, RNG_MODE_TGM3 - ld [rRNGModeState], a - ld [wRNGModeState], a - - ld a, RNG_MODE_TGM3 - ld [rRNGModeState], a - ld [wRNGModeState], a - - ld a, ROT_MODE_ARSTI - ld [rRotModeState], a - ld [wRotModeState], a - - ld a, DROP_MODE_SONIC - ld [rDropModeState], a - ld [wDropModeState], a - - ld a, SCURVE_DMGT - ld [rSpeedCurveState], a - ld [wSpeedCurveState], a - - ld a, HIG_MODE_OFF - ld [rAlways20GState], a - ld [wAlways20GState], a - - ld hl, sSpeedCurve - ld a, l - ldh [hStartSpeed], a - ld [rSelectedStartLevel], a - ld a, h - ldh [hStartSpeed+1], a - ld [rSelectedStartLevel+1], a - -.otherinit + ; Other initialization. + call RestoreSRAM call TimeInit call IntrInit call InputInit diff --git a/src/res/gameplay_map.inc b/src/res/gameplay_map.inc index a299213..885f03a 100644 --- a/src/res/gameplay_map.inc +++ b/src/res/gameplay_map.inc @@ -19,7 +19,7 @@ IF !DEF(GAMEPLAY_MAP_INC) DEF GAMEPLAY_MAP_INC EQU 1 -SECTION "Gameplay Tilemap", ROM0 +SECTION "Gameplay Tilemap", ROMX, BANK[1] GameplayTilemap:: DB $02,$01,$01,$01,$01,$01,$01,$01,$01,$01 DB $01,$03,$09,$01,$01,$01,$01,$01,$01,$09 diff --git a/src/res/tiles.inc b/src/res/tiles.inc index 3c58ceb..cacb0f7 100644 --- a/src/res/tiles.inc +++ b/src/res/tiles.inc @@ -18,7 +18,7 @@ IF !DEF(TILES_INC) DEF TILES_INC EQU 1 -SECTION "Tile data", ROM0 +SECTION "Tile data", ROMX, BANK[1] Tiles:: DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF diff --git a/src/res/title_map.inc b/src/res/title_map.inc index f190f69..c2d9a81 100644 --- a/src/res/title_map.inc +++ b/src/res/title_map.inc @@ -19,7 +19,7 @@ IF !DEF(TITLE_MAP_INC) DEF TITLE_MAP_INC EQU 1 -SECTION "Title Screen Tilemap", ROM0 +SECTION "Title Screen Tilemap", ROMX, BANK[1] TitleScreenTilemap:: DB $C3,$5B,$4C,$59,$4F,$5A,$5D,$4C,$01,$59 DB $5A,$61,$4C,$01,$FA,$FB,$FC,$FD,$FE,$FF diff --git a/src/sfx.asm b/src/sfx.asm index b65f009..4da20dd 100644 --- a/src/sfx.asm +++ b/src/sfx.asm @@ -61,7 +61,7 @@ DEF REG_WAVE_PATTERN_E EQU $3E DEF REG_WAVE_PATTERN_F EQU $3F -SECTION "SFX Data", ROM0 +SECTION "SFX Data", ROMX, BANK[2] sSFXPieceI:: db REG_NR12_CH1_VOLEV, $00, REG_NR14_CH1_FRQHI, $80, REG_NR22_CH2_VOLEV, $00, REG_NR24_CH2_FRQHI, $80 db REG_NR32_CH3_VOLUM, $00, REG_NR34_CH3_FRQHI, $80, REG_NR42_CH4_VOLEV, $00, REG_NR44_CH4_CNTRL, $80 @@ -2431,6 +2431,12 @@ SFXKill:: ; This play routine must be called every frame. SFXPlay:: + ; Bank to SFX bank. + ld a, [rBANKID] + ld e, a + ld a, BANK("SFX Data") + ld [rROMB0], a + ; Load the playhead position into HL. ldh a, [hPlayhead] ld l, a @@ -2439,7 +2445,10 @@ SFXPlay:: ; Nothing to do if it's a null ptr. or a, l - ret z + jr nz, .getRegister + ld a, e + ld [rROMB0], a + ret ; Otherwise, get the register to write to. .getRegister @@ -2449,6 +2458,8 @@ SFXPlay:: ; If it's $FE, then we're done. Check if there's more for us in the queue. cp a, $FE jr nz, :+ + ld a, e + ld [rROMB0], a call SFXProcessQueue ret @@ -2473,6 +2484,8 @@ SFXPlay:: ldh [hPlayhead], a ld a, h ldh [hPlayhead+1], a + ld a, e + ld [rROMB0], a ret diff --git a/src/sram.asm b/src/sram.asm new file mode 100644 index 0000000..96f32b4 --- /dev/null +++ b/src/sram.asm @@ -0,0 +1,160 @@ +; DMGTRIS +; Copyright (C) 2023 - Randy Thiemann + +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. + +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. + +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . + + +IF !DEF(SRAM_ASM) +DEF SRAM_ASM EQU 1 + + +INCLUDE "globals.asm" + + +SECTION "Persistent Globals", SRAM +rMagic:: ds 4 +rCheck:: ds 6 +rSwapABState:: ds 1 +rRNGModeState:: ds 1 +rRotModeState:: ds 1 +rDropModeState:: ds 1 +rSpeedCurveState:: ds 1 +rAlways20GState:: ds 1 +rSelectedStartLevel:: ds 2 + + +SECTION "SRAM Functions", ROM0 +InitializeSRAM: + ; Set the magic id. + ld a, SAVE_MAGIC_0 + ld [rMagic], a + ld a, SAVE_MAGIC_1 + ld [rMagic+1], a + ld a, SAVE_MAGIC_2 + ld [rMagic+2], a + ld a, SAVE_MAGIC_3 + ld [rMagic+3], a + + ; Load defaults. + ld a, BUTTON_MODE_NORM + ld [rSwapABState], a + ld [wSwapABState], a + + ld a, RNG_MODE_TGM3 + ld [rRNGModeState], a + ld [wRNGModeState], a + + ld a, ROT_MODE_ARSTI + ld [rRotModeState], a + ld [wRotModeState], a + + ld a, DROP_MODE_SONIC + ld [rDropModeState], a + ld [wDropModeState], a + + ld a, SCURVE_DMGT + ld [rSpeedCurveState], a + ld [wSpeedCurveState], a + + ld a, HIG_MODE_OFF + ld [rAlways20GState], a + ld [wAlways20GState], a + ; Falls through to the next label! + + +PartiallyInitializeSRAM: + ; Save build data. + ld a, LOW(__UTC_YEAR__) + ld [rCheck], a + ld a, __UTC_MONTH__ + ld [rCheck+1], a + ld a, __UTC_DAY__ + ld [rCheck+2], a + ld a, __UTC_HOUR__ + ld [rCheck+3], a + ld a, __UTC_MINUTE__ + ld [rCheck+4], a + ld a, __UTC_SECOND__ + ld [rCheck+5], a + + ; Set to the default start level. + ld hl, sSpeedCurve + ld a, l + ldh [hStartSpeed], a + ld [rSelectedStartLevel], a + ld a, h + ldh [hStartSpeed+1], a + ld [rSelectedStartLevel+1], a + ret + + +RestoreSRAM:: + ; Check if our SRAM is initialized at all. + ; If not, we load all the defaults. + ld a, [rMagic] + cp a, SAVE_MAGIC_0 + jr nz, InitializeSRAM + ld a, [rMagic+1] + cp a, SAVE_MAGIC_1 + jr nz, InitializeSRAM + ld a, [rMagic+2] + cp a, SAVE_MAGIC_2 + jp nz, InitializeSRAM + ld a, [rMagic+3] + cp a, SAVE_MAGIC_3 + jp nz, InitializeSRAM + + ; If SRAM is initialized, we still need to check if it's for this exact build. + ; If not, wipe data that is no longer valid. + ld a, [rCheck] + cp a, LOW(__UTC_YEAR__) + jr nz, PartiallyInitializeSRAM + ld a, [rCheck+1] + cp a, __UTC_MONTH__ + jr nz, PartiallyInitializeSRAM + ld a, [rCheck+2] + cp a, __UTC_DAY__ + jr nz, PartiallyInitializeSRAM + ld a, [rCheck+3] + cp a, __UTC_HOUR__ + jr nz, PartiallyInitializeSRAM + ld a, [rCheck+4] + cp a, __UTC_MINUTE__ + jr nz, PartiallyInitializeSRAM + ld a, [rCheck+5] + cp a, __UTC_SECOND__ + jr nz, PartiallyInitializeSRAM + + ; SRAM is initialized and for this build, so we can load the data. + ld a, [rSwapABState] + ld [wSwapABState], a + ld a, [rRNGModeState] + ld [wRNGModeState], a + ld a, [rRotModeState] + ld [wRotModeState], a + ld a, [rDropModeState] + ld [wDropModeState], a + ld a, [rSpeedCurveState] + ld [wSpeedCurveState], a + ld a, [rAlways20GState] + ld [wAlways20GState], a + + ld a, [rSelectedStartLevel] + ldh [hStartSpeed], a + ld a, [rSelectedStartLevel+1] + ldh [hStartSpeed+1], a + ret + + +ENDC