M/C Part 9 Right, following up last month's little squiddle at interrupts (squiddle? - yup, I made the word up myself), here's a little hint on how to scan for the mouse. Firstly, here's the mouse scan routine from last time: MOUSE_SCAN PUSH BC PUSH DE PUSH HL LD BC,#FFFE IN A,(C) LD HL,MOUSE_SPACE ; Temporary storage area LD DE,#070F IN A,(C) AND E CP E JR NZ,MOUSE_END MS1 LD (HL),A INC HL IN A,(C) DEC D JR NZ,MS1 LD (HL),A LD HL,MOUSE_TABLE LD A,(HL) CPL ; CPL inverts all the bits of A AND 7 ; Isolate bits 0-2 LD (BUTTON_STATUS),A INC HL INC HL LD A,(HL) INC HL AND E RLCA RLCA RLCA RLCA LD D,A LD A,(HL) AND E OR D ***** NEG ; Add this if you want to number ***** ; your y axis from 0 at the top. ; Neg makes the accumulator negative ; ie. 1 becomes -1 (#FF) LD D,A LD A,(Y_COORD) ADD A,D CP 192 ; This is yer maximum y coordinate JR C,MS2 XOR A BIT 7,D JR NZ,MS2 LD A,191 ; Maximum y-1 MS2 LD (Y_COORD),A INC HL INC HL LD A,(HL) INC HL AND E RLCA RLCA RLCA RLCA LD D,A LD A,(HL) AND E OR D LD E,A RLA SBC A,A LD D,A LD HL,(X_COORD) ; 16 bit value ADD HL,DE LD A,(FATPIX) ; This is zero, if we are using LD B,3 ; MODE 3 with high-res pixels. AND A ; Otherwise, make it non-zero. JR Z,MS3 ; (ie. if in another mode or if DEC B ; fatpix is 1) MS3 LD A,H INC A JR Z,MS4 CP B JR C,MS5 LD H,B DEC H DEC H LD L,255 JR MS5 MS4 LD HL,0 MS5 LD (X_COORD),HL MOUSE_END POP HL POP DE POP BC RET X_COORD DW 0 Y_COORD DB 0 BUTTON DB 0 ; BITS 0 & 2 correspond to buttons on ; mouse FATPIX DB 0 ; see above. MOUSE_SPACE DS 8 Right, after you skipped over that, let me explain. If this routine is called by the frame interrupt, the mouse is scanned and coordinates are updated. However, if no mouse is connected (and by this I mean that there is no interface plugged into SAM's bum), this will result in your cursor moving steadily down to the bottom left of the screen - not too practical if you want your program to be of use to the non-mouse owning public. Of course, you can set up your prog to use keys when loaded, and supply a method of selecting mouse control, but this can be irritating and if a geezer with nae mouse accidentally (or stupidly, if he's from Dundee) selects this his cursor is way gone, and he's gonna have to re-load the prog. Now, some of you may know that I've just written a couple of games which are mouse compatible (Colin's supposed to be releasing them) and when you buy them you'll notice two things (apart from the fact that they're both sheer class): a) If you've got a mouse connected mouse control is selected automatically. b) If you haven't got a mouse you can't select the mouse control icon. Since I'm such a cool kinda guy, I've decided to share the mouse detection routine with you (I am TOO good, though). Firstly, here's how it works: The mouse is not scanned continously - if it was your program would be too slow. Instead the interface (apart from just converting atari to din plugs, as one Fred reader thought) has internal registers which take the movement signals from the mouse and update the movement displacement from the last time it transmitted the data to the coupe. When you ask for a read of these registers, they empty ready to start again. This way your cursor will always be in the right position, and the more scans you request, the smoother your sprite movement will be. The input from the interface is sent as a series of 4-bit numbers, some of which are paired to form 8-bit displacements. In the program above these values are read into a table (mouse_space) before being analysed. The below routine uses this fact to detect the mouse: mouse_detect ld hl,(xcoord) ; Calling mouse_scan will push hl ; update the coords - use ld a,(ycoord) ; these lines to preserve push af ; initial coords. call mouse_scan ; Clear the internal ; registers of the interface ; by requesting a scan. ; Any previous movements of ; the mouse are discarded. xor a ld (mouse),a ; Reset the mouse flag and ld (mouse_space+7),a ; empty the last byte of ; scan table. call mouse_scan ; Scan the registers. ld a,(mouse_space+7) ; Have a look at the last and 15 ; table value. jr nz,md_end ; If it isn't zero there is ; no mouse connected, so ; leave the mouse flag at ; zero. inc a ; Otherwise, set it to one. ld (mouse),a md_end pop af ; Restore the previous ld (ycoord),a ; coords. You would want this pop hl ; to produce some consistency ld (xcoord),hl ; if you were changing from ret ; keyboard/joystick control ; with a cursor on screen. ; Otherwise the cursor would ; jump due to any previous ; moves of the mouse. mouse db 0 ; 0=mouse off, 1=on I hope this explains the way the mouse works and will help you all add to your user-friendliness (and your programs' user-friendliness too!) Right, now to that fan letter (!). MICHAEL NICHOLAS has written to me from Lichfield, Staffordshire with a request for some info on music in m/c. "I've been using the ports 255 and 511 and can't set 28,1 or 20,63 propally." (his spelling, not mine - he must have Tasword too!) Okay, now I'm not a musician by any stretch of the imagination, but I had to write interrupt driven music routines for Triltex and The Viking Game (extra plugs!), so I'll show you the way I solved the problems. This is the routine for the sound effects which are played just like music - some foriegn geezer whose name I can hardly remember, never mind pronounce or spell, is doing the music and has his own more complex routines, but since this is meant to be a column for beginners I'll keep it simple. music push af ; preserve registers push bc push hl ld a,(sound_on) ; have a flag to switch and a ; sound on and off. jr z,music_end ld a,(music_count) ; only play notes so many dec a ; 50ths of a sec. jr z,m1 ld (music_count),a jr music_end m1 ld a,(tempo) ; restore music count ld (music_count),a ld hl,(music_pos) ld bc,511 ld a,(hl) inc hl cp 28 jr c,music_code ; any value >28 must be a out (c),a ; code dec b ld a,(hl) inc hl ld a,(hl) out (c),a inc b jr m2 music_code cp 40 ; use whatever codes you jr z,end_of_notes ; want cp 41 jr z,music_loop xor a ; any other code means ld (sound_on),a ; switch the sound off call sound_clear music_end pop hl pop bc pop af ret end_of_notes ld (music_pos),hl ; finish this set oo notes jr music_end ; and return music_loop ld hl,(music_start); loop round to the ld (music_pos),hl ; beginning of the tune. jr music_end sound_on db 1 ; You could have a tune music_count db tempo ; selection routine to set up tempo db 2 ; all these values. music_pos dw music_start ; music_start dw #8000 ; sound_clear push bc ; a useful routine to clear push de ; the sound chip - all ld bc,511 ; registers except f are ld de,31 ; preserved sc1 out (c),e dec b out (c),d inc b dec e jr nz,sc1 out (c),e dec b out (c),d pop de pop bc ret Your music data is stored in blocks of notes which are played together - stored as register no, data value, register, data... and so on, ended by a value of 40 (or whatever else you want to define). To make the whole tune loop round end with 41: to switch off the sound and finish use 255. You can add any other codes you want. You would probably need a routine to page in music data, and to answer Michael's query, just put 28,1 and 20,63 as parts of the music data (at the start). This means you can switch off sound half way through too, or whatever.