[{"data":1,"prerenderedAt":207},["ShallowReactive",2],{"learn:invaders:08-descend":3},{"item":4,"marksAgainst":206},{"slug":5,"number":6,"title":7,"idea":8,"models":9,"body":12,"tryIt":156,"game":188,"cites":189,"program":205},"08-descend",8,"Reaching an edge, it inches down","one routine, three moves: the same ADD HL,DE steps right, left, or down",[10,11],3,1,[13,19,23,27,75,79,82,89,96,99,105,108,119,121,135,138,142,145,149,152],{"kind":14,"inlines":15},"p",[16],{"kind":17,"text":18},"text","Now the row comes for the base. When it reaches an edge it still turns round, but that step takes it down a row instead of sideways, and then it marches back across the screen one row lower. Each crossing brings the invaders nearer. For now they stop coming down at row 13, two rows above the base; they go on marching there.",{"kind":20,"id":21,"text":22},"h2","what-changed","What changed",{"kind":14,"inlines":24},[25],{"kind":17,"text":26},"Chapter 7's program, with these changes:",{"kind":28,"items":29},"ul",[30,36,45,57,64],[31,34],{"kind":32,"text":33},"strong","~",{"kind":17,"text":35}," The comment at the top, lines 1 to 5, now describes chapter 8.",[37,38,40,43],{"kind":32,"text":33},{"kind":17,"text":39}," ",{"kind":41,"text":42},"code","MARCH",{"kind":17,"text":44},"'s comment: line 121 is changed and line 122 is new; they say that the step at an edge goes down a row.",[46,48,50,51,53,55],{"kind":32,"text":47},"+",{"kind":17,"text":49}," Six lines in ",{"kind":41,"text":42},{"kind":17,"text":52},", lines 137 to 142, after ",{"kind":41,"text":54},"EX DE,HL",{"kind":17,"text":56},": unless the invaders are on row 13, the step at an edge goes down a row.",[58,59,60,62],{"kind":32,"text":33},{"kind":17,"text":39},{"kind":41,"text":61},"MOVEROW",{"kind":17,"text":63},"'s comment, lines 164 and 165: it now says that 64 moves the row down.",[65,66,67,69,71,73],{"kind":32,"text":47},{"kind":17,"text":39},{"kind":41,"text":68},"INVROW",{"kind":17,"text":70},", after ",{"kind":41,"text":72},"TICK",{"kind":17,"text":74},", line 214: the screen row the invaders are on.",{"kind":14,"inlines":76},[77],{"kind":17,"text":78},"Nothing is taken out.",{"kind":20,"id":80,"text":81},"down-is-64","Down is 64",{"kind":14,"inlines":83},[84,86,87],{"kind":17,"text":85},"Chapter 7's ",{"kind":41,"text":61},{"kind":17,"text":88}," adds DE to every invader's address. It does not care what DE is: 1 moves the row a column right, -1 a column left, and 64 a row down, because a row is 64 cells and the cell below an address is 64 after it, as the cell above was 64 before it in chapter 4. So going down needs no new routine, only a different DE.",{"kind":14,"inlines":90},[91,93,94],{"kind":17,"text":92},"At an edge, ",{"kind":41,"text":42},{"kind":17,"text":95}," turns round as before, putting the new step in DE, and then, unless the row is as low as it goes, puts 64 in DE instead:",{"kind":41,"lang":97,"text":98},"z80","        EX      DE,HL           ; and the new step into DE\n        LD      A,(INVROW)      ; the row the invaders are on\n        CP      13              ; row 13, the lowest they go for now?\n        JR      Z,SIDE          ; then they only turn, and step sideways\n        INC     A               ; one row lower\n        LD      (INVROW),A\n        LD      DE,64           ; a row is 64 cells: this step goes down\nSIDE:   CALL    MOVEROW         ; every invader moves by DE",{"kind":14,"inlines":100},[101,103],{"kind":41,"text":102},"STEP",{"kind":17,"text":104}," has already changed sign, so the step after the one down goes back the other way. The row is erased before it moves and drawn after, as in chapter 7, so it leaves nothing behind on the row above.",{"kind":20,"id":106,"text":107},"which-row","Which row",{"kind":14,"inlines":109},[110,112,114,116,117],{"kind":17,"text":111},"The addresses in ",{"kind":41,"text":113},"INVS",{"kind":17,"text":115}," say where every invader is, but not, without some arithmetic, which row that is. ",{"kind":41,"text":68},{"kind":17,"text":118}," keeps it in a byte, starting at 2:",{"kind":41,"lang":97,"text":120},"INVROW: DB      2               ; the row the invaders are on, 2 to 13",{"kind":14,"inlines":122},[123,125,127,129,131,133],{"kind":41,"text":124},"CP 13",{"kind":17,"text":126}," compares A with 13 and sets only the flags, so A still holds the row for ",{"kind":41,"text":128},"INC A",{"kind":17,"text":130},". At row 13 the jump to ",{"kind":41,"text":132},"SIDE",{"kind":17,"text":134}," skips the move down, and DE still holds the new step: the row turns and marches back on the same row, as it did in chapter 7. Row 14 is where a shot starts and row 15 is the base, so the invaders never draw over either.",{"kind":20,"id":136,"text":137},"how-long-it-takes","How long it takes",{"kind":14,"inlines":139},[140],{"kind":17,"text":141},"The row steps about every 266 ms, as in chapter 7. It reaches the right edge after 20 steps and comes down on the 21st, about five and a half seconds in; then each crossing is 34 steps sideways and one down, about nine seconds. Ten more crossings bring it to row 13, about 100 seconds after Run ▶.",{"kind":20,"id":143,"text":144},"keys-go-to-the-screen-not-the-editor","Keys go to the screen, not the editor",{"kind":14,"inlines":146},[147],{"kind":17,"text":148},"Click the TRS-80's screen before you press the arrows or the space bar, so that it has the keyboard.",{"kind":20,"id":150,"text":151},"on-the-model-i","On the Model I",{"kind":14,"inlines":153},[154],{"kind":17,"text":155},"The Model I has the same keyboard row and the same screen, so the program runs unchanged. Fugløy runs the Model I at 1.77 MHz, and the Model III at 2.03 MHz, so the row steps about every 305 ms there instead of 266.",[157,161],{"kind":14,"inlines":158},[159],{"kind":17,"text":160},"Press Run ▶ and wait about five seconds: the row reaches the right edge, comes down to row 3, and marches back to the left.",{"kind":14,"inlines":162},[163,165,166,168,170,172,173,175,176,178,180,181,183,185,186],{"kind":17,"text":164},"Then change ",{"kind":41,"text":124},{"kind":17,"text":167}," to ",{"kind":41,"text":169},"CP 4",{"kind":17,"text":171},". After two edges, down to row 4, the invaders go no lower, and turn on row 4 at each edge after. Or put ",{"kind":41,"text":124},{"kind":17,"text":174}," back and change ",{"kind":41,"text":68},{"kind":17,"text":177},"'s ",{"kind":41,"text":179},"DB 2",{"kind":17,"text":167},{"kind":41,"text":182},"DB 12",{"kind":17,"text":184},": the invaders come down once, to row 3, and no further. ",{"kind":41,"text":68},{"kind":17,"text":187}," is only what the program has been told about the row, and nothing checks it against the table.",null,[190,194,198,202],{"source":191,"page":192,"about":193},"m3-trm","14","the Model III's keyboard is memory at 3800H-3BFFH, and its screen at 3C00H",{"source":195,"page":196,"about":197},"m1-trh","12","the Model I's keyboard is memory from 3800H, and its screen at 3C00H",{"source":199,"page":200,"about":201},"decker","64","the keyboard's rows are read at 3801H to 3840H, one address a row",{"source":203,"page":204,"about":201},"paay","26","; Build Space Invaders, chapter 8: the row inches down. Chapter 7's base,\n; shot and marching row, and now, when the row reaches an edge, it turns\n; round and steps down a row instead of sideways, so each crossing of the\n; screen brings the invaders a row nearer the base. INVROW keeps the screen\n; row they are on; for now they go no lower than row 13.\n\n        ORG     7000H           ; the program lives at 7000H, in free memory\n\n; WAIT: a counted delay, 5,120 passes of 26 T-states, about 66 ms a turn at\n; 2.03 MHz. The routines come first, and the game itself after them, from\n; START, where END START says the program begins.\nWAIT:   PUSH    BC              ; save BC, which the loop uses\n        LD      BC,1400H        ; 1400H is 5,120 passes of 26 T-states\nDELAY:  DEC     BC\n        LD      A,B\n        OR      C\n        JR      NZ,DELAY\n        POP     BC              ; BC as the caller left it\n        RET\n\n; DRAWBASE: copy the three bytes HL points at to the base's place on row 15,\n; 3FC0H plus BASEX. BC is kept on the stack; A, DE and HL are not.\nDRAWBASE:\n        PUSH    BC              ; save BC, which LDIR counts down\n        LD      A,(BASEX)       ; the base's column ...\n        ADD     A,0C0H          ; ... plus 3FC0H, row 15: the base's left cell\n        LD      E,A\n        LD      D,3FH\n        LD      BC,3            ; three bytes\n        LDIR                    ; from (HL) to (DE), one byte at a time\n        POP     BC              ; BC as the caller left it\n        RET\n\n; MOVEBASE: with the left or right arrow down, erase the base, move it a\n; column, and draw it again. Columns 0 and 61 are the edges: there it stays.\nMOVEBASE:\n        LD      A,(3840H)       ; the arrows' row: bit 5 left, 6 right\n        AND     60H             ; keep those two bits (0110 0000)\n        RET     Z               ; neither is down: nothing to do\n        LD      C,A             ; keep the keys in C, so A is free\n        LD      HL,BLANK        ; erase the base where it is\n        CALL    DRAWBASE\n        LD      A,(BASEX)       ; the base's column, from memory\n        BIT     5,C             ; left?\n        JR      Z,NOTLT\n        CP      0               ; column 0, the left edge: stay\n        JR      Z,NOTLT\n        DEC     A\nNOTLT:\n        BIT     6,C             ; right?\n        JR      Z,NOTRT\n        CP      61              ; column 61, the right edge for three cells: stay\n        JR      Z,NOTRT\n        INC     A\nNOTRT:\n        LD      (BASEX),A       ; the new column, back to memory\n        LD      HL,BASE         ; draw the base there\n        CALL    DRAWBASE\n        RET\n\n; MOVESHOT: the shot, if there is one, moves up a row; past row 0 it is gone.\nMOVESHOT:\n        LD      HL,(SHOT)       ; where the shot is: two bytes from memory into HL\n        LD      A,H             ; 0 is no shot: test HL as the clear tests BC\n        OR      L\n        RET     Z               ; no shot: nothing to do\n        LD      (HL),20H        ; erase the shot where it is\n        LD      DE,-64          ; up a row\n        ADD     HL,DE\n        BIT     2,H             ; still on the screen? 3C00H-3FFFH all have bit 2 of H set\n        JR      NZ,SHOTUP\n        LD      HL,0            ; off the top: no shot\nSHOTUP: LD      (SHOT),HL       ; keep where it is, or 0\n        LD      A,H\n        OR      L\n        RET     Z               ; gone: nothing to draw\n        LD      (HL),21H        ; the shot is an exclamation mark\n        RET\n\n; FIRE: with the space bar down and no shot in the air, a shot starts on\n; row 14, just above the base's middle cell.\nFIRE:   LD      A,(3840H)       ; the space bar is bit 7 of the arrows' row\n        BIT     7,A\n        RET     Z               ; not down: nothing to do\n        LD      HL,(SHOT)\n        LD      A,H\n        OR      L\n        RET     NZ              ; a shot is in the air already: one at a time\n        LD      A,(BASEX)       ; row 14 starts at 3F80H; the base's middle\n        ADD     A,81H           ; is its column plus one: 3F81H plus BASEX\n        LD      L,A\n        LD      H,3FH\n        LD      (HL),21H        ; draw the shot\n        LD      (SHOT),HL       ; and remember where it is\n        RET\n\n; DRAWROW: copy the two bytes DE points at to every invader's place: INVS\n; holds their screen addresses, a word each. IX walks the table and B counts\n; the invaders; BC is kept on the stack, and DE ends where it began.\nDRAWROW:\n        PUSH    BC              ; save BC: B counts the invaders\n        LD      IX,INVS         ; IX points at the table's first word\n        LD      B,8             ; eight invaders, counted down by DJNZ\nDRAWONE:\n        LD      L,(IX+0)        ; this invader's screen address: the low byte\n        LD      H,(IX+1)        ; first, then the high, as a DW stores them\n        LD      A,(DE)          ; the shape's left cell\n        LD      (HL),A\n        INC     HL\n        INC     DE\n        LD      A,(DE)          ; and its right cell\n        LD      (HL),A\n        DEC     DE              ; back to the shape's start, for the next one\n        INC     IX              ; on to the next word of the table\n        INC     IX\n        DJNZ    DRAWONE         ; B minus 1, and the next invader until it is 0\n        POP     BC              ; BC as the caller left it\n        RET\n\n; MARCH: every fourth turn, erase the row and move it a column, the way STEP\n; says. At the edge the row is marching to, it turns round, and that step\n; goes down a row instead, as far as row 13.\nMARCH:  LD      HL,TICK         ; one turn fewer to the row's next step\n        DEC     (HL)\n        RET     NZ              ; not 0 yet: not this turn\n        LD      (HL),4          ; 0: a step now, and the next in four turns\n        LD      DE,BLANK        ; erase the row where it is\n        CALL    DRAWROW\n        LD      DE,(STEP)       ; the step: 1 right, or -1 left\n        CALL    EDGE            ; Z: an invader is at the edge ahead\n        JR      NZ,SIDE\n        LD      HL,0            ; turn round: the step becomes 0 minus the step\n        OR      A               ; clear the carry flag, which SBC takes off too\n        SBC     HL,DE\n        LD      (STEP),HL\n        EX      DE,HL           ; and the new step into DE\n        LD      A,(INVROW)      ; the row the invaders are on\n        CP      13              ; row 13, the lowest they go for now?\n        JR      Z,SIDE          ; then they only turn, and step sideways\n        INC     A               ; one row lower\n        LD      (INVROW),A\n        LD      DE,64           ; a row is 64 cells: this step goes down\nSIDE:   CALL    MOVEROW         ; every invader moves by DE\n        RET\n\n; EDGE: is an invader at the edge the row is marching to? E is the step's\n; low byte, 1 or 0FFH. The low six bits of an invader's address are its\n; column; the next column would be 63 at the right edge, and -1 at the left,\n; and both are 3FH in six bits. Z if an invader is there, NZ if none is.\nEDGE:   LD      IX,INVS         ; IX walks the table, as in DRAWROW\n        LD      B,8\nEDGEONE:\n        LD      A,(IX+0)        ; the low byte of the invader's address\n        ADD     A,E             ; plus the step\n        AND     3FH             ; its low six bits: the column it would move to\n        CP      3FH             ; 63, or -1: past an edge\n        RET     Z               ; this one is at the edge: return with Z\n        INC     IX\n        INC     IX\n        DJNZ    EDGEONE\n        OR      1               ; none is: A is not 0 after OR 1, so NZ\n        RET\n\n; MOVEROW: add DE to every invader's address in INVS: 1 moves the row a\n; column right, -1, the word 0FFFFH, a column left, and 64 a row down.\nMOVEROW:\n        LD      IX,INVS\n        LD      B,8\nMOVEONE:\n        LD      L,(IX+0)        ; the invader's address into HL\n        LD      H,(IX+1)\n        ADD     HL,DE           ; plus the step\n        LD      (IX+0),L        ; and back into the table\n        LD      (IX+1),H\n        INC     IX\n        INC     IX\n        DJNZ    MOVEONE\n        RET\n\nSTART:  LD      HL,3C00H        ; HL points at the top-left cell\n        LD      BC,400H         ; BC counts the cells: 400H is 1024\nCLEAR:  LD      (HL),20H        ; a space: the cell is blank\n        INC     HL              ; on to the next cell\n        DEC     BC              ; one cell fewer to go (DEC BC sets no flags ...)\n        LD      A,B             ; ... so test BC by hand: copy B into A\n        OR      C               ; and OR in C: zero only when B and C both are\n        JR      NZ,CLEAR        ; not zero yet: clear the next cell\n        LD      HL,BASE         ; draw the base where BASEX says\n        CALL    DRAWBASE\n\n; The game loop: one turn of the game, then round again. A game's turn\n; reads the keys, moves things and draws them: the base, the shot, the invaders.\nLOOP:   CALL    WAIT            ; the turn's pause, so the game runs at a steady speed\n        CALL    MOVEBASE        ; the base moves if an arrow is down\n        CALL    MOVESHOT        ; the shot, if there is one, rises a row\n        CALL    FIRE            ; the space bar starts a shot, if there is none\n        CALL    MARCH           ; every fourth turn, the row steps\n        LD      DE,INVADER      ; the row, drawn every turn: a shot passing\n        CALL    DRAWROW         ; through an invader erases a cell, and this mends it\n        JR      LOOP            ; and round again, for ever\n\n; The game's data: below the loop, where the processor never runs into it.\nBASE:   DB      0BCH,0BFH,0BCH  ; the base: a wing, a block, a wing\nBLANK:  DB      '   '           ; three spaces, to erase it\nINVADER:\n        DB      9EH,0ADH        ; an invader: two cells, a head, arms and legs\n; INVS: the invaders' places, each row 2's start, 3C80H, plus a column.\nINVS:   DW      3C80H+14,3C80H+18,3C80H+22,3C80H+26\n        DW      3C80H+30,3C80H+34,3C80H+38,3C80H+42\nBASEX:  DB      30              ; the base's column, 0 to 61\nSHOT:   DW      0               ; the shot's screen address, or 0 for none\nSTEP:   DW      1               ; the row's step: 1 right, or -1 (0FFFFH) left\nTICK:   DB      4               ; turns to the row's next step\nINVROW: DB      2               ; the row the invaders are on, 2 to 13\n\n        END     START           ; the program starts at START\n","; Build Space Invaders, chapter 7: the row marches. Chapter 6's base, shot\n; and row of eight invaders, and now every fourth turn MARCH moves the row a\n; column, the way STEP says, right or left. When an invader reaches the edge\n; the row is marching to, EDGE says so, and the row turns round and marches\n; back. The invaders still let a shot go behind them.\n\n        ORG     7000H           ; the program lives at 7000H, in free memory\n\n; WAIT: a counted delay, 5,120 passes of 26 T-states, about 66 ms a turn at\n; 2.03 MHz. The routines come first, and the game itself after them, from\n; START, where END START says the program begins.\nWAIT:   PUSH    BC              ; save BC, which the loop uses\n        LD      BC,1400H        ; 1400H is 5,120 passes of 26 T-states\nDELAY:  DEC     BC\n        LD      A,B\n        OR      C\n        JR      NZ,DELAY\n        POP     BC              ; BC as the caller left it\n        RET\n\n; DRAWBASE: copy the three bytes HL points at to the base's place on row 15,\n; 3FC0H plus BASEX. BC is kept on the stack; A, DE and HL are not.\nDRAWBASE:\n        PUSH    BC              ; save BC, which LDIR counts down\n        LD      A,(BASEX)       ; the base's column ...\n        ADD     A,0C0H          ; ... plus 3FC0H, row 15: the base's left cell\n        LD      E,A\n        LD      D,3FH\n        LD      BC,3            ; three bytes\n        LDIR                    ; from (HL) to (DE), one byte at a time\n        POP     BC              ; BC as the caller left it\n        RET\n\n; MOVEBASE: with the left or right arrow down, erase the base, move it a\n; column, and draw it again. Columns 0 and 61 are the edges: there it stays.\nMOVEBASE:\n        LD      A,(3840H)       ; the arrows' row: bit 5 left, 6 right\n        AND     60H             ; keep those two bits (0110 0000)\n        RET     Z               ; neither is down: nothing to do\n        LD      C,A             ; keep the keys in C, so A is free\n        LD      HL,BLANK        ; erase the base where it is\n        CALL    DRAWBASE\n        LD      A,(BASEX)       ; the base's column, from memory\n        BIT     5,C             ; left?\n        JR      Z,NOTLT\n        CP      0               ; column 0, the left edge: stay\n        JR      Z,NOTLT\n        DEC     A\nNOTLT:\n        BIT     6,C             ; right?\n        JR      Z,NOTRT\n        CP      61              ; column 61, the right edge for three cells: stay\n        JR      Z,NOTRT\n        INC     A\nNOTRT:\n        LD      (BASEX),A       ; the new column, back to memory\n        LD      HL,BASE         ; draw the base there\n        CALL    DRAWBASE\n        RET\n\n; MOVESHOT: the shot, if there is one, moves up a row; past row 0 it is gone.\nMOVESHOT:\n        LD      HL,(SHOT)       ; where the shot is: two bytes from memory into HL\n        LD      A,H             ; 0 is no shot: test HL as the clear tests BC\n        OR      L\n        RET     Z               ; no shot: nothing to do\n        LD      (HL),20H        ; erase the shot where it is\n        LD      DE,-64          ; up a row\n        ADD     HL,DE\n        BIT     2,H             ; still on the screen? 3C00H-3FFFH all have bit 2 of H set\n        JR      NZ,SHOTUP\n        LD      HL,0            ; off the top: no shot\nSHOTUP: LD      (SHOT),HL       ; keep where it is, or 0\n        LD      A,H\n        OR      L\n        RET     Z               ; gone: nothing to draw\n        LD      (HL),21H        ; the shot is an exclamation mark\n        RET\n\n; FIRE: with the space bar down and no shot in the air, a shot starts on\n; row 14, just above the base's middle cell.\nFIRE:   LD      A,(3840H)       ; the space bar is bit 7 of the arrows' row\n        BIT     7,A\n        RET     Z               ; not down: nothing to do\n        LD      HL,(SHOT)\n        LD      A,H\n        OR      L\n        RET     NZ              ; a shot is in the air already: one at a time\n        LD      A,(BASEX)       ; row 14 starts at 3F80H; the base's middle\n        ADD     A,81H           ; is its column plus one: 3F81H plus BASEX\n        LD      L,A\n        LD      H,3FH\n        LD      (HL),21H        ; draw the shot\n        LD      (SHOT),HL       ; and remember where it is\n        RET\n\n; DRAWROW: copy the two bytes DE points at to every invader's place: INVS\n; holds their screen addresses, a word each. IX walks the table and B counts\n; the invaders; BC is kept on the stack, and DE ends where it began.\nDRAWROW:\n        PUSH    BC              ; save BC: B counts the invaders\n        LD      IX,INVS         ; IX points at the table's first word\n        LD      B,8             ; eight invaders, counted down by DJNZ\nDRAWONE:\n        LD      L,(IX+0)        ; this invader's screen address: the low byte\n        LD      H,(IX+1)        ; first, then the high, as a DW stores them\n        LD      A,(DE)          ; the shape's left cell\n        LD      (HL),A\n        INC     HL\n        INC     DE\n        LD      A,(DE)          ; and its right cell\n        LD      (HL),A\n        DEC     DE              ; back to the shape's start, for the next one\n        INC     IX              ; on to the next word of the table\n        INC     IX\n        DJNZ    DRAWONE         ; B minus 1, and the next invader until it is 0\n        POP     BC              ; BC as the caller left it\n        RET\n\n; MARCH: every fourth turn, erase the row and move it a column, the way STEP\n; says. At the edge the row is marching to, it turns round first.\nMARCH:  LD      HL,TICK         ; one turn fewer to the row's next step\n        DEC     (HL)\n        RET     NZ              ; not 0 yet: not this turn\n        LD      (HL),4          ; 0: a step now, and the next in four turns\n        LD      DE,BLANK        ; erase the row where it is\n        CALL    DRAWROW\n        LD      DE,(STEP)       ; the step: 1 right, or -1 left\n        CALL    EDGE            ; Z: an invader is at the edge ahead\n        JR      NZ,SIDE\n        LD      HL,0            ; turn round: the step becomes 0 minus the step\n        OR      A               ; clear the carry flag, which SBC takes off too\n        SBC     HL,DE\n        LD      (STEP),HL\n        EX      DE,HL           ; and the new step into DE\nSIDE:   CALL    MOVEROW         ; every invader moves by DE\n        RET\n\n; EDGE: is an invader at the edge the row is marching to? E is the step's\n; low byte, 1 or 0FFH. The low six bits of an invader's address are its\n; column; the next column would be 63 at the right edge, and -1 at the left,\n; and both are 3FH in six bits. Z if an invader is there, NZ if none is.\nEDGE:   LD      IX,INVS         ; IX walks the table, as in DRAWROW\n        LD      B,8\nEDGEONE:\n        LD      A,(IX+0)        ; the low byte of the invader's address\n        ADD     A,E             ; plus the step\n        AND     3FH             ; its low six bits: the column it would move to\n        CP      3FH             ; 63, or -1: past an edge\n        RET     Z               ; this one is at the edge: return with Z\n        INC     IX\n        INC     IX\n        DJNZ    EDGEONE\n        OR      1               ; none is: A is not 0 after OR 1, so NZ\n        RET\n\n; MOVEROW: add DE to every invader's address in INVS: a step of 1 moves the\n; row a column right, and -1, the word 0FFFFH, a column left.\nMOVEROW:\n        LD      IX,INVS\n        LD      B,8\nMOVEONE:\n        LD      L,(IX+0)        ; the invader's address into HL\n        LD      H,(IX+1)\n        ADD     HL,DE           ; plus the step\n        LD      (IX+0),L        ; and back into the table\n        LD      (IX+1),H\n        INC     IX\n        INC     IX\n        DJNZ    MOVEONE\n        RET\n\nSTART:  LD      HL,3C00H        ; HL points at the top-left cell\n        LD      BC,400H         ; BC counts the cells: 400H is 1024\nCLEAR:  LD      (HL),20H        ; a space: the cell is blank\n        INC     HL              ; on to the next cell\n        DEC     BC              ; one cell fewer to go (DEC BC sets no flags ...)\n        LD      A,B             ; ... so test BC by hand: copy B into A\n        OR      C               ; and OR in C: zero only when B and C both are\n        JR      NZ,CLEAR        ; not zero yet: clear the next cell\n        LD      HL,BASE         ; draw the base where BASEX says\n        CALL    DRAWBASE\n\n; The game loop: one turn of the game, then round again. A game's turn\n; reads the keys, moves things and draws them: the base, the shot, the invaders.\nLOOP:   CALL    WAIT            ; the turn's pause, so the game runs at a steady speed\n        CALL    MOVEBASE        ; the base moves if an arrow is down\n        CALL    MOVESHOT        ; the shot, if there is one, rises a row\n        CALL    FIRE            ; the space bar starts a shot, if there is none\n        CALL    MARCH           ; every fourth turn, the row steps\n        LD      DE,INVADER      ; the row, drawn every turn: a shot passing\n        CALL    DRAWROW         ; through an invader erases a cell, and this mends it\n        JR      LOOP            ; and round again, for ever\n\n; The game's data: below the loop, where the processor never runs into it.\nBASE:   DB      0BCH,0BFH,0BCH  ; the base: a wing, a block, a wing\nBLANK:  DB      '   '           ; three spaces, to erase it\nINVADER:\n        DB      9EH,0ADH        ; an invader: two cells, a head, arms and legs\n; INVS: the invaders' places, each row 2's start, 3C80H, plus a column.\nINVS:   DW      3C80H+14,3C80H+18,3C80H+22,3C80H+26\n        DW      3C80H+30,3C80H+34,3C80H+38,3C80H+42\nBASEX:  DB      30              ; the base's column, 0 to 61\nSHOT:   DW      0               ; the shot's screen address, or 0 for none\nSTEP:   DW      1               ; the row's step: 1 right, or -1 (0FFFFH) left\nTICK:   DB      4               ; turns to the row's next step\n\n        END     START           ; the program starts at START\n",1792464471315]