This is the freely redistributable source code to a clone of Sokoban for the Nintendo Entertainment System. This game is written in 6502 assembly. There did not seem to be any Nintendo code in the database, (so I thought this would be a good addition).
;Sokoban - Johannes Holmberg 1999-2000
spritemem = $200
bgpaldata = $BFE0
sprpaldata = $BFF0
playerxdata = $20
paladdr = $3F00
sprpaladdr = $3F10
ppucontrol1 = $61
noboxdata = $B300
playerx = $2FF
playery = $2FC
px = $310
py = $311
lvlmatrix = $300
behbox = $500
lvlpointer = $0
boxcount = $10
boxptr = $11
boxesleft = $12
tx = $20
ty = $21
curboxptr = $40
temp1 = $50
temp2 = $51
temp3 = $52
temp4 = $53
temp5 = $54
temp6 = $55
temp7 = $56
temp8 = $57
dirx = $45
diry = $46
bgwall = $60
bgground = $65
bggoal = $62
spbox = $63
spchar = $64
memlvlptr = $2
startpressed = $58
.org $C000
reset
sei
cld
ldx $0
stx $2000
stx ppucontrol1
stx $2001
lda #7
sta $1
lda #0
ldy #0
ldx #$FF
txs ;Set stack pointer to $FF
clearram ;Clear ram...
sta (0),y
dey
bne clearram
dec $1
bpl clearram
lda #$20 ;Clear name and attribute tables.=$1000 bytes
sta $2006
lda #0
sta $2006
ldy #$10 ;$10*$100=$1000
ldx #0
clearppuram
sta $2007
dex
bne clearppuram
dey
bne clearppuram
lda #$3F
ldx #$0
sta $2006
stx $2006
ldy #$20
setpalette ;Set the palette...
lda bgpaldata,x
sta $2007
inx
dey
bne setpalette
lda #$FF ;Tile numbers...
sta bgwall
lda #$4F
sta bgground
lda #$9F
sta bggoal
lda #$FF
sta spchar
lda #$3F
sta spbox
lda #1
sta boxesleft ;Just a precaution...
lda #$90 ;Allow NMIs, and set background address to $1000.
sta $2000
sta ppucontrol1
lda #0
sta startpressed
jsr titlescreen ;Titlescreen...
lda #$80 ;Set the level pointer to $8000 - level 1 (duh).
sta lvlpointer+1
bigloop
jsr loadlevel ;Load the level lvlpointer points to.
ostro ;Just do nothing until there is a VBlank.
jmp ostro
vblank
pha ;Store the values of the registers.
txa ;Not actually necessary right now,
pha ;but it might be in the future.
tya
pha
lda boxesleft ;Determine whether this level is completed.
bne keepplayingthislevel
inc lvlpointer+1
jsr loadlevel
keepplayingthislevel
lda #0 ;Make sure the screen doesn't scroll :)
sta $2005
sta $2005
sta dirx ;No movement (delete old movement values).
sta diry
lda #2
sta $4014 ;This seems like a stupid thing to do, oh well. :)
ldx #1
stx $4016
dex
stx $4016 ;Reset joypad register.
lda $4016 ;A ;These buttons are currently unused...
lda $4016 ;B
lda $4016 ;Select
lda $4016 ;Start?
and #1
beq notstart
lda startpressed
bne startalreadypressed
lda #$FF
sta startpressed
pla ;Reset stack pointer
pla
pla
dec bgwall
dec bgground
dec bggoal
dec spchar
dec spbox ;These are all increased by loadlevel
jmp bigloop ;Reload level.
notstart
lda #0
sta startpressed
startalreadypressed
lda $4016 ;Up?
and #1
beq notup
lda #$FF
sta diry
jmp trytomove
notup
lda $4016 ;Down?
and #1
beq notdown
lda #1
sta diry
jmp trytomove
notdown
lda $4016 ;Left?
and #1
beq notleft
lda #255
sta dirx
jmp trytomove
notleft
lda $4016 ;Right?
and #1
beq notright
lda #1
sta dirx
jmp trytomove
notright
backfrommoving
pla ;Get the register values back...
tay
pla
tax
pla
rti
trytomove ;Check if movement is possible.
lda #6 ;Set the levelpointer.
sta memlvlptr+1
lda #0
sta memlvlptr
sta temp3 ;Store the pointer (might be unnecessary).
sta temp4
lda playerx ;Load the player's x coordinate.
lsr a
lsr a ;Divide by 8 (sprite width).
lsr a
sta px ;Store in another variable!
clc
adc dirx ;Add the x movement to it.
sta temp1 ;Store in temp1!!! :)
lda playery ;Do the same thing to the y coordinate.
clc
adc #1 ;Add one (you know why...).
lsr a
lsr a ;Divide by 8 (Sprite height...).
lsr a
sec
sbc #6 ;Subtract 6 (The playing field is centered on the screen).
clc
adc diry ;Add the y direction.
asl a
asl a
asl a ;Multiply by 32 (screen width in tiles).
asl a
asl a
sta memlvlptr ;Store in memlvlptr.
lda #0
adc memlvlptr+1 ;Add 0 to the high byte of memlvlptr,
sta memlvlptr+1 ;Incase there is a carry bit.
sta temp8 ;Store in temp8.
lda memlvlptr
clc
adc temp1 ;Add temp1 (x position) to memlvlptr.
sta temp7 ;Store in temp7.
sta memlvlptr ;Store in memlvlptr...
ldy #0 ;No offset.
lda (memlvlptr),y ;Load the byte at memlvlptr.
cmp #$50 ;Is the square empty?
beq normalmove
cmp #$A0 ;Is it a "goal"-square?
beq normalmove
cmp #$FE ;Is it a box?
beq pushmove
jmp backfrommoving
pushmove
jsr moveboxtest
jmp backfrommoving
normalmove
jsr move
cantmove
jmp backfrommoving
moveboxtest ;Check the tile after the box to see if it is empty.
lda diry
asl a
asl a
asl a
asl a
asl a
sta temp1
lda memlvlptr
pha
clc
adc dirx
clc
adc temp1
sta memlvlptr
sta temp5
pla ;
lsr a ;
lsr a ;
lsr a ;
lsr a ;
lsr a ;
cmp #7 ;
bne notthatway ;
lda diry ;
cmp #1 ;
bne nobigchange ;
jmp bigchange ;
notthatway ;
cmp #0 ;
bne nobigchange ;
lda diry ;
cmp #$FF ;
bne nobigchange ;
bigchange ;
lda memlvlptr+1 ;
eor #1 ;
sta memlvlptr+1 ;
; bcc nobigchange
; lda temp1
; bmi nobigchange
; lda memlvlptr+1
; eor #1 ;Change the high byte if there has been an overflow.
; sta memlvlptr+1
nobigchange
lda memlvlptr+1
sta temp6
lda (memlvlptr),y
sta temp3
cmp #$50
beq oktomove ;Ok, it's empty.
cmp #$A0
beq movetogoal ;Ok, it's a "goal"-square.
rts
movetogoal
dec boxesleft
oktomove
;Find the right sprite...
lda dirx ;Get the box coordinates by adding the
asl a ;movement values to the player coordinates.
asl a
asl a
clc
adc playerx
sta temp1
lda diry
asl a
asl a
asl a
clc
adc playery
sta temp2
ldy #0
trynextsprite ;Now go through all the sprites.
lda spritemem,y ;First check the y position.
cmp temp2
beq tryxtoo
iny
iny
iny
iny
bne trynextsprite
tryxtoo ;If y is a match, check x too.
lda spritemem+3,y
cmp temp1
beq foundit ;If x also matches it must be the one!
iny
iny
iny
iny
bne trynextsprite
foundit
sty curboxptr ;Store the boxponter in curboxptr!
lda curboxptr ;Hmm, why not do a tya? :)
lsr a ;Divide by 4 to get the sprite number.
lsr a
tax ;Store it in x.
lda temp7 ;Load memlvlptr from temp7 and temp8.
sta memlvlptr
lda temp8
sta memlvlptr+1
ldy #0
lda behbox,x ;See what's behind the box that is about to be moved.
sta (memlvlptr),y ;Store it instead of the box at that position.
cmp #$A0
bne itsnotagoalsquare
inc boxesleft
itsnotagoalsquare
lda temp5 ;Get the memlvlptr for the new boxposition.
sta memlvlptr ;temp5 and temp6...
lda temp6
sta memlvlptr+1
lda (memlvlptr),y ;See what is there.
sta behbox,x ;Store it in behbox,
lda #$FE ;and replace it with a box value.
sta (memlvlptr),y
;Now move the damn box!!!
lda ppucontrol1 ;Just some code to do the animation
and #$7F ;and change the coordinates of the player/box.
sta ppucontrol1
sta $2000
ldy #8
ldx curboxptr
novblankyet2
lda $2002
bpl novblankyet2
lda #$2
sta $4014
lda dirx
clc
adc playerx
sta playerx
lda diry
clc
adc playery
sta playery
lda spritemem,x
clc
adc diry
sta spritemem,x
lda spritemem+3,x
clc
adc dirx
sta spritemem+3,x
dey
bne novblankyet2
lda ppucontrol1
ora #$80
sta ppucontrol1
sta $2000
;slut p† det... <-Swedish ;)
rts
move ;Move the player...
lda ppucontrol1
and #$7F
sta ppucontrol1
sta $2000
ldy #8
novblankyet
lda $2002
bpl novblankyet
lda #$2
sta $4014
lda dirx
clc
adc playerx
sta playerx
lda diry
clc
adc playery
sta playery
dey
bne novblankyet
lda ppucontrol1
ora #$80
sta ppucontrol1
sta $2000
rts
loadlevel ;Load the level...
inc bgwall ;Use new set of tiles.
inc bgground
inc bggoal
inc spchar
inc spbox
lda #0
sta $2001 ;Disable backgrounds...
lda ppucontrol1
and #$7F
sta $2000 ;Disable NMIs.
sta ppucontrol1
lele ;_Bnu was here. (?)
lda $2002
bpl lele
;Nytt
lda #$3F
sta $2006
lda #$00
sta $2006
lda #0
ldx #4
clc
newpaletteloop
adc #$10
tay
pha
lda (lvlpointer),y
sta $2007
pla
dex
bne newpaletteloop
pha
lda #$3F
sta $2006
lda #$10
sta $2006
pla
ldx #8
newpaletteloop2
adc #$10
tay
pha
lda (lvlpointer),y
sta $2007
pla
dex
bne newpaletteloop2
;slut p† nytt
lala
lda $2002
bpl lala
lda #6
sta ty
sta memlvlptr+1 ;
ldy #0 ;Reset sprites...
sty tx
sty boxptr
sty boxcount
sty memlvlptr ;
resetsprites
tya
lsr a
lsr a
tay
lda #$50
sta behbox,y
tya
asl a
asl a
tay
lda #$F2
sta spritemem,y
iny
lda spbox
sta spritemem,y
iny
lda #1
sta spritemem,y
iny
iny
bne resetsprites
sty playery+2
ldy spchar
sty playery+1
lda #$20 ;Don't remember what this is supposed to do... Seems wrong...
ldy #$C0 ;Oh well...
sta $2006
lda #0
sta $2006
ldx #$FF
settoff
stx $2007
dey
bne settoff
ldx #1 ;Shift the first one, don't and.
loadmore
lda (lvlpointer),y
dex
bmi andnotshift
lsr a
lsr a
lsr a
lsr a
jmp donewiththisstuff
andnotshift
and #$F
donewiththisstuff
cmp #5 ;Is it the player?
bne notplayer
lda ty
asl a
asl a
asl a ;Multiply by 8...
sbc #0 ;subtract 1...
sta playery
lda tx
asl a
asl a
asl a ;Multiply by 8...
sta playerx
lda #$50
pha
lda bgground
jmp notafloor
notplayer
cmp #6
bne notbox2
inc boxcount
tya ;Create a new boxsprite...
pha
lda ty
asl a
asl a
asl a ;Multiply by 8 (sprite height)
sbc #0 ;Subtract one from the y-position. Assumes that carry is not set.
pha
ldy boxptr
lda #$A0
sta behbox,y
pla
sta spritemem,y
iny
iny
iny
lda tx
asl a
asl a
asl a ;Multiply by 8 (sprite width :)
sta spritemem,y
iny
sty boxptr
lda #1 ;
sta temp4 ;
pla
tay
lda #$A0
pha
lda bggoal
jmp notafloor
notbox2
cmp #4
bne notbox
tya ;Create a new boxsprite...
pha
inc boxcount
lda ty
asl a
asl a
asl a ;Multiply by 8 (sprite height)
sbc #0 ;Subtract one from the y-position. Assumes that carry is not set.
ldy boxptr
sta spritemem,y
iny
iny
iny
lda tx
asl a
asl a
asl a ;Multiply by 8 (sprite width :)
sta spritemem,y
iny
sty boxptr
lda #1 ;
sta temp4 ;
pla
tay
lda #$50
pha
lda bgground
jmp notafloor
notbox
cmp #0
bne notempty
lda #$FF
pha
jmp notafloor
notempty
cmp #1
bne notawall
lda #$0
pha
lda bgwall
jmp notafloor
notawall
cmp #3
bne notagoal
lda #$A0
pha
lda bggoal
jmp notafloor
notagoal
cmp #2
bne notafloor
lda #$50
pha
lda bgground
notafloor
sta $2007
;pha
lda temp4 ;
beq nochange ;
pla ;
lda #$FE ;
pha ;
nochange ;
tya
asl a
bcc notpage2
lda #7
sta memlvlptr+1
notpage2
txa
beq noadd
tya
asl a
bcs cool ;clc
adc #1
jmp add
cool ;
clc ;
adc #1 ;
sec ;
jmp add ;
noadd
tya
asl a
add
tay
pla
sta (memlvlptr),y ;
tya
ror a
tay
lda #0 ;
sta temp4 ;
inc tx
lda #$20
cmp tx
bne notnewline
lda #$FF
sta $2007
sta $2007
lda #2 ;blaff
iny
beq doneloading
sta tx
inc ty
notnewline
txa
bne dotheiny
jmp loadmore
dotheiny
ldx #1
iny
beq doneloading
jmp loadmore
doneloading
ldx #$FF
settoff2
stx $2007
dey
bne settoff2
lda lvlpointer+1
sec
sbc #$80
tay
ldx noboxdata,y
stx boxesleft
uuu
lda $2002 ;Working?
bpl uuu
lda #$18
sta $2001
lda ppucontrol1
ora #$80
sta ppucontrol1
sta $2000
rts
titlescreen
lda #0
sta $2001
lda ppucontrol1
and #$7F
sta ppucontrol1
sta $2000
lda #$20
sta $2006
lda #0
sta $2006
ldy #$C0
ldx #4
lda #$FF
paintitblack
sta $2007
dey
bne paintitblack
dex
bne paintitblack
lda #$21
sta $2006
ldx #0
stx $2006
drawmore
lda $B200,x
beq drawless
sta $2007
inx
bne drawmore
drawless
lda #$22
sta $2006
lda #$A
sta $2006
ldx #0
drawpressstart
lda $B2C0,x
beq yetanotherlabel
sta $2007
inx
bne drawpressstart
yetanotherlabel
lda #$18
sta $2001
lda ppucontrol1
and #$7f
sta ppucontrol1
sta $2000
ostronhest
ldx #1
stx $4016
dex
stx $4016
stx $2005
stx $2005
lda $4016
lda $4016
lda $4016
lda $4016
and #1
cmp #1
beq startispushed
jmp ostronhest
startispushed
lda ppucontrol1
ora #$80
sta ppucontrol1
sta $2000
rts
.org $FFFA
.word vblank
.word reset
.word reset
.end