bson@rice-chex.ai.mit.edu (Jan Brittenson) (11/16/90)
OK, here's my sprite drawer if you're interested. First a warning:
this program will happily scramble your memory if given improper
arguments. This generally means, but is not limited to, specifying
coordinates outside the GROB.
I will post the source code only. It is copyrighted by me, but you
are hereby granted the right to use it for whatever non-commercial
purposes you desire. For other purposes, consult me. Of course no
responsibility or liability is taken. You're on your own here, should
your beloved HP go down in flames, or you end up requiring life-long
psychiatric care.
SPRITE
The sprite drawer initially reads four arguments off the stack:
4: destination.grob
3: row.short
2: col.short
1: sprite.string
The row (Y) and column (X) are read into the Y and X registers, and
the IP is set to the first nibble of the string, where execution will
begin.
The drawer maintains the following of registers:
reg bits description
X 12 - current column (0 is leftmost) 0-#fff
Y 12 - current row (0 is uppermost) 0-#fff
A 4 - angle 0-15
C 20 - collision counter 0-#fffff
G 3 - current GROP, graphical operator, 0,1,2,4
F 3 - flags F.C, F.PP, F.PC
IP 20 - current sprite address
[Initial values: A=0, C=0, F.*=0, G=1]
The F register is divided into three bits:
F.C - collision detection off/on (0/1)
F.PP - push point on stack when done off/on (0/1)
F.PC - push collision counter on stack when done off/on (0/1)
The A register contains the angle offset. It consitutes an offset
added to all drawing and moving commands to deduct the effective
angle. The angle is one of 16:
5 3
6 4 2
7 \|/ 1
8- -0
9 /|\ f
a c e
b d
The odd angles are halfway between the even ones. The angle 5 is
halfway between 4 and 6 (112.5 degrees).
During execution the following commands make sense; all others are
ignored.
opcode mnemonic decriptions
1g G=g Set GROP to g: 1=BIS, 2=XOR, 4=BIC
2 F.C=1 Enable collision detection
3 F.C=0 Disable collision detection
4na MOVE n,a Move n (1-15) pixels, angle a
Enna MOVE nn,a Move nn (1-255) pixels, angle a
7a DRAW 1,a Draw 1 pixel, angle a
8na DRAW n,a Draw n (1-15) pixels, angle a
Dnna DRAW nn,a Draw nn (1-255) pixels, angle a
B SETPT Set pixel at current X,Y
90 F.PC=1 Push collision counter when done
91 F.PP=1 Push Y,X when done
92 POP XY Pop new X,Y off stack
93 POP A Pop new A off stack
c END
The drawing and moving commands start at the current point, and
move the specified number of pixels in the specified direction. The
drawing commands set the pre-draw current point, and end up with the
current point set to the first pixel following the last pixel set. In
other words, the command DRAW 3,2 (822) will do the following:
O 4: move one pixel and leave the point
/
* 3: move one pixel and set the point
/
* 2: move one pixel and set the point
/
* 1: set the current point
The pixel is set according to the current GROP (G register). The
same is true for SETPT as well, which simply sets the current point
without moving. If collision detection is enabled, the point is tested
and the collision counter updated before any graphical operation is
applied. When drawing, collision is checked for the first and up to
but not including the final point (i.e. 1-3 would be checked in the
example above). SETPT always checks for collision detection if
enabled.
I hope this brief explanation is sufficient.
O /
\/
/\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
O \
;; +
;; SPRITE -- HP-48 sprite drawer
;;
;;
;; In:
;; 4:dest.grob
;; 3:row.short
;; 2:col.short
;; 1:sprite.string
;;
;; Out:
;; any or none
;;
;;
;; Register usage:
;;
;; d1 - current GROB address
;; d0 - current sprite address
;; r0.x - GROB cols (X max + 1)
;; r1.x - GROB rows (Y max + 1)
;; r3.x - current col (X), 0-#fff (0-4095)
;; r4.x - current row (Y), 0-#fff (0-4095)
;; r3.3 - rotational angle 0-15
;; b.s - current mask (1,2,4,8)
;; r3.4:8 - collision counter
;; r3.9 - current GROP:
;; 1 - OR
;; 2 - XOR
;; 4 - bic
;;
;; r3.13:15 - GROB row width, in nibbles
;;
;; d.s - current flags:
;; 0 - collision detection enabled
;; 1 - exit
;; 2 - push collision counter when done
;; 3 - push end point when done
;;
;; r2.a - relocation constant
;;
;;
;; bson@ai.mit.edu, Nov 8, 1990
;;
;; Copyright (c) 1990, Jan Brittenson
;;
;; 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. You may freely
;; use, modify, and redistribute it for any noncommercial purpose, given
;; that this notice is not removed or changed.
;;
;;
;;--
get2shorts=#3f5d
getshort=#6641
restore_regs=#67d2
save_regs=#679b
error_too_few_args=#18cc7
error_bad_arg_type=#18cb7
pushshort_r0=#6537
pushshort_r0r1=#6529
rplret=#71be
data.b 'H'
data.b 'P'
data.b 'H'
data.b 'P'
data.b '4'
data.b '8'
data.b '-'
data.b 'D'
data.a #2dcc
begin: data.a end-begin
sprite: call.3 reloc
reloc: pop.a c
move.w c,r2 ; R2 = logical reloc
move.a @d1,c
brnz.a c,L_1000
jump.3 sprite_insuff_args
L_1000: add.a 5,d1
inc.a d
swap.a c,d1
push.a c
move.a @d1,a
move.p5 #2a2c,c ; String
breq.a c,a,L_1001
jump.3 sprite_bad_argtype
L_1001: add.a 10,d1 ; Skip type and length
pop.a c
swap.a c,d1
push.a c ; Push string addr
call.3 pop_xy ; Get row, col from stack
move.a @d1,c
brnz.a c,L_1002
jump.3 sprite_insuff_args
L_1002: add.a 5,d1
inc.a d
swap.a c,d1
push.a c
move.a @d1,a
move.p5 #2b1e,c ; GROB
breq.a c,a,L_1003
jump.3 sprite_bad_argtype
L_1003: add.a 10,d1
move.a @d1,a ; Get GROB height
move.w a,r1 ; R1.x = GROB height
add.a 5,d1
move.a @d1,a ; Get GROB width
move.w a,r0 ; R0.x = GROB width
pop.a c
swap.a c,d1
push.a c
call.a save_regs
pop.a c
move.a c,d1
add.a 5,d1 ; D1 = GROB data
pop.a c
move.a c,d0 ; D0 = string address
call.3 sprite_init ; Initialize reentrant variables
; Main loop
sprite_main:
call.3 sprite_exec1 ; Execute one command
rln.w d
move.p d,c
rrn.w d
brbc 1,c,sprite_main
; Exit
move.s d,c
move.w c,r0
call.a restore_regs
move.w r0,c
rln.w c
push.a c
move.a c,a
brbc 3,a,L_301 ; Don't push final point
clr.a c
move.x r4,c
move.w c,r0
move.x r3,c
move.w c,r1
call.a pushshort_r0r1 ; Push in order: row, col
L_301:
pop.a c
move.a c,a
brbc 2,a,L_300 ; Don't push collision counter
move.w r3,c
rrn.w c
rrn.w c
rrn.w c
rrn.w c
move.w c,r0
call.a pushshort_r0 ; Push: coll count
L_300:
jump.a rplret
; Various error messages
sprite_bad_argtype:
jump.a error_bad_arg_type
sprite_insuff_args:
jump.a error_too_few_args
; Get X and Y from stack
pop_xy:
call.a get2shorts ; C=lev1.short, A=lev2.short
move.x a,r3 ; R3.x = cur row
move.x c,r4 ; R4.x = cur col
ret
; Reset to default values, except for variables from stack.
sprite_init:
move.w r2,a
move.p5 grob_base,c
add.a a,c
swap.a c,d1
move.a c,@d1 ; Save GROB addr in grob_base
swap.a c,d1
move.w r3,a ; Angle, coll ctr, GROP, all = 0
clr.w c
or.x a,c
move.w r0,a ; A.x = GROB cols
brbs 0,a,L_1 ; Not a byte
brbs 1,a,L_1 ; Not a byte
brbc 2,a,L_2 ; A byte
L_1:
add.x 8,a ; Adjust to next byte
L_2:
srb.x a ; Turn into nibble count
srb.x a
clrb 0,a ; Always even # of nibbles
rrn.w a ; Move into nibbles 13,14,15
rrn.w a
rrn.w a
move.1 13,p
or.p a,c
inc.1 p
or.p a,c
inc.1 p
or.p a,c
move.w c,r3
move.1 0,p
move.w r4,a ; A.x = row#, C.x = col#
call.3 sprite_mapxy ; C.a = addr, A.0 = mask
rrn.w a
move.s a,b ; B.s = cur mask
swap.a a,d1
add.a c,a
swap.a a,d1 ; D1 = cur addr
move.p1 1,c ; Default GROP = OR
call.3 set_grop
clr.s d ; No flags enabled
ret
; Map row (A.x) and col (C.x) to nibble offset and mask.
; Set C.a to addr, and A.1 to mask.
sprite_mapxy:
push.a c
move.x a,c
move.x c,d ; D.x = row #
move.w r3,c
clr.b c
rln.w c
rln.w c
rln.w c ; C.a = row size in nibbles
clr.a b
brz.x d,L_4
L_3:
add.a c,b
dec.x d
brnz.x d,L_3
L_4:
pop.a c
clr.a d
move.x c,d ; D.a = col #
srb.x d
srb.x d ; D.a = nibble #
swap.a c,d
add.a c,b ; B.a = addr
swap.a c,d
clrb 2,c
clrb 3,c
move.p c,d ; D.a = col #
clr.a a
inc.a a ; A.a = 1
brz.p d,L_5
L_6:
add.a a,a
dec.p d
brz.p d,L_6
L_5:
move.a b,c ; C.a = nibble #
ret
; Set current pixel
spr_x_setpix:
call.3 get_grop ; C.0 = GROP
move.s d,c ; C.1 = GROP, C.0 = run flags
rln.w c
brbc 0,c,L_428 ; No collision detection - skip
move.s @d1,c ; C.15 = Current GROB nibble
and.s b,c ; Test if collision
brz.s c,L_428 ; Nope - skip
move.w r3,a
rrn.w a
rrn.w a
rrn.w a
rrn.w a
inc.x a ; Yep - increment counter
rln.w a
rln.w a
rln.w a
rln.w a
move.w a,r3
L_428:
move.s @d1,c ; C.15 = Current GROB nibble
brbc 4,c,L_4281 ; GROP != OR
or.s b,c ; C.15 = old OR mask
brcc L_4299
L_4281: brbc 5,c,L_4282 ; GROP != XOR
move.s b,a
not.s a
and.s c,a ; A.s = !B.s & C.s
not.s c
and.s b,c ; C.s = B.s & !C.s
or.s a,c ; C.s = !B.s & C.s | B.s & !C.s
brcc L_4299
L_4282: brbc 6,c,L_42991 ; GROP != BIC
move.s b,a
not.s a ; A.s = !mask
and.s a,c ; C.s = !mask & C.s
L_4299:
move.s c,@d1 ; Write back
L_42991:
ret
; Execute one sprite command
sprite_exec1:
clr.a a
move.p @d0,a ; A.a = nibble
add.a 1,d0
move.p5 sprite_exec_table,c
; Jump indirect table.
; A.a = entry#, C = table offset
spr_exec:
move.a c,b
move.w r2,c ; C.a = reloc
add.a b,c ; C.a = addr
move.a a,b ; B=entry#
add.a a,a
add.a a,a ; A *= 4
add.a b,a ; A *= (4+1)
add.a c,a ; A = table addr
swap.a a,d0
move.a @d0,c
swap.a a,d0
move.a c,b ; B = code offset
move.w r2,c
add.a b,c ; C = code addr
jump.a c
; END - terminate
spr_x_end:
rln.w d ; Get flag word
move.p d,c
setb 1,c ; Set bit #1
move.p c,d
rrn.w d
; NOP - no operation
spr_x_nop:
ret
; ENA COLL - enable collision detection
spr_x_ena_coll:
rln.w d ; Get flag word
move.p d,c
setb 0,c ; Set bit 0
L_8:
move.p c,d
rrn.w d
ret
; DIS COLL - disable collision detection
spr_x_dis_coll:
rln.w d ; Get flag word
move.p d,c
clrb 0,c ; Clear bit 0
brnz.s b,L_8
; PUSH/POP - various PUSH/POP commands
spr_x_push:
clr.a a
move.1 @d0,a ; Next nibble
add.a 1,d0
move.p5 push_table,c
jump.3 spr_exec ; Jump indirect
; PUSH COLL - push collision count when done
spr_x_push_coll:
setb 2,c ; Set bit 2
brnz.p c,L_8
; PUSH POINT - push last point when done
spr_x_push_pt:
setb 3,c ; Set bit 3
brnz.p c,L_8
; POP XY - Get new X and Y coordinates from stack
spr_x_pop_xy:
call.3 swap_regs
call.3 pop_xy ; Pop row, col off stack
call.3 swap_regs
move.w r3,c ; C.x = col #
move.w r4,a ; A.x = row #
call.3 sprite_mapxy ; C.a = addr, A.0 = mask
rrn.w a
move.s a,b ; B.s = new mask
push.a c ; Save GROB offset
move.w r2,a ; A.a = reloc
move.p5 grob_base,c
add.a c,a ; C.a = &grob_base
swap.a a,d1
move.a @d1,a ; A.a = grob_base
pop.a c
add.a c,a ; A.a = grob_base + new offset
move.a a,d1 ; D1 = new GROB address
ret
; POP ANGLE - Get new rotation from stack
spr_x_pop_rot:
call.3 swap_regs
call.a getshort ; A.a = angle
call.3 swap_regs
move.1 3,p
rln.w a
rln.w a
rln.w a ; A.3 = angle
move.p a,r3 ; R3.3 = angle
move.1 0,p
ret
; MOVE n,m - move n (0-15) pixels, angle m
spr_x_move:
call.3 get_grop ; C.0 = GROP
move.s d,c ; C.0 = run flags, C.1 = GROP
rln.w c
push.a c
clrb 0,c ; Disable collision detection
rrn.w c
move.s c,d
clr.p c
call.3 set_grop ; GROP = 0
call.3 spr_x_drawn ; Draw with null GROP
pop.a c ; C.1 = GROP, C.0 = run flags
rrn.w c
move.s c,d ; Restore run flags
jump.3 set_grop ; Restore GROP
; MOVE nn,m - move nn (0-255) pixels, angle m
spr_x_movenn:
call.3 get_grop ; C.0 = GROP
move.s d,c ; C.0 = run flags, C.1 = GROP
rln.w c
push.a c
clrb 0,c ; Disable collision detection
rrn.w c
move.s c,d
clr.p c
call.3 set_grop ; GROP = 0
call.3 spr_x_drawnn ; Draw with null GROP
pop.a c ; C.1 = GROP, C.0 = run flags
rrn.w c
move.s c,d ; Restore run flags
jump.3 set_grop ; Restore GROP
; Adjust row and column according to row/col increments.
; Row: A.x, Col: C.x, Adjustment: B.x, Increments: A.3:4
; Uses: D.x
adjrowcol:
swap.a c,a
move.x c,d
swap.a c,a
swap.a c,b
push.a c
swap.a b,c
rrn.w a
brbc 12,a,L_222 ; Row is not half-angle
srb.x b ; Row is half-angle
L_222: brbc 8,a,L_20 ; No row movement, adjust col
brbs 9,a,L_21 ; Moving up
neg.x b ; Up: use negative offset
L_21: swap.a c,d
add.x b,c ; Down: add to row number
swap.a c,d
L_20:
swap.a c,b
pop.a c
push.a c
swap.a c,b
brbc 14,a,L_223 ; Col is not half-angle
srb.x b ; Col is half-angle
L_223: brbc 10,a,L_221 ; No col adjustment
brbc 11,a,L_23 ; Moving left
neg.x b ; Left: use negative col offset
L_23: add.x b,c ; Right: add to col #
L_221:
swap.a c,b
pop.a c
swap.a c,b
rln.w a
swap.a c,d
move.x c,a
swap.a c,d
ret
; Fetch nibble and add to rotational angle.
; Map to incrementation bits, and store them in A.3:4
; Clears A.x and wrecks C.w
spr_fetch_angle:
move.1 0,p
clr.a a
move.1 @d0,a ; A.a = angle
add.a 1,d0
move.w r3,c ; C.3 = rotation
srn.a c
srn.a c
srn.a c
add.p c,a
add.a a,a ; Nibbles to bytes
move.w r2,c
add.a c,a
move.p5 angle_table,c
add.a a,c ; C.a = byte pointer
swap.a c,d0
move.b @d0,a ; A.b = angle bits
swap.a c,d0
sln.w a
sln.w a
sln.w a ; A.3:4 = angle bits
ret
; GROP - set GROP
spr_x_grop:
move.1 9,p
move.w r3,a
move.p @d0,a ; A.9 = nibble
move.p1 3,c ; C.9 = 3
and.p c,a ; Mask low 2 bits
move.w a,r3
move.1 0,p
ret
; General GROP = C.0
; Trashes C.9
set_grop:
move.1 c,0,p ; P = C.0
move.1 p,c,9 ; C.9 = P
move.1 9,p
move.p c,r3 ; R3.9 = GROP
move.1 0,p
ret
; General C.0 = GROP
; Trashes C.9
get_grop:
move.1 9,p
move.p r3,c ; C.9 = GROP
move.1 c,9,p ; P = C.9
move.1 p,c,0 ; C.0 = P
move.1 0,p
ret
; DRAW nn,m - draw nn pixels long sprite
spr_x_drawnn:
clr.x c
move.b @d0,c
add.a 2,d0
move.x c,b ; B.x = C.x = sprite length
brcc spr_x_draw_b
; DRAW1 - draw 1-pixel sprite
spr_x_draw1:
move.p1 1,c ; One pixel long
brnz.p c,spr_x_draw_main ; Go draw
; DRAWN - draw n-pixel sprite
spr_x_drawn:
move.1 @d0,c ; # of pixels of length
add.a 1,d0
; Draw sprite of length C.1. Get nibble indicating angle and
; add basic rotation. In the draw loop, registers are
; used as follows:
;
; B.x - length (1-10h)
; D.a - row width, in nibbles (from R3.13:15)
; A.x - collision counter
; A.3 - increment flags
; 12 - row movement on/off (0/1)
; 13 - row movement up/down (0/1)
; 14 - col movement on/off (0/1)
; 15 - col movement left/right (0/1)
; C.0 - D.s run flags
; C.1 - GROP
; C.2 - half-angle increment flags
; 8 - row is half-angle
; 9 - row half-angle toggle
; 10 - col is half-angle
; 11 - col half-angle toggle
;
; The rest of the registers are used in their global role. E.g.
; B.s is the current mask.
;
spr_x_draw_main:
move.1 0,p
clr.x b
move.p c,b ; B.x = # of pixels
; Alternative entry, B.x = sprite length
spr_x_draw_b:
call.3 spr_fetch_angle ; A.3:4 = angle bits, A.x = 0
move.w r3,c ; C.x = col number
move.x r4,a ; A.x = row number
call.3 adjrowcol ; Adjust C.x,A.x by B.x, via A.3:4
move.x c,r3 ; Update col
move.x a,r4 ; Update row
move.w r3,c
rrn.w c
rrn.w c
rrn.w c
rrn.w c
move.x c,a ; A.x = collision counter
move.w r3,c
clr.b c
rln.w c
rln.w c
rln.w c
move.a c,d ; D.a = width, in nibbles
brbs 13,a,L_311 ; Moving down, if any
neg.a d ; Use negative row width if up
L_311:
call.3 get_grop ; C.0 = GROP
move.s d,c
rln.w c ; C.0 = run flags, C.1 = GROP
swap.a c,a
move.1 c,4,p
swap.a c,a
move.1 p,c,2 ; C.xs = A.4 = half-angle flags
move.1 0,p
; Main draw loop.
; Alter pixel, move, and iterate.
sprite_draw:
brbc 0,c,L_28 ; No collision detection - skip
move.s @d1,c ; C.15 = Current GROB nibble
and.s b,c ; Test if collision
brz.s c,L_28 ; Nope - skip
inc.x a ; Yep - increment counter
L_28:
move.s @d1,c ; C.15 = Current GROB nibble
brbc 4,c,L_281 ; GROP != OR
or.s b,c ; C.15 = old OR mask
brcc L_299
L_281: brbc 5,c,L_282 ; GROP != XOR
move.s b,a
not.s a
and.s c,a ; A.s = !B.s & C.s
not.s c
and.s b,c ; C.s = B.s & !C.s
or.s a,c ; C.s = !B.s & C.s | B.s & !C.s
brcc L_299
L_282: brbc 6,c,L_2991 ; GROP != BIC
move.s b,a
not.s a ; A.s = !mask
and.s a,c ; C.s = !mask & C.s
L_299:
move.s c,@d1 ; Write back
L_2991:
brbc 12,a,L_30 ; No row movement - move col
brbc 8,c,L_100 ; Row is not half-angle, simply add
brbs 9,c,L_101 ; Move and clear toggle
setb 9,c ; Move next time around
brcc L_30 ; Move col
L_101: clrb 9,c
L_100: swap.a c,d1
add.a d,c ; Add one row up or down
swap.a c,d1
L_30:
brbc 14,a,L_32 ; No col movement - continue
brbc 10,c,L_102 ; Col is not half-angle
brbs 11,c,L_103 ; Move and clear toggle
setb 11,c ; Move col next time around
brcc L_32 ; Iterate
L_103: clrb 11,c ; Don't move col next time around
L_102: brbc 15,a,L_33 ; Moving left
add.s b,b ; Moving right - shift mask left
brnz.s b,L_32 ; Still within nibble - continue
add.a 1,d1 ; Outside - next nibble
inc.s b ; Set mask to 1
brnz.s b,L_32 ; Continue
L_33:
srb.s b ; Moving left - shift mask right
brnz.s b,L_32 ; Still within nibble - continue
inc.s b ; Set mask to 1
add.s b,b ; ...2
add.s b,b ; ...4
add.s b,b ; ...8
sub.a 1,d1 ; And move to prev nibble
L_32:
dec.x b ; Decrement pixel counter
brz.x b,L_35
jump.3 sprite_draw ; Continue drawing
; Restore/update global registers and return
L_35:
move.1 3,p ; Zero extend coll ctr to 5 nibbles
clr.p a
inc.1 p
clr.p a
move.w r3,c
rrn.w c
rrn.w c
rrn.w c
rrn.w c
clr.a c
or.a a,c
rln.w c
rln.w c
rln.w c
rln.w c
move.w c,r3 ; R3.4:8 = collision counter
move.1 0,p
ret
; Swap registers with their saved contents.
; Wrecks C.a.
TOH=#705b0
TOS=#70579
FP=#70574
Free_size=#7066e
swap_regs:
move.a a,c
push.a c
swap.a c,d0
move.5 TOH,d0
move.a @d0,a
move.a c,@d0
move.5 TOS,d0
move.a @d0,c
swap.a c,d1
move.a c,@d0
move.5 FP,d0
move.a @d0,c
swap.a c,b
move.a c,@d0
move.5 Free_size,d0
move.a @d0,c
swap.a d,c
move.a c,@d0
move.a a,d0
pop.a c
move.a c,a
ret
; Jump table for first nibble
sprite_exect:
sprite_exec_table=sprite_exect-reloc
data.a spr_x_nop-reloc
data.a spr_x_grop-reloc
data.a spr_x_ena_coll-reloc
data.a spr_x_dis_coll-reloc
data.a spr_x_move-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_draw1-reloc
data.a spr_x_drawn-reloc
data.a spr_x_push-reloc
data.a spr_x_nop-reloc
data.a spr_x_setpix-reloc
data.a spr_x_end-reloc
data.a spr_x_drawnn-reloc
data.a spr_x_movenn-reloc
data.a spr_x_nop-reloc
; Jump table for second nibble of 9x group (PUSH/POP)
sprite_pusht:
push_table=sprite_pusht-reloc
data.a spr_x_push_coll-reloc
data.a spr_x_push_pt-reloc
data.a spr_x_pop_xy-reloc
data.a spr_x_pop_rot-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
data.a spr_x_nop-reloc
; Sprite angle-to-incrementation map.
; The angle entries are bit maps interpreted as follows:
;
; 0a0bcdef
;
; Where
; a = Column is half-angle
; b = Row is half-angle
; c = Left/right
; d = Column movement off/on
; e = Up/down
; f = Row movement off/on
;
sprite_anglet:
angle_table=sprite_anglet-reloc
data.2 #0c ; 0 (0)
data.2 #1d ; 1 (22.5)
data.2 #0d ; 2 (45)
data.2 #4d ; 3 (67.5)
data.2 #01 ; 4 (90)
data.2 #45 ; 5 (112.5)
data.2 #05 ; 6 (135)
data.2 #15 ; 7 (157.5)
data.2 #04 ; 8 (180)
data.2 #17 ; 9 (202.5)
data.2 #07 ; a (225)
data.2 #47 ; b (247.5)
data.2 #03 ; c (270)
data.2 #4f ; d (292.5)
data.2 #0f ; e (315)
data.2 #1f ; f (337.5)
; Various variables
grob_basev:
grob_base=grob_basev-reloc
data.a 0 ; GROB base address
end: