Skip to content
Game 1Unit 10 of 181 hr learning time

Keeping Score

The HUD strip's second job: +5 for surviving the road, +25 for a sheep safely home — one binary word, peeled into decimal digits with DIVU and stamped in a glyph font.

56% of Flock

Safe arrivals deserve counting.

Two events now pay out: the first time each sheep puts the whole road behind her, +5; a sheep safely penned, +25. The total sits at the right end of the HUD strip in four white digits — and between the number and the screen lie two small, permanent lessons: how a binary word becomes decimal digits, and how a font is nothing but a table of glyphs.

The Display

Flock Unit 10

0030 — one road survived, one sheep home. The same scripted run as Unit 9’s capture, now with a paper trail.

Peeling Digits

The score lives as one binary wordadd.w #PEN_POINTS,score and arithmetic stays plain addition. The display is decimal, and the bridge between them is the 68000’s DIVU:

drawscore:
            move.w  score,d7            ; D7 = what's left to convert
            moveq   #38,d5              ; Rightmost digit's byte column
            moveq   #4-1,d6             ; Four digits
.digit:
            moveq   #0,d0
            move.w  d7,d0
            divu    #10,d0              ; Quotient low, remainder high
            move.l  d0,d1
            swap    d1                  ; D1 = this digit (0-9)
            move.w  d0,d7               ; D7 = the rest
            ; Find the digit's glyph: font + digit*8
            lea     digitfont,a2
            add.w   d1,d1
            add.w   d1,d1
            add.w   d1,d1               ; digit * 8
            adda.w  d1,a2
            move.w  d5,d0               ; Byte column
            move.w  #ROW_HUD+4,d1
            bsr     drawglyph
            subq.w  #1,d5               ; Next digit to the left
            dbf     d6,.digit
            rts

DIVU #10 divides and hands back both halves in one register — quotient in the low word, remainder in the high. The remainder is the rightmost digit; the quotient is what’s left to convert. Four passes, stamped right to left, and the binary word reads as decimal. (The swap is the idiomatic 68000 move for reaching a result’s high word — you’ll use it constantly.)

The digits themselves are drawglyph again — the same byte-per-row stamp the flock icons use. digitfont is ten glyphs end to end, and digit × 8 indexes straight into it: a font is a table, a character is an offset, and text is a loop. Every HUD, menu and title screen you’ll ever build on this machine is that sentence scaled up.

Paying Out

Where the points land says what the game values:

  • The road bonus lives in steer, on a completed hop: the first time a sheep’s y clears the bank line, roadflag goes up and 5 points land. The flag resets when the next sheep steps up — penned or squashed, her successor’s road is still ahead of her. One flag per life, the cheapest possible “once per sheep”.
  • The pen bonus lives in trypen, beside the resident glyph — 25 points at the moment of arrival.

Both call drawscore immediately. Same discipline as the flock strip: the display is a function of the number, redrawn whole at the moment of change. Nobody ever wonders whether the screen is stale.

Experiment: The Economy of a Farmyard

  • Rebalance: ROAD_POINTS equ 20, PEN_POINTS equ 5. Now the game rewards daring over finishing. Play a level and feel your own behaviour shift — scoring is a steering wheel for the player.
  • Pay the road bonus every crossing of the bank line (drop the flag). She can now farm points by shuttling. Watch how fast a kind rule becomes an exploit.
  • Five digits: widen the loop and the columns. What’s the biggest score the word can hold, and what happens just past it?
  • Stamp SCORE as a label — five more glyphs in the table, letters this time. (You now own a font pipeline. It cost one table and zero new routines.)

The Complete Code

;──────────────────────────────────────────────────────────────
; FLOCK - A sheep-crossing arcade game for the Commodore Amiga
; Unit 10: Keeping Score
;
; The HUD strip earns its second job. Safe arrivals score:
; +5 for surviving the road, +25 for reaching a pen — kept as
; one binary word, converted to four decimal digits with DIVU,
; and stamped into the strip with a glyph font. The display
; is a function of the number, redrawn whole, same as the
; flock icons.
;──────────────────────────────────────────────────────────────

;══════════════════════════════════════════════════════════════
; TWEAKABLE VALUES — Change these and see what happens!
;══════════════════════════════════════════════════════════════

; Colours are $0RGB (4 bits per component, values 0-F)
COLOUR_FOLD_GRASS   equ $0480       ; The fold's pasture
COLOUR_HEDGE        equ $0350       ; Hedgerow between fold and stream
COLOUR_WATER        equ $036A       ; The stream
COLOUR_BANK         equ $0350       ; Grassy bank below the stream
COLOUR_LANE         equ $0666       ; The lane's tarmac
COLOUR_VERGE        equ $0350       ; Verge below the lane
COLOUR_FIELD        equ $0470       ; The field where the flock waits

COLOUR_FENCE        equ $0531       ; Pen walls (bitplane, fold band)
COLOUR_WOOD         equ $0852       ; The footbridge (bitplane, stream band)
COLOUR_DASH         equ $0EEE       ; Lane markings (bitplane, lane band)
COLOUR_TUFT         equ $0360       ; Spare (bitplane, grass bands)

COLOUR_WOOL         equ $0EEE       ; The sheep's fleece (sprite colour 1)
COLOUR_FACE         equ $0210       ; Her face, ears and tail (sprite colour 2)
COLOUR_SHADE        equ $0BBB       ; Fleece shading (sprite colour 3)

COLOUR_TRACTOR      equ $0B20       ; The tractor's bodywork (sprite colour 1)
COLOUR_TYRE         equ $0210       ; Wheels and trim (sprite colour 2)
COLOUR_CAB          equ $0999       ; The cab roof (sprite colour 3)

COLOUR_WOODWORK     equ $0742       ; The hay cart's bed (sprites 4-5)
COLOUR_HAY          equ $0C92       ; Its heaped load

COLOUR_ROVER        equ $0364       ; The Land Rover's paint (sprites 6-7)
COLOUR_ROOF         equ $0AAA       ; Its roof panel

; Where each band begins (screen row 0-255, top to bottom)
ROW_HEDGE           equ 40
ROW_STREAM          equ 48
ROW_BANK            equ 80
ROW_LANE            equ 96
ROW_VERGE           equ 160
ROW_FIELD           equ 176

; Where the sheep starts, and how she moves
SHEEP_X             equ 152
SHEEP_Y             equ 200
STEP                equ 8           ; Pixels per hop
COOLDOWN            equ 6           ; Frames between hops

; The traffic: three lanes, three rhythms
TRACTOR_Y           equ 98          ; Top lane
TRACTOR_SPEED       equ 2           ; Steady, rightward
ROVER_Y             equ 120         ; Middle lane
ROVER_SPEED         equ -3          ; Fast, leftward
CART_Y              equ 142         ; Bottom lane — crossed first
CART_SPEED          equ -1          ; Plodding, leftward

; How long the world stops when a sheep is lost
SQUASH_BEAT         equ 25          ; Frames of stillness

; The flock
FLOCK_SIZE          equ 5           ; Sheep in hand at the start

; The fold's pens
PEN_ROW             equ 16          ; Where a resident sheep settles
FENCE_Y             equ 24          ; She stops here unless a pen is open
PEN_BEAT            equ 15          ; Frames of calm after a penning

; What things are worth
ROAD_POINTS         equ 5           ; Surviving the road (per sheep)
PEN_POINTS          equ 25          ; A sheep safely home
ROW_BANK_TOP        equ 88          ; Past here, the road is behind her

; The HUD strip at the foot of the screen
ROW_HUD             equ 240
COLOUR_HUD          equ $0231       ; The strip itself
COLOUR_ICON         equ $0EEE       ; Sheep icons (bitplane, HUD band)

;══════════════════════════════════════════════════════════════
; HARDWARE REGISTERS
;══════════════════════════════════════════════════════════════

CUSTOM      equ $dff000

DMACON      equ $096        ; DMA control (write)
INTENA      equ $09a        ; Interrupt enable (write)
INTREQ      equ $09c        ; Interrupt request (write)
COP1LC      equ $080        ; Copper list pointer
COPJMP1     equ $088        ; Copper restart strobe
VPOSR       equ $004        ; Beam position
JOY1DAT     equ $00c        ; Joystick, control port 2
CLXDAT      equ $00e        ; Collision data (read clears it!)
CLXCON      equ $098        ; Collision control

BPLCON0     equ $100        ; Bitplane control
BPLCON1     equ $102        ; Scroll
BPLCON2     equ $104        ; Priority
BPL1MOD     equ $108        ; Odd plane modulo
DDFSTRT     equ $092        ; Display data fetch start
DDFSTOP     equ $094        ; Display data fetch stop
DIWSTRT     equ $08e        ; Display window start
DIWSTOP     equ $090        ; Display window stop
BPL1PTH     equ $0e0        ; Bitplane 1 pointer (high)
BPL1PTL     equ $0e2        ; Bitplane 1 pointer (low)
BPL2PTH     equ $0e4        ; Bitplane 2 pointer (high)
BPL2PTL     equ $0e6        ; Bitplane 2 pointer (low)
BPL2MOD     equ $10a        ; Even plane modulo
SPR0PTH     equ $120        ; Sprite 0 pointer (high)
COLOR00     equ $180        ; Background colour
COLOR01     equ $182        ; Bitplane colour 1
COLOR02     equ $184        ; Bitplane colour 2 (plane 2)
COLOR03     equ $186        ; Bitplane colour 3 (both planes)
COLOR17     equ $1a2        ; Sprite 0/1 colour 1
COLOR18     equ $1a4        ; Sprite 0/1 colour 2
COLOR19     equ $1a6        ; Sprite 0/1 colour 3
COLOR21     equ $1aa        ; Sprite 2/3 colour 1
COLOR22     equ $1ac        ; Sprite 2/3 colour 2
COLOR23     equ $1ae        ; Sprite 2/3 colour 3
COLOR25     equ $1b2        ; Sprite 4/5 colour 1
COLOR26     equ $1b4        ; Sprite 4/5 colour 2
COLOR27     equ $1b6        ; Sprite 4/5 colour 3
COLOR29     equ $1ba        ; Sprite 6/7 colour 1
COLOR30     equ $1bc        ; Sprite 6/7 colour 2
COLOR31     equ $1be        ; Sprite 6/7 colour 3

ROW_BYTES   equ 40          ; 320 pixels / 8

;══════════════════════════════════════════════════════════════
; CODE (Chip RAM — the Copper, planes and sprites live here)
;══════════════════════════════════════════════════════════════

            section code,code_c

start:
            lea     CUSTOM,a5           ; A5 = custom chip base ($DFF000)

            ; --- Take over the machine ---
            move.w  #$7fff,INTENA(a5)   ; Disable all interrupts
            move.w  #$7fff,INTREQ(a5)   ; Clear pending interrupts
            move.w  #$7fff,DMACON(a5)   ; Disable all DMA

            ; --- Point the Copper's bitplane MOVEs at our planes ---
            lea     copbpl,a1
            lea     plane,a0
            move.l  a0,d0
            move.w  d0,6(a1)            ; Low word into the BPL1PTL move
            swap    d0
            move.w  d0,2(a1)            ; High word into the BPL1PTH move
            lea     plane2,a0
            move.l  a0,d0
            move.w  d0,14(a1)           ; And the same for plane 2
            swap    d0
            move.w  d0,10(a1)

            ; --- Point sprite 0 at the sheep, the rest at nothing ---
            lea     copsprites,a1       ; Eight pointer pairs in the list
            lea     sheep0,a0
            move.l  a0,d0
            move.w  d0,6(a1)            ; Sprite 0 low word
            swap    d0
            move.w  d0,2(a1)            ; Sprite 0 high word

            lea     nullspr,a0          ; Sprites 1-7: an empty sprite
            move.l  a0,d0
            moveq   #7-1,d6
.nulls:
            lea     8(a1),a1            ; Next pointer pair in the list
            move.w  d0,6(a1)
            swap    d0
            move.w  d0,2(a1)
            swap    d0
            dbf     d6,.nulls

            ; --- ...except the traffic: sprites 2, 4 and 6.
            ; Each vehicle gets the EVEN sprite of its own pair, so
            ; each lives in its own collision group: tractor in 2/3
            ; (bit 9 against the sheep), cart in 4/5 (bit 10),
            ; Land Rover in 6/7 (bit 11) — and its own palette.
            lea     copsprites+16,a1    ; Sprite 2: the tractor
            lea     tractor,a0
            move.l  a0,d0
            move.w  d0,6(a1)
            swap    d0
            move.w  d0,2(a1)
            lea     copsprites+32,a1    ; Sprite 4: the hay cart
            lea     cart,a0
            move.l  a0,d0
            move.w  d0,6(a1)
            swap    d0
            move.w  d0,2(a1)
            lea     copsprites+48,a1    ; Sprite 6: the Land Rover
            lea     rover,a0
            move.l  a0,d0
            move.w  d0,6(a1)
            swap    d0
            move.w  d0,2(a1)


            ; --- Arm collision detection ---
            move.w  #$0000,CLXCON(a5)   ; Even sprites always take part;
                                        ;   we need nothing extra for 0-vs-2
            move.w  CLXDAT(a5),d0       ; Prime: reading clears the latches

            ; --- Draw the farmyard's detail into the bitplane ---
            bsr     drawfarmyard
            bsr     drawflock           ; The flock in hand, bottom-left
            bsr     drawscore           ; And the score, bottom-right

            ; --- Place the sheep at her starting spot ---
            bsr     updsprite

            ; --- Install Copper list ---
            lea     copperlist,a0
            move.l  a0,COP1LC(a5)
            move.w  d0,COPJMP1(a5)      ; Strobe: restart Copper from COP1LC

            ; --- Enable DMA ---
            move.w  #$83a0,DMACON(a5)   ; SET + DMAEN + BPLEN + COPEN + SPREN

            ; === Main Loop ===
mainloop:
            ; Wait for vertical blank — in two phases. If we only
            ; waited FOR line 0, a fast loop body could finish while
            ; the beam is still ON line 0 and run again in the same
            ; frame. Wait to leave line 0 first, then to reach it.
            move.l  #$1ff00,d1          ; Mask: bits 8-16 of beam position
.vbleave:
            move.l  VPOSR(a5),d0        ; Read beam position
            and.l   d1,d0               ; Isolate line number
            beq.s   .vbleave            ; Loop while still on line 0
.vbwait:
            move.l  VPOSR(a5),d0        ; Read beam position
            and.l   d1,d0               ; Isolate line number
            bne.s   .vbwait             ; Loop until line 0 again

            bsr     steer               ; Read the stick, maybe hop
            bsr     drivelanes          ; All the traffic, one mover
            bsr     checksquash         ; Did the lane win?
            bsr     updsprite           ; Position is data: rewrite POS/CTL
            bsr     showframe           ; Point sprite 0 at this step's image

            ; Check left mouse button (active low at CIAA)
            btst    #6,$bfe001          ; CIAA Port A, bit 6
            bne.s   mainloop            ; Not pressed — keep going

            ; Button pressed — halt
.halt:
            bra.s   .halt

;══════════════════════════════════════════════════════════════
; STEER — read the joystick, hop the sheep
;
; JOY1DAT is control port 2. The decode is famously sideways:
;   right = bit 1            left = bit 9
;   down  = bit 0 XOR bit 1  up   = bit 8 XOR bit 9
; One XOR of the register with itself-shifted turns the two
; awkward pairs into plain testable bits.
;
; A hop is STEP pixels; COOLDOWN frames must pass between hops
; — that's what makes her *step* like a sheep rather than glide
; like a cursor.
;══════════════════════════════════════════════════════════════

steer:
            tst.w   won                 ; Fold full — nothing to steer
            bne.s   .frozen
            tst.w   gameover            ; No flock, no shepherd
            bne.s   .frozen
            tst.w   squashtimer         ; Mid squash-beat? She can't move
            beq.s   .alive
.frozen:    rts
.alive:
            tst.w   cooldown
            beq.s   .ready
            subq.w  #1,cooldown         ; Still mid-hop rhythm — wait
            rts
.ready:
            move.w  JOY1DAT(a5),d0      ; Read the stick
            move.w  d0,d1
            lsr.w   #1,d1
            eor.w   d0,d1               ; Now: bit 0 = down, bit 8 = up

            btst    #8,d1               ; Up?
            beq.s   .notup
            cmp.w   #FENCE_Y,sheepy     ; At the fence line?
            bgt.s   .climb
            bsr     trypen              ; Only a pen lets her past
            bra     .done
.climb:
            sub.w   #STEP,sheepy
            bra.s   .stepped
.notup:
            btst    #0,d1               ; Down?
            beq.s   .notdown
            add.w   #STEP,sheepy
            bra.s   .stepped
.notdown:
            btst    #9,d0               ; Left?
            beq.s   .notleft
            sub.w   #STEP,sheepx
            bra.s   .stepped
.notleft:
            btst    #1,d0               ; Right?
            beq.s   .done               ; Stick centred — no hop
            add.w   #STEP,sheepx
.stepped:
            move.w  #COOLDOWN,cooldown  ; Set the hop rhythm
            eori.w  #1,curframe         ; The other feet, next picture

            ; --- First time past the road? That's worth something.
            tst.w   roadflag
            bne.s   .scored
            cmp.w   #ROW_BANK_TOP,sheepy
            bgt.s   .scored
            move.w  #1,roadflag
            add.w   #ROAD_POINTS,score
            bsr     drawscore
.scored:

            ; --- Hold her inside the farm ---
            tst.w   sheepx
            bge.s   .xlow
            clr.w   sheepx
.xlow:      cmp.w   #320-16,sheepx
            ble.s   .xhigh
            move.w  #320-16,sheepx
.xhigh:     cmp.w   #FENCE_Y,sheepy     ; The fence is the ceiling;
            bge.s   .ylow               ;   pens are the only way past
            move.w  #FENCE_Y,sheepy
.ylow:      cmp.w   #ROW_HUD-16,sheepy  ; The HUD strip is not a pasture
            ble.s   .done
            move.w  #ROW_HUD-16,sheepy
.done:
            rts

;══════════════════════════════════════════════════════════════
; DRIVELANES — advance all the traffic
;
; Unit 5's mover, made data. Each vehicle is a row in vehtab —
; WHERE its x lives, and how fast it moves (signed: negative
; drives leftward). One loop walks the table: add the speed,
; wrap off whichever edge the speed points at, store. Adding a
; vehicle to the game is adding a row to the table.
;══════════════════════════════════════════════════════════════

drivelanes:
            lea     vehtab,a2
            moveq   #3-1,d6             ; Three vehicles
.veh:
            move.l  (a2)+,a0            ; A0 = where this one's x lives
            move.w  (a2)+,d1            ; D1 = its speed (signed)
            move.w  (a0),d0
            add.w   d1,d0
            tst.w   d1
            bmi.s   .leftward
            cmp.w   #320,d0             ; Rightward: clear of the right edge?
            blt.s   .store
            move.w  #-16,d0             ; Re-enter from the left
            bra.s   .store
.leftward:
            cmp.w   #-16,d0             ; Leftward: clear of the left edge?
            bgt.s   .store
            move.w  #320,d0             ; Re-enter from the right
.store:
            move.w  d0,(a0)
            dbf     d6,.veh
            rts

vehtab:     dc.l    tractx
            dc.w    TRACTOR_SPEED
            dc.l    cartx
            dc.w    CART_SPEED
            dc.l    roverx
            dc.w    ROVER_SPEED

;══════════════════════════════════════════════════════════════
; CHECKSQUASH — read the collision latches, judge the lane
;
; CLXDAT accumulates collisions as Denise draws, and READING
; IT CLEARS IT — so read it exactly once per frame and keep
; the copy. Bit 9 means "sprite 0 or 1 touched sprite 2 or 3":
; our sheep met our tractor, pixel against pixel. The hardware
; compared every overlapping pixel pair for us, for free.
;══════════════════════════════════════════════════════════════

checksquash:
            tst.w   squashtimer         ; Already mid-beat?
            beq.s   .watch
            subq.w  #1,squashtimer      ; Count the stillness down
            bne.s   .out
            move.w  CLXDAT(a5),d0       ; Beat over: flush the contact
.out:       rts                         ;   that accumulated during it
.watch:
            tst.w   gameover            ; Nothing left to lose?
            bne.s   .safe
            move.w  CLXDAT(a5),d0       ; Read once — this clears it
            and.w   #$0e00,d0           ; Bits 9/10/11: the sheep against
            beq.s   .safe               ;   ANY of the three vehicle groups
            ; --- Squashed. One fewer in hand. ---
            subq.w  #1,lives
            bsr     drawflock           ; Redraw the strip
            tst.w   lives
            bgt.s   .next               ; Sheep remain — send the next one
            move.w  #1,gameover         ; The field is empty
            rts
.next:
            move.w  #SHEEP_X,sheepx     ; The next sheep steps up
            move.w  #SHEEP_Y,sheepy
            clr.w   roadflag            ; A fresh road for the next one
            move.w  #SQUASH_BEAT,squashtimer
.safe:
            rts

;══════════════════════════════════════════════════════════════
; SETPOS — pack screen (x, y) into one sprite's POS/CTL
;   a0 = sprite structure   d0 = x   d1 = y
;
; Unit 3's packing, generalised: any sprite, any position. Beam
; coordinates: VSTART = y + $2C, HSTART = x + $80 — and the
; ninth bits ride in CTL's low flags.
;══════════════════════════════════════════════════════════════

setpos:
            add.w   #$2c,d1             ; D1 = VSTART (beam line)
            move.w  d1,d2
            add.w   #16,d2              ; D2 = VSTOP (16 rows tall)
            add.w   #$80,d0             ; D0 = HSTART (beam position)

            ; POS = VSTART[7:0] << 8 | HSTART[8:1]
            move.w  d1,d3
            lsl.w   #8,d3
            move.w  d0,d4
            lsr.w   #1,d4
            and.w   #$ff,d4
            or.w    d4,d3
            move.w  d3,(a0)             ; Write POS

            ; CTL = VSTOP[7:0] << 8 | V8START<<2 | V8STOP<<1 | H0START
            move.w  d2,d3
            and.w   #$ff,d3
            lsl.w   #8,d3
            btst    #8,d1               ; VSTART's ninth bit
            beq.s   .nv8s
            or.w    #%100,d3
.nv8s:      btst    #8,d2               ; VSTOP's ninth bit
            beq.s   .nv8e
            or.w    #%010,d3
.nv8e:      btst    #0,d0               ; HSTART's odd-pixel bit
            beq.s   .nh0
            or.w    #%001,d3
.nh0:       move.w  d3,2(a0)            ; Write CTL
            rts

;══════════════════════════════════════════════════════════════
; UPDSPRITE — place every sprite for this frame
;
; One routine owns every position write: the sheep (both step
; images, so whichever showframe picks she stands in the same
; place) and the tractor.
;══════════════════════════════════════════════════════════════

updsprite:
            lea     sheep0,a0
            move.w  sheepx,d0
            move.w  sheepy,d1
            bsr     setpos
            lea     sheep1,a0
            move.w  sheepx,d0
            move.w  sheepy,d1
            bsr     setpos
            lea     tractor,a0
            move.w  tractx,d0
            move.w  #TRACTOR_Y,d1
            bsr     setpos
            lea     cart,a0
            move.w  cartx,d0
            move.w  #CART_Y,d1
            bsr     setpos
            lea     rover,a0
            move.w  roverx,d0
            move.w  #ROVER_Y,d1
            bsr     setpos
            rts

;══════════════════════════════════════════════════════════════
; SHOWFRAME — point sprite 0 at this step's image
;
; Animation is nothing but choosing which data the channel
; fetches. The Copper list's sprite 0 pointer words are
; rewritten with whichever picture curframe names — the same
; poke the startup code did, now done every frame.
;══════════════════════════════════════════════════════════════

showframe:
            lea     nullspr,a0          ; Game over, or the whole flock
            tst.w   gameover            ;   home: no sheep on the move
            bne.s   .picked
            tst.w   won
            bne.s   .picked
            lea     sheep0,a0
            tst.w   curframe
            beq.s   .picked
            lea     sheep1,a0
.picked:
            move.l  a0,d0
            lea     copsprites,a1
            move.w  d0,6(a1)            ; Sprite 0 low word
            swap    d0
            move.w  d0,2(a1)            ; Sprite 0 high word
            rts

;══════════════════════════════════════════════════════════════
; DRAW THE FARMYARD (unchanged from Unit 1)
;══════════════════════════════════════════════════════════════

drawfarmyard:
            ; --- The fold's pens (rows 4-35) ---
            moveq   #0,d0               ; x = byte 0
            moveq   #4,d1               ; row 4
            moveq   #ROW_BYTES,d2       ; full width
            moveq   #4,d3               ; 4 rows thick
            bsr     rectfill

            lea     penposts,a2         ; Post positions (byte columns)
            moveq   #6-1,d6             ; Six posts
.posts:
            moveq   #0,d0
            move.b  (a2)+,d0            ; x = next post column
            moveq   #8,d1               ; rows 8-35
            moveq   #1,d2               ; one byte wide
            moveq   #28,d3
            bsr     rectfill
            dbf     d6,.posts

            ; --- The footbridge (rows 48-79, mid-stream) ---
            moveq   #18,d0              ; byte 18 = pixel 144
            moveq   #ROW_STREAM,d1
            moveq   #4,d2               ; 32 pixels wide
            moveq   #32,d3              ; the stream's full height
            bsr     rectfill

            ; --- Lane markings: two dashed lines (rows 116, 136) ---
            moveq   #116,d1
            bsr     dashline
            move.w  #136,d1
            ; falls through

;──────────────────────────────────────────────────────────────
; dashline — a row of dashes across the lane
;   d1 = starting row. 2 bytes on, 2 bytes off, 4 rows thick.
;──────────────────────────────────────────────────────────────
dashline:
            moveq   #0,d0               ; x = byte 0
.dash:
            move.w  d1,-(sp)            ; rectfill trashes d1
            move.w  d0,-(sp)            ; ...and d0
            moveq   #2,d2               ; 2 bytes of dash
            moveq   #4,d3               ; 4 rows thick
            bsr     rectfill
            move.w  (sp)+,d0
            move.w  (sp)+,d1
            addq.w  #4,d0               ; next dash 4 bytes along
            cmp.w   #ROW_BYTES,d0
            blt.s   .dash
            rts

;──────────────────────────────────────────────────────────────
; rectfill — set a byte-aligned rectangle of pixels
;   d0 = x (bytes)   d1 = row   d2 = width (bytes)   d3 = height
;   Trashes d1, d4, d5, a0, a1.
;──────────────────────────────────────────────────────────────
rectfill:
            lea     plane,a0
            move.w  d1,d4
            mulu    #ROW_BYTES,d4       ; row * 40
            add.w   d0,d4               ; + x
            adda.w  d4,a0               ; A0 = first byte of the rectangle
            move.w  d3,d4               ; D4 = rows to go
.row:
            movea.l a0,a1
            move.w  d2,d5               ; D5 = bytes to go
.col:
            move.b  #$ff,(a1)+          ; 8 pixels on
            subq.w  #1,d5
            bne.s   .col
            lea     ROW_BYTES(a0),a0    ; down one row
            subq.w  #1,d4
            bne.s   .row
            rts

penposts:   dc.b    0,8,16,24,32,39     ; Byte columns of the six posts
            even

;══════════════════════════════════════════════════════════════
; TRYPEN — at the fence, try to enter the pen she's facing
;
; Each pentab row is a pen: the span of sheep-centre x values
; it accepts, the byte column its resident glyph is drawn at,
; and a flag byte that remembers it's taken. A hit pens her:
; the resident appears (plane 2 — white among the brown
; fences), the next sheep steps up, and a full fold wins.
;══════════════════════════════════════════════════════════════

trypen:
            move.w  sheepx,d0
            addq.w  #8,d0               ; D0 = her centre
            lea     pentab,a2
            moveq   #5-1,d6
.pen:
            cmp.w   (a2),d0             ; Left of this pen?
            blt.s   .nextpen
            cmp.w   2(a2),d0            ; Right of it?
            bgt.s   .nextpen
            tst.b   5(a2)               ; Already taken?
            bne.s   .nextpen
            ; --- She's in. A resident for the fold. ---
            move.b  #1,5(a2)
            move.w  4(a2),d0            ; Glyph byte column
            and.w   #$ff00,d0
            lsr.w   #8,d0
            bsr     penglyph
            add.w   #PEN_POINTS,score   ; A sheep safely home
            bsr     drawscore
            move.w  #SHEEP_X,sheepx     ; The next sheep steps up
            move.w  #SHEEP_Y,sheepy
            clr.w   roadflag            ; Her road is still ahead of her
            move.w  #PEN_BEAT,squashtimer
            subq.w  #1,unpenned         ; A full fold wins
            bne.s   .out
            move.w  #1,won
.out:
            rts
.nextpen:
            addq.l  #6,a2
            dbf     d6,.pen
            rts                         ; Fence, post or a full pen: no way through

;──────────────────────────────────────────────────────────────
; penglyph — stamp the resident-sheep glyph into PLANE 2
;   d0 = x (bytes). Row is PEN_ROW; the glyph is the HUD icon.
;──────────────────────────────────────────────────────────────
penglyph:
            lea     plane2,a0
            move.w  #PEN_ROW,d4
            mulu    #ROW_BYTES,d4
            add.w   d0,d4
            adda.w  d4,a0
            lea     sheepicon,a2
            moveq   #8-1,d4
.row:
            move.b  (a2)+,(a0)
            lea     ROW_BYTES(a0),a0
            dbf     d4,.row
            rts

            ; Per pen: centre-x span (min, max), glyph byte
            ; column (high byte of the word), taken flag, pad
pentab:     dc.w    8,63
            dc.b    4,0
            even
            dc.w    72,127
            dc.b    12,0
            even
            dc.w    136,191
            dc.b    20,0
            even
            dc.w    200,255
            dc.b    28,0
            even
            dc.w    264,311
            dc.b    36,0
            even

;══════════════════════════════════════════════════════════════
; DRAWFLOCK — the sheep in hand, as icons on the HUD strip
;
; One 8x8 glyph per sheep still in hand, drawn at the bottom
; left; the strip is cleared first so a lost sheep disappears.
; The icons are bitplane pixels — the HUD band's COLOR01 makes
; them white, the same per-band trick as the fence and dashes.
;══════════════════════════════════════════════════════════════

drawflock:
            ; Clear the icon area (a row of byte-rectangles)
            moveq   #1,d0               ; From byte 1
            move.w  #ROW_HUD+4,d1
            moveq   #12,d2              ; Room for the whole flock
            moveq   #8,d3
            bsr     rectclear

            ; One glyph per sheep in hand
            move.w  lives,d7
            ble.s   .none               ; Empty hand, empty strip
            moveq   #1,d6               ; First icon at byte 1
.icons:
            move.w  d6,d0
            move.w  #ROW_HUD+4,d1
            lea     sheepicon,a2
            bsr     drawglyph
            addq.w  #2,d6               ; Two bytes along for the next
            subq.w  #1,d7
            bne.s   .icons
.none:
            rts

;──────────────────────────────────────────────────────────────
; drawglyph — copy an 8-row, 1-byte-wide glyph into the plane
;   d0 = x (bytes)   d1 = row   a2 = glyph (8 bytes)
;   Trashes d1, d4, a0.
;──────────────────────────────────────────────────────────────
drawglyph:
            lea     plane,a0
            move.w  d1,d4
            mulu    #ROW_BYTES,d4
            add.w   d0,d4
            adda.w  d4,a0
            moveq   #8-1,d4
.row:
            move.b  (a2)+,(a0)
            lea     ROW_BYTES(a0),a0
            dbf     d4,.row
            rts

;──────────────────────────────────────────────────────────────
; rectclear — rectfill's opposite: clear a byte-aligned block
;   d0 = x (bytes)   d1 = row   d2 = width (bytes)   d3 = height
;   Trashes d1, d4, d5, a0, a1.
;──────────────────────────────────────────────────────────────
rectclear:
            lea     plane,a0
            move.w  d1,d4
            mulu    #ROW_BYTES,d4
            add.w   d0,d4
            adda.w  d4,a0
            move.w  d3,d4
.row:
            movea.l a0,a1
            move.w  d2,d5
.col:
            clr.b   (a1)+
            subq.w  #1,d5
            bne.s   .col
            lea     ROW_BYTES(a0),a0
            subq.w  #1,d4
            bne.s   .row
            rts

sheepicon:  dc.b    %00100100           ; A sheep, in eight bytes:
            dc.b    %01111110           ;   ears up top,
            dc.b    %11111111           ;   a fat woolly middle,
            dc.b    %11111111
            dc.b    %11111111
            dc.b    %01111110
            dc.b    %00111100           ;   tapering to
            dc.b    %00011000           ;   a little tail
            even

;══════════════════════════════════════════════════════════════
; DRAWSCORE — four decimal digits at the strip's right end
;
; The score lives as one binary word; the display is decimal.
; DIVU by 10 peels the digits off the right: the remainder is
; the next digit, the quotient carries on. Stamp them right to
; left with the same drawglyph the icons use — each digit is
; just a glyph in the font table.
;══════════════════════════════════════════════════════════════

drawscore:
            move.w  score,d7            ; D7 = what's left to convert
            moveq   #38,d5              ; Rightmost digit's byte column
            moveq   #4-1,d6             ; Four digits
.digit:
            moveq   #0,d0
            move.w  d7,d0
            divu    #10,d0              ; Quotient low, remainder high
            move.l  d0,d1
            swap    d1                  ; D1 = this digit (0-9)
            move.w  d0,d7               ; D7 = the rest
            ; Find the digit's glyph: font + digit*8
            lea     digitfont,a2
            add.w   d1,d1
            add.w   d1,d1
            add.w   d1,d1               ; digit * 8
            adda.w  d1,a2
            move.w  d5,d0               ; Byte column
            move.w  #ROW_HUD+4,d1
            bsr     drawglyph
            subq.w  #1,d5               ; Next digit to the left
            dbf     d6,.digit
            rts

digitfont:  ; 0-9, one byte per row, eight rows each
            dc.b    %01111100,%11000110,%11001110,%11010110,%11100110,%11000110,%01111100,0  ; 0
            dc.b    %00011000,%00111000,%00011000,%00011000,%00011000,%00011000,%01111110,0  ; 1
            dc.b    %01111100,%11000110,%00000110,%00111100,%01100000,%11000000,%11111110,0  ; 2
            dc.b    %01111100,%11000110,%00000110,%00111100,%00000110,%11000110,%01111100,0  ; 3
            dc.b    %00011100,%00111100,%01101100,%11001100,%11111110,%00001100,%00001100,0  ; 4
            dc.b    %11111110,%11000000,%11111100,%00000110,%00000110,%11000110,%01111100,0  ; 5
            dc.b    %01111100,%11000000,%11111100,%11000110,%11000110,%11000110,%01111100,0  ; 6
            dc.b    %11111110,%00000110,%00001100,%00011000,%00110000,%00110000,%00110000,0  ; 7
            dc.b    %01111100,%11000110,%01111100,%11000110,%11000110,%11000110,%01111100,0  ; 8
            dc.b    %01111100,%11000110,%11000110,%01111110,%00000110,%00000110,%01111100,0  ; 9
            even

;══════════════════════════════════════════════════════════════
; COPPER LIST — the farmyard, plus eight sprite pointers
;══════════════════════════════════════════════════════════════

copperlist:
            ; --- Display setup ---
            dc.w    DIWSTRT,$2c81       ; Window: top-left
            dc.w    DIWSTOP,$2cc1       ; Window: bottom-right
            dc.w    DDFSTRT,$0038       ; Fetch start (lores)
            dc.w    DDFSTOP,$00d0       ; Fetch stop
            dc.w    BPLCON0,$2200       ; 2 bitplanes, colour burst on
            dc.w    BPLCON1,$0000       ; No scroll
            dc.w    BPLCON2,$0024       ; Sprites in front of playfield
            dc.w    BPL1MOD,$0000       ; No modulo — rows pack tight
            dc.w    BPL2MOD,$0000
copbpl:
            dc.w    BPL1PTH,$0000       ; Plane addresses, poked in
            dc.w    BPL1PTL,$0000       ;   by the CPU at startup
            dc.w    BPL2PTH,$0000
            dc.w    BPL2PTL,$0000

copsprites:
            dc.w    SPR0PTH+0,$0000     ; Sprite 0: the sheep (poked in)
            dc.w    SPR0PTH+2,$0000
            dc.w    SPR0PTH+4,$0000     ; Sprites 1-7: the null sprite
            dc.w    SPR0PTH+6,$0000
            dc.w    SPR0PTH+8,$0000
            dc.w    SPR0PTH+10,$0000
            dc.w    SPR0PTH+12,$0000
            dc.w    SPR0PTH+14,$0000
            dc.w    SPR0PTH+16,$0000
            dc.w    SPR0PTH+18,$0000
            dc.w    SPR0PTH+20,$0000
            dc.w    SPR0PTH+22,$0000
            dc.w    SPR0PTH+24,$0000
            dc.w    SPR0PTH+26,$0000
            dc.w    SPR0PTH+28,$0000
            dc.w    SPR0PTH+30,$0000

            ; --- Plane-2 colours: a resident sheep is white wherever
            ;     she settles (colour 2 = plane 2 alone; colour 3 = both
            ;     planes — fence-and-sheep never overlap, white is safe)
            dc.w    COLOR02,$0EEE
            dc.w    COLOR03,$0EEE

            ; --- The sheep's colours (sprites 0-1 share 17-19) ---
            dc.w    COLOR17,COLOUR_WOOL
            dc.w    COLOR18,COLOUR_FACE
            dc.w    COLOR19,COLOUR_SHADE

            ; --- The tractor's colours (sprites 2-3 share 21-23) ---
            dc.w    COLOR21,COLOUR_TRACTOR
            dc.w    COLOR22,COLOUR_TYRE
            dc.w    COLOR23,COLOUR_CAB

            ; --- The hay cart's (sprites 4-5 share 25-27) ---
            dc.w    COLOR25,COLOUR_WOODWORK
            dc.w    COLOR26,COLOUR_TYRE
            dc.w    COLOR27,COLOUR_HAY

            ; --- The Land Rover's (sprites 6-7 share 29-31) ---
            dc.w    COLOR29,COLOUR_ROVER
            dc.w    COLOR30,COLOUR_TYRE
            dc.w    COLOR31,COLOUR_ROOF

            ; --- THE FOLD (from the top of the frame) ---
            dc.w    COLOR00,COLOUR_FOLD_GRASS
            dc.w    COLOR01,COLOUR_FENCE        ; Pixels here are fence

            ; --- HEDGEROW (row 40) ---
            dc.w    $5401,$fffe                 ; Wait: line $2C+40 = $54
            dc.w    COLOR00,COLOUR_HEDGE
            dc.w    COLOR01,COLOUR_TUFT

            ; --- THE STREAM (row 48) ---
            dc.w    $5c01,$fffe                 ; Wait: line $2C+48 = $5C
            dc.w    COLOR00,COLOUR_WATER
            dc.w    COLOR01,COLOUR_WOOD         ; Pixels here are bridge

            ; --- THE BANK (row 80) ---
            dc.w    $7c01,$fffe                 ; Wait: line $2C+80 = $7C
            dc.w    COLOR00,COLOUR_BANK
            dc.w    COLOR01,COLOUR_TUFT

            ; --- THE LANE (row 96) ---
            dc.w    $8c01,$fffe                 ; Wait: line $2C+96 = $8C
            dc.w    COLOR00,COLOUR_LANE
            dc.w    COLOR01,COLOUR_DASH         ; Pixels here are markings

            ; --- THE VERGE (row 160) ---
            dc.w    $cc01,$fffe                 ; Wait: line $2C+160 = $CC
            dc.w    COLOR00,COLOUR_VERGE
            dc.w    COLOR01,COLOUR_TUFT

            ; --- THE FIELD (row 176, down to row 239) ---
            dc.w    $dc01,$fffe                 ; Wait: line $2C+176
            dc.w    COLOR00,COLOUR_FIELD
            dc.w    COLOR01,COLOUR_TUFT

            ; --- THE HUD STRIP (row 240) ---
            ; Row 240 is beam line $11C — past 255, which the Copper's
            ; 8-bit comparator can't name directly. The classic trick:
            ; wait for the very end of line 255, THEN wait for the low
            ; byte. The first wait carries you across the boundary.
            dc.w    $ffdf,$fffe                 ; To the end of line 255
            dc.w    $1c01,$fffe                 ; Then line $11C & $FF = $1C
            dc.w    COLOR00,COLOUR_HUD
            dc.w    COLOR01,COLOUR_ICON

            ; --- END OF COPPER LIST ---
            dc.w    $ffff,$fffe                 ; Wait for impossible position

;══════════════════════════════════════════════════════════════
; THE SHEEP — sprite 0, two step images
;
; Same sheep, two pictures. Step image 0: front-left and
; back-right feet planted. Step image 1: the other diagonal,
; tail swung the other way. Alternate them as she hops and
; she waddles. The control words are written by updsprite.
;══════════════════════════════════════════════════════════════

            section data,data_c

sheep0:
            dc.w    0                   ; POS — written by updsprite
            dc.w    0                   ; CTL — written by updsprite

            ;        plane A (fleece)    plane B (face/shade/feet)
            dc.w    %0000000000000000,%0000100000010000  ; ..ears..
            dc.w    %0000000000000000,%0000011111100000  ; ..head..
            dc.w    %0000000000000000,%0000001111000000  ; ..face..
            dc.w    %0000111111110000,%0000000000000000  ; fleece ruff
            dc.w    %0011111111111100,%0000000000000000  ; shoulders
            dc.w    %0111111111111110,%1000000000000000  ; < front foot
            dc.w    %0111111111111110,%1001000000001000  ; < + flecks
            dc.w    %0111111111111110,%0000000000000000
            dc.w    %0111111111111110,%0000001001000000  ; shade flecks
            dc.w    %0111111111111110,%0000000000000001  ; back foot >
            dc.w    %0111111111111110,%0000100000010001  ; + flecks  >
            dc.w    %0011111111111100,%0000000000000000  ; haunches
            dc.w    %0011111111111100,%0000000000000000
            dc.w    %0001111111111000,%0000000000000000
            dc.w    %0000111111110000,%0000000000000000  ; rump
            dc.w    %0000000000000000,%0000001100000000  ; tail, left

            dc.w    0,0                 ; End of sprite

sheep1:
            dc.w    0                   ; POS — written by updsprite
            dc.w    0                   ; CTL — written by updsprite

            ;        plane A (fleece)    plane B (face/shade/feet)
            dc.w    %0000000000000000,%0000100000010000  ; ..ears..
            dc.w    %0000000000000000,%0000011111100000  ; ..head..
            dc.w    %0000000000000000,%0000001111000000  ; ..face..
            dc.w    %0000111111110000,%0000000000000000  ; fleece ruff
            dc.w    %0011111111111100,%0000000000000000  ; shoulders
            dc.w    %0111111111111110,%0000000000000001  ; front foot >
            dc.w    %0111111111111110,%0001000000001001  ; + flecks  >
            dc.w    %0111111111111110,%0000000000000000
            dc.w    %0111111111111110,%0000001001000000  ; shade flecks
            dc.w    %0111111111111110,%1000000000000000  ; < back foot
            dc.w    %0111111111111110,%1000100000010000  ; < + flecks
            dc.w    %0011111111111100,%0000000000000000  ; haunches
            dc.w    %0011111111111100,%0000000000000000
            dc.w    %0001111111111000,%0000000000000000
            dc.w    %0000111111110000,%0000000000000000  ; rump
            dc.w    %0000000000000000,%0000000011000000  ; tail, right

            dc.w    0,0                 ; End of sprite

;══════════════════════════════════════════════════════════════
; THE TRACTOR — sprite 2
;
; Big rear wheels on the left, small front wheels and the
; bonnet pointing right — the way it drives. Red bodywork,
; dark tyres, a grey cab roof. Its own palette: sprites 2-3
; share colours 21-23.
;══════════════════════════════════════════════════════════════

tractor:
            dc.w    0                   ; POS — written by updsprite
            dc.w    0                   ; CTL — written by updsprite

            ;        plane A (body/cab)   plane B (tyres/cab)
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0111110000000000  ; rear wheel
            dc.w    %0000000000000000,%0111110000011110  ; + front wheel
            dc.w    %0000000000000000,%0111110000011110
            dc.w    %0000001111111100,%0111110000000000  ; chassis
            dc.w    %0111111111111110,%0000111110000000  ; body + cab
            dc.w    %0111111111111110,%0000111110000000
            dc.w    %0111111111111110,%0000111110000000
            dc.w    %0111111111111110,%0000111110000000
            dc.w    %0000001111111100,%0111110000000000  ; chassis
            dc.w    %0000000000000000,%0111110000011110
            dc.w    %0000000000000000,%0111110000011110  ; + front wheel
            dc.w    %0000000000000000,%0111110000000000  ; rear wheel
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0000000000000000

            dc.w    0,0                 ; End of sprite

nullspr:    dc.w    0,0                 ; A sprite that displays nothing
            dc.w    0,0

; --- The sheep's state ---
sheepx:     dc.w    SHEEP_X             ; Screen x (0-304)
sheepy:     dc.w    SHEEP_Y             ; Screen y (0-240)
cooldown:   dc.w    0                   ; Frames until the next hop
curframe:   dc.w    0                   ; Which step image: 0 or 1

;══════════════════════════════════════════════════════════════
; THE HAY CART — sprite 4
;
; Plods leftward: a wooden bed, a heaped load of hay, and
; wheels at the corners. Wood and hay get their own palette
; (sprites 4-5 share colours 25-27).
;══════════════════════════════════════════════════════════════

cart:
            dc.w    0                   ; POS — written by updsprite
            dc.w    0                   ; CTL — written by updsprite

            ;        plane A (wood/hay)   plane B (wheels/hay)
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0110000000000110  ; wheels
            dc.w    %0011111111111100,%0110000000000110
            dc.w    %0011111111111100,%0110000000000110
            dc.w    %0011111111111100,%0000111111110000  ; hay rises
            dc.w    %0011111111111100,%0001111111111000
            dc.w    %0011111111111100,%0001111111111000
            dc.w    %0011111111111100,%0001111111111000
            dc.w    %0011111111111100,%0001111111111000
            dc.w    %0011111111111100,%0000111111110000  ; hay falls
            dc.w    %0011111111111100,%0110000000000110
            dc.w    %0011111111111100,%0110000000000110  ; wheels
            dc.w    %0000000000000000,%0110000000000110
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0000000000000000

            dc.w    0,0                 ; End of sprite

;══════════════════════════════════════════════════════════════
; THE LAND ROVER — sprite 6
;
; The farmer's in a hurry. Boxy paintwork, a roof panel set
; back from the bonnet (it drives leftward, so the bonnet is
; the left end), wheels at the corners. Sprites 6-7 share
; colours 29-31.
;══════════════════════════════════════════════════════════════

rover:
            dc.w    0                   ; POS — written by updsprite
            dc.w    0                   ; CTL — written by updsprite

            ;        plane A (paint/roof)  plane B (wheels/roof)
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0011000000001100  ; wheels
            dc.w    %0111111111111110,%0011000000001100
            dc.w    %0111111111111110,%0011000000001100
            dc.w    %0111111111111110,%0000001111111000  ; roof panel,
            dc.w    %0111111111111110,%0000001111111000  ;   set back
            dc.w    %0111111111111110,%0000001111111000  ;   from the
            dc.w    %0111111111111110,%0000001111111000  ;   bonnet
            dc.w    %0111111111111110,%0000001111111000
            dc.w    %0111111111111110,%0000001111111000
            dc.w    %0111111111111110,%0011000000001100
            dc.w    %0111111111111110,%0011000000001100  ; wheels
            dc.w    %0000000000000000,%0011000000001100
            dc.w    %0000000000000000,%0000000000000000
            dc.w    %0000000000000000,%0000000000000000

            dc.w    0,0                 ; End of sprite

; --- The traffic's state ---
tractx:     dc.w    -16                 ; The tractor enters from the left
cartx:      dc.w    300                 ; The cart from the right
roverx:     dc.w    160                 ; The Rover mid-lane, flat out

; --- The squash beat ---
squashtimer: dc.w   0                   ; Frames of stillness remaining

; --- The flock ---
lives:      dc.w    FLOCK_SIZE          ; Sheep in hand
gameover:   dc.w    0                   ; 1 = the field is empty
won:        dc.w    0                   ; 1 = every pen is full
unpenned:   dc.w    5                   ; Pens still to fill
score:      dc.w    0                   ; Points so far
roadflag:   dc.w    0                   ; This sheep has crossed the road

;══════════════════════════════════════════════════════════════
; THE BITPLANE (Chip RAM)
;══════════════════════════════════════════════════════════════

plane:      ds.b    ROW_BYTES*256       ; Plane 1: fence, bridge, dashes, icons
plane2:     ds.b    ROW_BYTES*256       ; Plane 2: the fold's residents

If It Doesn’t Work

  • Garbage digits? The font index is digit × 8 — three add.w d1,d1 doublings. Miscount the doublings and you’re reading between glyphs.
  • The score never draws? drawscore runs at startup and on every change — if you add a payout, the call goes beside it.
  • Division surprises? DIVU wants the dividend as a long — clear the register first (moveq #0,d0 before the move.w). A stale high word divides into nonsense.
  • The same sheep keeps earning the road bonus? roadflag must reset on respawn and on penning — the successor’s flag, not the veteran’s.

Try This

  1. High score. A second word, updated at game over if beaten, drawn dimmer beside the live score. Decide where it draws from — and notice you’ve just invented persistent state that outlives a flock.
  2. Score the squash. Minus points for a loss? Trace what sub.w does when the score would go below zero, and decide whether your farmyard is the kind that does debt.
  3. The cost of drawing. drawscore converts and stamps four digits on every change. Would caching the digits and redrawing only the changed ones be worth it? Count the writes before you answer — then remember which machine drew the rest of this frame for free.

What You’ve Learnt

  • DIVU — quotient and remainder in one instruction; repeated division by 10 is binary-to-decimal. swap reaches the high word.
  • Fonts as tables — glyph = font + character × height; text is a loop over stamps. The HUD font and the flock icons are the same machinery.
  • Once-per-life flagsroadflag pays a bonus exactly once per sheep, reset where the next life begins.
  • Display as a function of state, again — the score redraws at the moment it changes, whole. The habit generalises.

What’s Next

The farm is silent. In Unit 11, Paula speaks: a soft baa on the hop, a squelch for a loss, a contented bleat at the pen — tones from the Amiga’s sound chip, triggered from the events you’ve already built. The last sense arrives.