Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ I built this project on macOS. The instructions should be pretty easy to follow
The build pipeline has dependencies on [node.js](http://nodejs.org) and [SDCC](http://sdcc.sourceforge.net). You'll need to install them.

### Dependencies
`cd` into `ihx2gb/` and run `npm install`.

`cd` into `img2gb/` and run `npm install`.

`cd` into `stringc/` and run `npm install`.

### Building the Game
`cd` into `game/` and run `make` or `make debug`.

### Building the Game and Dependencies
Just run `make`, `make debug` or `make run` in the root folder.

### Building with an SDCC Snapshot
*This is for versions of SDCC that aren't installed*
```
SDCC_HOME=/path/to/sdcc/share/sdcc/
make SDCCBIN=${SDCC_HOME}../../bin/
```
75 changes: 49 additions & 26 deletions game/makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
CC = sdcc
ASMC = sdasgb
CFLAGS = -c -mgbz80
ASMFLAGS = -plosgffjw
LINKFLAGS = -mgbz80 --no-std-crt0 --data-loc 0xc0a0
SDCCBIN =
CC = $(SDCCBIN)sdcc
AS = $(SDCCBIN)sdasgb
MKROM = $(SDCCBIN)makebin
# https://github.com/LIJI32/SameBoy or any other emulator
EMU = sameboy
# https://github.com/bbbbbr/romusage
ROMUSE = romusage
NODE = node
CFLAGS = -c -msm83
ASFLAGS = -plosgffjw
LDFLAGS = -msm83 --no-std-crt0 --data-loc 0xc0a0

GFXS = $(notdir $(shell find data/gfx -name '*.png'))
GFXSRC = $(patsubst %.png,data_gfx_%.c,$(GFXS))
Expand All @@ -13,44 +20,60 @@ OBJS = $(SRCS:.c=.o)
SRCFILES = $(patsubst %.c,src/%.c,$(SRCS))
OBJFILES = $(patsubst %.s,obj/%.rel,$(ASMS)) $(patsubst %.c,obj/%.rel,$(SRCS))

build: obj/dependencies bin/BubbleFactory.gb
ROM = BubbleFactory

debug: CFLAGS += -DDEBUG
.PHONY: build debug run clean spaceleft statistics

build: obj/dependencies bin/$(ROM).gb

debug: CFLAGS += -DDEBUG --debug
debug: LDFLAGS += -Wl-y
debug: build

src/data_strings.c: data/strings.json
node ../stringc data/stringsMap.json $< $@
$(NODE) ../stringc data/stringsMap.json $< $@

src/data_gfx_%.c: data/gfx/%.png
node ../img2gb -n $(notdir $(basename $<)) $< $@
$(NODE) ../img2gb -n $(notdir $(basename $<)) $< $@

obj/dependencies: $(SRCFILES)
obj/dependencies: $(SRCFILES) | obj/
@echo "regenerate dependency file"
@mkdir -p obj
@rm -f obj/dependencies
@$(RM) -f obj/dependencies
@for srcFile in $(SRCFILES) ; do \
{ printf "obj/"; $(CC) -MM $$srcFile; } >> obj/dependencies ; \
done

-include obj/dependencies

bin/BubbleFactory.gb: obj/game.ihx
@mkdir -p bin
node ../ihx2gb --name BUBBLEFACT --licensee DH --cartridge 0x1B --ram 1 --version 1 $< $@
bin/$(ROM).gb: obj/game.ihx | bin/
$(MKROM) -Z -yn BUBBLEFACT -yk DH -yt 0x1B -ya 1 -yS -yp0x014C=1 $< $@
cp obj/game.sym bin/$(ROM).sym
cp obj/game.noi bin/$(ROM).noi
test \! -s obj/game.cdb || cp obj/game.cdb bin/$(ROM).cdb

obj/game.ihx: $(OBJFILES)
@mkdir -p obj
$(CC) $(LINKFLAGS) $^ -o $@
obj/game.ihx: $(OBJFILES) | obj/
$(CC) $(LDFLAGS) $^ -o $@

obj/%.rel: src/%.c
@mkdir -p obj
obj/%.rel: src/%.c | obj/
$(CC) $(CFLAGS) $< -o $@

obj/%.rel: src/%.s
@mkdir -p obj
$(ASMC) $(ASMFLAGS) $@ $<
obj/%.rel: src/%.s | obj/
$(AS) $(ASFLAGS) $@ $<

%/:
@mkdir -p $@

spaceleft: build
$(ROMUSE) bin/$(ROM).noi -g -E

statistics: build
test \! -s bin/$(ROM).cdb || $(ROMUSE) bin/$(ROM).cdb -g
$(ROMUSE) bin/$(ROM).noi -G -E -sH -a

run: build
$(EMU) bin/$(ROM).gb

clean:
rm -rf src/data_*
rm -rf obj
rm -rf bin
$(RM) -rf src/data_*
$(RM) -rf obj
$(RM) -rf bin
10 changes: 4 additions & 6 deletions game/src/crt0.s
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,22 @@
ld sp, #0xE000

; initialize gamepad to 0
ld a, #0
xor a
ld (_gbJoypadState), a

; install dma handler
ld c, #(.endOAMDMA - .oamDMA)
ld de, #0xFF80
ld hl, #.oamDMA

; c is never 0
.installOAMDMALoop:
ld a, c
or a
jr z, .endInstallOAMDMALoop

ld a, (hl+)
ld (de), a
inc de

dec c
jr .installOAMDMALoop
jr nz, .installOAMDMALoop
.endInstallOAMDMALoop:

call _main
Expand Down
53 changes: 25 additions & 28 deletions game/src/gb.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void gbLCDDisable() {

; busy wait for vblank
.lcdDisableLoop:
ld a, (#0xff44)
ldh a, (#0xff44)
cp a, #144
jr nz, .lcdDisableLoop

Expand Down Expand Up @@ -69,29 +69,40 @@ void gbJoypadStateUpdate() {

push af
push bc
ld c, #0

; Read first part of joypad state
ld a, #0x20
ld (#0xff00), a
ldh (c), a

; Read several times to burn cycles waiting for register to update
ld a, (#0xff00)
ld a, (#0xff00)
; `ldh a, (c); ldh a, (c)` same amount of clocks
; as `ld a, (#0xff00)` but one byte less
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
cpl ; Invert so 1=on and 0=off
and #0x0f ; Only want 4 least significant bits
ld b, a ; Store in b

; Read second part of joypad state
ld a, #0x10
ld (#0xff00), a
ldh (c), a

; Read several times to burn cycles waiting for register to update
ld a, (#0xff00)
ld a, (#0xff00)
ld a, (#0xff00)
ld a, (#0xff00)
ld a, (#0xff00)
ld a, (#0xff00)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)
ldh a, (c)

cpl ; invert
and #0x0f ; only 4 least significant bits
Expand All @@ -109,44 +120,30 @@ void gbJoypadStateUpdate() {
gbJoypadReleasedSinceLastUpdate = (gbJoypadState ^ lastValue) & lastValue;
}

// 8bit in a
void gbLogUInt8(GBUInt8 value) {
(void)(value); // Suppresses unused variable warning

__asm
push af
push hl
ldhl sp, #3
ld a, (hl)
ld d, d
jr .gbLogUInt8End
.dw 0x6464
.dw 0x0000
.strz "0x%a%"
.gbLogUInt8End:
pop hl
pop af
__endasm;
}

// 16bit in de
void gbLogUInt16(GBUInt16 value) {
(void)(value); // Suppresses unused variable warning

__asm
push af
push bc
push hl
ldhl sp, #8
ld a, (hl+)
ld c, a
ld b, (hl)
ld d, d
jr .gbLogUInt16End
.dw 0x6464
.dw 0x0000
.strz "0x%bc%"
.strz "0x%de%"
.gbLogUInt16End:
pop hl
pop bc
pop af
__endasm;
}
56 changes: 16 additions & 40 deletions game/src/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,9 @@ void mapUpdateGraphics() {
_needsToRedrawHighScore = false;

memoryCopyLength = 4;
memoryCopyDestinationAddress = gbTileMap0;
memoryCopySourceAddress = _highScoreMap[0];
memoryCopy();

memoryCopyDestinationAddress = gbTileMap0 + 32;
memoryCopySourceAddress = _highScoreMap[1];
memoryCopy();
memoryCopy(gbTileMap0, _highScoreMap[0]);

memoryCopy(gbTileMap0 + 32, _highScoreMap[1]);

return;
}
Expand All @@ -240,13 +236,9 @@ void mapUpdateGraphics() {
_needsToRedrawScore = false;

memoryCopyLength = 4;
memoryCopyDestinationAddress = gbTileMap0 + 16;
memoryCopySourceAddress = _scoreMap[0];
memoryCopy();

memoryCopyDestinationAddress = gbTileMap0 + 48;
memoryCopySourceAddress = _scoreMap[1];
memoryCopy();
memoryCopy(gbTileMap0 + 16, _scoreMap[0]);

memoryCopy(gbTileMap0 + 48, _scoreMap[1]);

return;
}
Expand Down Expand Up @@ -303,13 +295,9 @@ void mapUpdateGraphics() {
if(_mapAnimationTickTime & 2) {
// Top Left
memoryCopyLength = 8;
memoryCopyDestinationAddress = gbTileMap0 + 67;
memoryCopySourceAddress = tileAnimations1[_mapAnimationCycle];
memoryCopy();

memoryCopyDestinationAddress = gbTileMap0 + 99;
memoryCopySourceAddress = tileAnimations2[_mapAnimationCycle];
memoryCopy();
memoryCopy(gbTileMap0 + 67, tileAnimations1[_mapAnimationCycle]);

memoryCopy(gbTileMap0 + 99, tileAnimations2[_mapAnimationCycle]);

if(bubblesIsTopInDanger()) {
if((_mapAnimationCycle & 1) == 0) {
Expand All @@ -328,35 +316,23 @@ void mapUpdateGraphics() {
} else {
// Top Right
memoryCopyLength = 6;
memoryCopyDestinationAddress = gbTileMap0 + 75;
memoryCopySourceAddress = tileAnimations1[_mapAnimationCycle] + 8;
memoryCopy();

memoryCopyDestinationAddress = gbTileMap0 + 107;
memoryCopySourceAddress = tileAnimations2[_mapAnimationCycle] + 8;
memoryCopy();
memoryCopy(gbTileMap0 + 75, tileAnimations1[_mapAnimationCycle] + 8);

memoryCopy(gbTileMap0 + 107, tileAnimations2[_mapAnimationCycle] + 8);
}
} else {
if(_mapAnimationTickTime & 2) {
// Bottom Left
memoryCopyLength = 8;
memoryCopyDestinationAddress = gbTileMap0 + 451;
memoryCopySourceAddress = tileAnimations3[_mapAnimationCycle];
memoryCopy();
memoryCopy(gbTileMap0 + 451, tileAnimations3[_mapAnimationCycle]);

memoryCopyDestinationAddress = gbTileMap0 + 483;
memoryCopySourceAddress = tileAnimations4[_mapAnimationCycle];
memoryCopy();
memoryCopy(gbTileMap0 + 483, tileAnimations4[_mapAnimationCycle]);
} else {
// Bottom Right
memoryCopyLength = 6;
memoryCopyDestinationAddress = gbTileMap0 + 459;
memoryCopySourceAddress = tileAnimations3[_mapAnimationCycle] + 8;
memoryCopy();
memoryCopy(gbTileMap0 + 459, tileAnimations3[_mapAnimationCycle] + 8);

memoryCopyDestinationAddress = gbTileMap0 + 491;
memoryCopySourceAddress = tileAnimations4[_mapAnimationCycle] + 8;
memoryCopy();
memoryCopy(gbTileMap0 + 491, tileAnimations4[_mapAnimationCycle] + 8);

if(bubblesIsBottomInDanger()) {
if((_mapAnimationCycle & 1) == 0) {
Expand Down
Loading