Skip to content

Instantly share code, notes, and snippets.

@og2t
Created May 5, 2011 07:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save og2t/956683 to your computer and use it in GitHub Desktop.
Save og2t/956683 to your computer and use it in GitHub Desktop.
For Y extended sprite rows with single raster irq (two in fact)
.var spr1X = $d000
.var spr1Y = $d001
.var spr2X = $d002
.var spr2Y = $d003
.var spr3X = $d004
.var spr3Y = $d005
.var spr4X = $d006
.var spr4Y = $d007
.var spr5X = $d008
.var spr5Y = $d009
.var spr6X = $d00a
.var spr6Y = $d00b
.var spr7X = $d00c
.var spr7Y = $d00d
.var spr8X = $d00e
.var spr8Y = $d00f
.var code = $0810
.var startLine = $38 + 38
.var brkFile = createFile("breakpoints.txt")
.macro break()
{
.eval brkFile.writeln("break " + toHexString(*))
}
.pseudocommand nop x {
:ensureImmediateArgument(x)
.for (var i=0; i<x.getValue(); i++) nop
}
.pseudocommand pause cycles
{
:ensureImmediateArgument(cycles)
.var x = floor(cycles.getValue())
.if (x<2) .error "Cant make a pause on " + x + " cycles"
// Take care of odd cyclecount
.if ([x&1]==1) {
bit $00
.eval x=x-3
}
// Take care of the rest
.if (x>0)
:nop #x/2
}
.macro ensureImmediateArgument(arg) {
.if (arg.getType()!=AT_IMMEDIATE) .error "The argument must be immediate!"
}
//=======================================================================================
:BasicUpstart2(run)
.pc = code "code"
run: sei
lda #$34
sta $01 // copy to the last video bank
lda #$35
sta $01
jsr setup
lda #$7f
sta $dc0d
sta $dd0d
bit $dc0d
lda #$1b
sta $d011
lda #$55
sta $3fff
jsr vblank
lda #62 // set timer interval
sta $dc04
lda #$00
sta $dc05
lda #$01
cmp $d012
bne *-3
jsr delay_0
bne *+5
cmp $00
nop
jsr delay_1
bne *+4
cmp $00
jsr delay_1-1
beq *+2
lda #$11 // run timer exactly here
sta $dc0e
lda #<Stable_IRQ
sta $fffe
lda #>Stable_IRQ
sta $ffff
lda #1
sta $d01a
sta $d019
cli
jmp backgroundProcess
//---------------------------------------------
delay_0: ldx #$a2 // delay on Timer A CIA
ldx #$a2
ldx #$a6
delay_1: nop
ldx #$07
dex
bne *-1
lda $d012
cmp $d012
rts
//---------------------------------------------
Stable_IRQ: pha
txa
pha
tya
pha
sec
lda #$32
sbc $dc04
sta *+4
bpl *
lda #LDA_IMM
lda #LDA_IMM
lda #LDA_IMM
lda NOP
// stable raster here... cycle 46
display: lda $d012
bne switch
// here we are in raster $00
// set the next raster irq to the line before the start line
lda #startLine - 1
sta $d012
// first line of the text screen
lda #50
sta spr1Y
sta spr2Y
sta spr3Y
sta spr4Y
sta spr5Y
sta spr6Y
sta spr7Y
sta spr8Y
jmp irqExit
switch:
// start line
// reset the raster
lda #0
sta $d012
// perform the sprite crunch trick
jmp trick
irqExit: inc $d019
pla
tay
pla
tax
pla
rti
.align $100
trick: // set sprites y
lda #startLine
sta spr1Y
sta spr2Y
sta spr3Y
sta spr4Y
sta spr5Y
sta spr6Y
sta spr7Y
sta spr8Y
:pause #4
dec $d021
lda #$ff
sta $d017
:pause #4
// the trick happens exactly here
lda #$00
sta $d017
inc $d021
lda #$ff
sta $d017
// wait a line to set the new sprite y
:pause #63
// y extended sprites wrapped twice
lda #startLine + [2 * 2 * 21] + 1
sta spr1Y
sta spr2Y
sta spr3Y
sta spr4Y
sta spr5Y
sta spr6Y
sta spr7Y
sta spr8Y
// neither first or last byte of the sprite doesn't have any influence on the effect
inc lastByte
inc lastByte - 1
inc sprite
jmp irqExit
// ---------------------------------------------------------
setup: lda #$00
sta $d012
lda #$09
sta $d020
lda #$00
sta $d021
// set sprites
lda #40
sta spr1X
clc
adc #24
sta spr2X
adc #24
sta spr3X
adc #24
sta spr4X
adc #24
sta spr5X
adc #24
sta spr6X
adc #24
sta spr7X
adc #24
sta spr8X
lda #startLine
sta spr1Y
sta spr2Y
sta spr3Y
sta spr4Y
sta spr5Y
sta spr6Y
sta spr7Y
sta spr8Y
lda #sprite/64
sta $07f8
sta $07f9
sta $07fa
sta $07fb
sta $07fc
sta $07fd
sta $07fe
sta $07ff
lda #%11111111
sta $d015
lda #0
sta $d01b
// clear screen
ldx #0
lda #32
!: sta $0400,x
sta $0500,x
sta $0500,x
inx
bne !-
rts
vblank: lda $d011
bpl *-3
lda $d011
bmi *-3
rts
.align $100
.pc = * "background processes"
backgroundProcess:
//inc $d020
jmp backgroundProcess
// reference to charsets/banks
// write data
.pc = $2000 "sprite"
sprite: .by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $55
.by $aa, $aa, $aa
.by $55, $55, $ff
lastByte: .by $3f
/*
The normal Struktur of Sprites looks like this:
00, 01, 02,
03, 04, 05,
06, 07, 08,
: : :
3c, 3d, 3e
So there are always 3 Byte-Steps, but if you use Sprite-Crunching, you can change that Struktur.
Set the bits of $d017 before the start of the right sideborder and clear them two cycles before the end of the left sideborder and SCR will show its magic!
Then the SpritePositionByte (first of the 3 Bytes in a Sprite row) has influence on the effect.
Also notice that a Sprite only ends if the SpritePositionByte would be $3f, otherwise the Sprite warps over and starts at $00 or $01 again.
1/ SPB of the actual SCR line
2/ Diff to the normal step
3/ SPB of the next line
00: +2 01 01: -1 05 02: impossible
03: -1 07 04: +2 05 05: +3 05
06: +4 05
09: -1
0c: ...
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment