Hacking Flappy Bird

By @frankbuss7/17/2016hacking

A walk-through of hacking Flappy Bird. Sos created a port of the iOS game Flappy Bird for the C64. The difficulty of the game is crazy, so I hacked it and implemented a computer player for it (my highscore without the hack was 9).

Unpack

First I needed to unpack the game. I loaded it in the VICE emulator, set a breakpoint in the monitor at the program start and after some single stepping and more breakpoints finally the game started with a jump to $3000. I saved the game with "bsave" (from $0801 to $7fff) in the monitor. There was another basic header after unpacking, which jumps to $3000.

Analyze

Then my idea was to emulate the joystick fire presses. I set a breakpoint on joystick input read ("break load dc00") and there are multiple positions in the program where it is read: waiting for fire when the game starts, acknowledge of the help graphics and then in the game. The position in the game is at $5da8. I replaced it with a "jsr $c000", filled the PRG file until $bfff and wrote some assembler to concat at the end of the PRG. First test was a "lda $dc00; rts" and it worked.

Then I analyzed how the game detects a hit with the tubes. This was easy, because when I disabled "sprite-background collisions" in the VIC settings in VICE, it didn't detect hits with the tubes anymore. So the tubes are characters with a modified character set and of course the bird is a sprite. A quick fill test for $0400 showed that the standard character screen position was still used. I set a breakpoint on store on $0427 (last character in the first row, "break store $0427") and found the scroll function and function for creating new tubes. It uses the voice 3 oscillator register for the y position, with the noise generator as a random number generator. There is a counter at $1e1e for the distance between the tubes and when it is 0, I can read the y character position in $1e20.

Hack

The rest was easy: Calculate the y raster position from the character position, delay it with a ringbuffer and compare it with the bird y sprite position. If too low, flap. As a bonus, the hack can be enabled with joystick left, and disabled with right. The source code, save it as flappy.asm:

.pc = $c000
		txa
		pha

		// default result is original joystick value
		lda $dc00
		sta result
		
		// joystick left = enable hack
		and #4
		bne !+
		lda #1
		sta hackEnabled
		
		// joystick right = disable hack
!:		lda result
		and #8
		bne !+
		lda #0
		sta hackEnabled
		
		// filter joystick left/right
!:		lda result
		ora #12
		sta result
		
		// increment ringbuffer pointer
		inc ringRead
		inc ringWrite
		
		// save last character position as y raster position when valid
		lda $1e1e
		cmp #0
		bne !+
		lda #20
		sec
		sbc $1e20
		asl
		asl
		asl
		clc
		adc #14
		sta lastPos
		
		// write last position to ringbuffer
!:		ldx ringWrite
		lda lastPos
		sta ringbuffer,x
		
		// test if hack is enabled
		lda hackEnabled
		beq end
		
		// default value for joystick, if hack is enabled
		lda #$ff
		sta result

		// compare delayed last position with bird sprite y position
		ldx ringRead
		lda ringbuffer,x
		cmp $d003
		bcs end
		
		// flap, with a delay between the flaps
		inc flapDelay
		lda flapDelay
		cmp #2
		bne end
		lda #0
		sta flapDelay
		lda #$00
		sta result
		
end:		pla
		tax
		lda result
		rts
		
lastPos:	.byte 0
result:		.byte 0
flapDelay:	.byte 0
hackEnabled:	.byte 0
ringWrite:	.byte 70
ringRead:	.byte 0
		.align $100
ringbuffer:	.fill 256, 150

For faster turnaround time while adjusting the offsets and ringbuffer delay, I used a script to compile my assembler program, concat it to the original program and start it in VICE:

java -jar "C:\Program Files (x86)\kickassembler\KickAss.jar" -binfile flappy.asm
copy /b flappy-unpacked.prg + flappy.bin flappy.prg
"C:\Program Files\WinVICE-2.4-x64\x64.exe" flappy.prg

Pack

Finally I packed the result with exomizer: flappy-bird.prg

https://www.youtube.com/watch?v=iYu8XzyS3-0

#hacking #hack #game #c64 #flappy-bird #vice #exomizer

2

comments