diff --git a/src/inc/fiber.plh b/src/inc/fiber.plh new file mode 100644 index 0000000..b19dea3 --- /dev/null +++ b/src/inc/fiber.plh @@ -0,0 +1,4 @@ +import fiber + predef fbrInit(numPool), fbrStop(fid)#0, fbrExit#0, fbrStart(defaddr, param) + predef fbrYield#0, fbrHalt#0, fbrResume(fid)#0 +end diff --git a/src/inc/portio.plh b/src/inc/portio.plh new file mode 100644 index 0000000..97d81ad --- /dev/null +++ b/src/inc/portio.plh @@ -0,0 +1,4 @@ +import portio + predef digitalRead(pin), portRead, digitalWrite(pin, val)#0 + predef portWrite(val)#0, analogRead(pin), delay(time)#0 +end diff --git a/src/inc/sndseq.plh b/src/inc/sndseq.plh new file mode 100644 index 0000000..61bfbbb --- /dev/null +++ b/src/inc/sndseq.plh @@ -0,0 +1,4 @@ +import sndseq + predef spkrTone(pitch, duration)#0, spkrPWM(sample, speed, len)#0 + predef musicPlay(track, rept)#0, musicStop#0, getKey(backgroundProc)#1 +end diff --git a/src/inc/spiport.plh b/src/inc/spiport.plh index 2488f82..730dfac 100644 --- a/src/inc/spiport.plh +++ b/src/inc/spiport.plh @@ -1,7 +1,27 @@ import spiport - const SPI_SLAVE_READY = '@' - const SPI_SLAVE_ERROR = '!' - const SPI_SLAVE_BUSY = $FF + // + // Wiring constants for Arduino + // + const PINHIGH = 1 + const PINLOW = 0 + const PINOUTPUT = 1 + const PININPUT = 0 + const PINPULLUP = 2 + // + // SPI commands to Wiring functions on Arduino + // + const CMDPINMODE = 3 + const CMDDIGREAD = 4 + const CMDDIGWRITE = 5 + const CMDANAREAD = 6 + const CMDANAWRITE = 7 + // + // SPI commands to serial functions on Arduino + // + const CMDSERMODE = 8 + const CMDSERAVAIL = 9 + const CMDSERREAD = 10 + const CMDSERWRITE = 11 predef spiXferByte(outbyte), spiSend(data), spiRecv, spiWriteBuf(buf, len), spiReadBuf(buf, len) predef spiDelay(time), spiReady end diff --git a/src/inc/wireio.plh b/src/inc/wireio.plh deleted file mode 100644 index 5bb3302..0000000 --- a/src/inc/wireio.plh +++ /dev/null @@ -1,23 +0,0 @@ -// -// Wiring constants for Arduino -// -const PINHIGH = 1 -const PINLOW = 0 -const PINOUTPUT = 1 -const PININPUT = 0 -const PINPULLUP = 2 -// -// SPI commands to Wiring functions on Arduino -// -const CMDPINMODE = 3 -const CMDDIGREAD = 4 -const CMDDIGWRITE = 5 -const CMDANAREAD = 6 -const CMDANAWRITE = 7 -// -// SPI commands to serial functions on Arduino -// -const CMDSERMODE = 8 -const CMDSERAVAIL = 9 -const CMDSERREAD = 10 -const CMDSERWRITE = 11 diff --git a/src/libsrc/fiber.pla b/src/libsrc/fiber.pla index 408c22b..85fe167 100644 --- a/src/libsrc/fiber.pla +++ b/src/libsrc/fiber.pla @@ -268,36 +268,3 @@ export def fbrResume(fid)#0 fin end done - -// -// Test Fiber library -// - -def puth(h)#0 - word valstr - - valstr = "0123456789ABCDEF" - valstr++ - putc('$') - putc(valstr->[(h >> 12) & $0F]) - putc(valstr->[(h >> 8) & $0F]) - putc(valstr->[(h >> 4) & $0F]) - putc(valstr->[ h & $0F]) -end - -def fbrTest(fid, param)#0 - byte i - - for i = 1 to param - puth(fid); putc($0D) - fbrYield - next -end - -//puts("fbrSwap = "); puth(@fbrSwap); putln -fbrInit(4) -fbrStart(@fbrTest, 3) -fbrStart(@fbrTest, 2) -fbrStart(@fbrTest, 1) -fbrYield; fbrYield; fbrYield; fbrYield -done diff --git a/src/libsrc/portio.pla b/src/libsrc/portio.pla index 2915cb8..31a818a 100644 --- a/src/libsrc/portio.pla +++ b/src/libsrc/portio.pla @@ -25,7 +25,7 @@ export def portRead return (^FLAG0>>7)&1|(^FLAG1>>6)&2|(^FLAG2>>5)&4|(^FLAG3>>4)&8 end -def digitalWrite(pin, val)#0 +export def digitalWrite(pin, val)#0 ANN0[((pin&3)<<1)+(val&1)] end diff --git a/src/libsrc/sndseq.pla b/src/libsrc/sndseq.pla new file mode 100755 index 0000000..deb6922 --- /dev/null +++ b/src/libsrc/sndseq.pla @@ -0,0 +1,838 @@ +include "inc/cmdsys.plh" +include "inc/fileio.plh" +include "inc/args.plh" +// +// Usage is documented following the source in this file... +// +const rndseed = $004E +const LSB = 0 +const MSB = 1 +const MB_ARPEGGIO = 4 // In 16ths of a second +const MAX_MBCH_NOTES = 9 +const SPKR_ARPEGGIO = 2 // In 16ths of a second +const DUR16TH = 8 +const MAX_SPKR_NOTES = 4 +const NOTEDIV = 4 +// +// 6522 VIA registers +// +struc t_VIA + byte IORB // I/O Register B + byte IORA // I/O Register A + byte DDRB // Data Direction Register B + byte DDRA // Data Direction Register A + word T1C // Timer 1 Count + word T1L // Timer 1 Latch + word T2C // Timer 2 Count + byte SR // Shift Register + byte ACR // Aux Control Register + byte PCR // Peripheral Control Register + byte IFR // Interrupt Flag Register + byte IER // Interrupt Enable Register + byte IOA_noHS // I/O Register A - no HandShake +end +const T1CH = T1C+1 +// +// AY-3-8910 PSG registers +// +struc t_PSG + word AFREQ // A Frequency Period + word BFREQ // B Frequency Period + word CFREQ // C Frequency Period + byte NGFREQ // Noise Generator Frequency Period + byte MIXER // Enable=0/Disable=1 NG C(5) B(4) A(3) Tone C(2) B(1) A(0) + byte AENVAMP // A Envelope/Amplitude + byte BENVAMP // B Envelope/Amplitude + byte CENVAMP // C Envelope/Amplitude + word ENVPERIOD // Envelope Period + byte ENVSHAPE // Envelope Shape +end +// +// Sequence event +// +struc t_event + byte deltatime // Event delta time in 4.4 seconds + byte percnote // Percussion:7==0 ? Pitch:4-0 : Octave:6-4,Note:3-0 + byte perchanvol // Percussion ? EnvDur:7-0 : Channel:7,Volume:3-0 +end +// +// Predef routines +// +predef musicPlay(track, rept)#0 +predef musicStop#0 +// +// Static sequencer values +// +word seqTrack, seqEvent, seqTime, eventTime, updateTime, musicSequence +byte numNotes, seqRepeat +byte indexA[2], indexB[2], indexC[2] +byte noteA[2], noteB[2], noteC[2] +word notes1[MAX_MBCH_NOTES], notes2[MAX_MBCH_NOTES] +word notes[2] = @notes1, @notes2 +word periods1[MAX_MBCH_NOTES], periods2[MAX_MBCH_NOTES] +word periods[2] = @periods1, @periods2 +// +// MockingBoard data. +// +word[] mbVIAs // Treat this as an array of VIA ptrs +word mbVIA1 = -1 // Init to "discover MockingBoard flag" value +word mbVIA2 = 0 +// +// Octave basis frequency periods (starting at MIDI note #12) +// Notes will be encoded as basis note (LSNibble) and octave (MSNibble)) +// +word[] spkrOctave0 // Overlay and scale mbOctave0 for speaker version +word[12] mbOctave0 = 3900, 3681, 3474, 3279, 3095, 2922, 2758, 2603, 2457, 2319, 2189, 2066 +word[5] arpeggioDuration = DUR16TH, DUR16TH, DUR16TH/2, DUR16TH/3, DUR16TH/4 +// +// Emulators are broken - they only activate the MockingBoard's 6522 Timer1 +// functionality when interrupts are enabled. This music sequencer is run +// in polling mode without the use of MockingBoard interrupts. To work around +// the emulators, MockingBoard interrupts are enabled, but the 6502 IRQs are +// disabled. NO INTERRUPTS ARE HANDLED WHEN PLAYING MUSIC! The previous state +// is restored between playing sequences. +// +asm vmincs + !SOURCE "vmsrc/plvmzp.inc" +end +asm getStatusReg#1 + PHP + PLA + DEX + STA ESTKL,X + LDA #$00 + STA ESTKH,X + RTS +end +asm setStatusReg(stat)#0 + LDA ESTKL,X + INX + PHA + PLP + RTS +end +asm disableInts#0 + SEI + RTS +end +asm enableInts#0 + CLI + RTS +end +// +// Write Programmable Sound Generator Registers +// +asm psgWriteTone(pVIA, reg, freq, vol)#0 + LDA ESTKL+3,X + STA TMPL + LDA ESTKH+3,X + STA TMPH + LDY #$01 + LDA ESTKL+2,X + LSR + ADC #$08 + STA (TMP),Y + DEY + LDA #$07 + STA (TMP),Y + LDA #$04 + STA (TMP),Y + LDA ESTKL,X + INY + STA (TMP),Y + DEY + LDA #$06 + STA (TMP),Y + LDA #$04 + STA (TMP),Y + INX + BNE + +end +asm psgWriteWord(pVIA, reg, val)#0 + LDA ESTKL+2,X + STA TMPL + LDA ESTKH+2,X + STA TMPH ++ LDY #$01 + TYA + CLC + ADC ESTKL+1,X + STA (TMP),Y + DEY + LDA #$07 + STA (TMP),Y + LDA #$04 + STA (TMP),Y + LDA ESTKH,X + INY + STA (TMP),Y + DEY + LDA #$06 + STA (TMP),Y + LDA #$04 + STA (TMP),Y + BNE + +end +asm psgWrite(pVIA, reg, val)#0 + LDA ESTKL+2,X + STA TMPL + LDA ESTKH+2,X + STA TMPH ++ LDY #$01 + LDA ESTKL+1,X + STA (TMP),Y + DEY + LDA #$07 + STA (TMP),Y + LDA #$04 + STA (TMP),Y + LDA ESTKL,X + INY + STA (TMP),Y + DEY + LDA #$06 + STA (TMP),Y + LDA #$04 + STA (TMP),Y + INX + INX + INX + RTS +end +// +// Apple II speaker tone generator routines +// +export asm spkrTone(pitch, duration)#0 + STX ESP + LDY ESTKH,X + LDA ESTKL,X + BEQ + + INY ++ STA DSTL + STY DSTH + LDY ESTKH+1,X + LDA ESTKL+1,X + BEQ + + INY ++ STA TMPL + STY TMPH + TAX + LDA #$FF + PHP + SEI +; +; Total loop count is 32 cycles, regardless of path taken +; +- NOP ; 2 + NOP ; 2 + BCS + ; 3 + ;--- + ;+7 = 12 (from BCS below) ++ +-- SEC ; 2 + DEX ; 2 + BNE ++ ; 2/3 + ;---- + ; 6/7 + + DEY ; 2 + BNE +++ ; 2/3 + ;---- + ;+4/5 = 10/11 + + BIT $C030 ; 4 + LDX TMPL ; 3 + LDY TMPH ; 3 + ;--- + ;+10 = 20 + +TONELP SBC #$01 ; 2 + BCS - ; 2/3 + ;---- + ; 4/5 + + DEC DSTL ; 5 + BNE -- ; 3 + ;---- + ;+8 = 12 + + DEC DSTH ; This sequence isn't accounted for + BNE -- ; since it is taken only in extreme cases + BEQ TONEXIT + +++ NOP ; 2 + NOP ; 2 + ;--- + ;+4 = 11 (from BNE above) + ++++ BIT $C000 ; 4 + BMI TONEXIT ; 2 + BPL TONELP ; 3 + ;--- + ;+9 = 20 +TONEXIT PLP + LDX ESP + INX + INX + RTS +end +export asm spkrPWM(sample, speed, len)#0 + STX ESP + LDY ESTKH,X + LDA ESTKL,X + BEQ + + INY ++ STY DSTH + STA DSTL + LDA ESTKL+2,X + STA SRCL + LDA ESTKH+2,X + STA SRCH + LDY ESTKL+1,X + INY + STY TMPL + LDY #$00 + PHP + SEI +- LDA (SRC),Y + SEC +-- LDX TMPL +--- DEX + BNE --- + SBC #$01 + BCS -- + BIT $C030 + INY + BNE + + INC SRCH ++ DEC DSTL + BNE - + DEC DSTH + BNE - + PLP + LDX ESP + INX + INX + INX + RTS +end +// +// Search slots for MockingBoard +// +def mbTicklePSG(pVIA) + pVIA->IER = $7F // Mask all interrupts + pVIA->ACR = $00 // Stop T1 countdown + pVIA->DDRB = $FF // Output enable port A and B + pVIA->DDRA = $FF + pVIA->IORA = $00 // Reset MockingBoard + if pVIA->IORA == $00 + pVIA->IORA = $04 // Inactive MockingBoard control lines + if pVIA->IORA == $04 + // + // At least we know we have some sort of R/W in the ROM + // address space. Most likely a MockingBoard or John Bell + // 6522 board. We will assume its a MockingBoard because + // emulators fail the following PSG read test. + // + //psgWriteWord(pVIA, 2, $DA7E) + //if mbReadP(pVIA, 2) == $7E and mbReadP(pVIA, 3) == $0A + return pVIA + //fin + fin + fin + return 0 +end +def mbSearch(slot) + if slot + mbVIA1 = mbTicklePSG($C000 + (slot << 8)) + if mbVIA1 + mbVIA2 = mbTicklePSG(mbVIA1 + $80) + return slot + fin + else + for slot = 1 to 7 + if slot == 3 or slot == 6 + continue + fin + mbVIA1 = mbTicklePSG($C000 + (slot << 8)) + if mbVIA1 + mbVIA2 = mbTicklePSG(mbVIA1 + $80) + return slot + fin + next + fin + return 0 +end +def psgSetup(pVIA)#0 + psgWrite(pVIA, MIXER, $3F) // Turn everything off + psgWrite(pVIA, AENVAMP, $00) + psgWrite(pVIA, BENVAMP, $00) + psgWrite(pVIA, CENVAMP, $10) + psgWrite(pVIA, NGFREQ, $01) + psgWriteWord(pVIA, ENVPERIOD, $0001) + psgWrite(pVIA, ENVSHAPE, $00) // Single decay + psgWriteWord(pVIA, AFREQ, $0000) // Fast response to update + psgWriteWord(pVIA, BFREQ, $0000) + psgWriteWord(pVIA, CFREQ, $0000) + psgWrite(pVIA, MIXER, $38) // Tone on C, B, A +end +// +// Sequence notes through MockingBoard +// +def mbSequence(yield, func)#0 + word period, n, yieldTime + byte note, volume, channel, i, overflow, status, quit + + // + // Reset oscillator table + // + indexA[0] = 0; indexA[1] = 0 + indexB[0] = 1; indexB[1] = 1 + indexC[0] = 2; indexC[1] = 2 + noteA[0] = 0; noteA[1] = 0 + noteB[0] = 0; noteB[1] = 0 + noteC[0] = 0; noteC[1] = 0 + // + // Get the PSGs ready + // + status = getStatusReg + disableInts + mbVIA1->ACR = $40 // Continuous T1 interrupts + mbVIA1=>T1L = $F9C2 // 16 Ints/sec + mbVIA1=>T1C = $F9C2 // 16 Ints/sec + mbVIA1->IFR = $40 // Clear interrupt + mbVIA1->IER = $C0 // Enable Timer1 interrupt + psgSetup(mbVIA1) + if mbVIA2; psgSetup(mbVIA2); fin + overflow = 0 + if yield and func + yieldTime = seqTime + yield + else + yieldTime = $7FFF + fin + updateTime = seqTime + quit = FALSE + repeat + while eventTime == seqTime + note = seqEvent->percnote + if note & $80 + // + // Note event + // + volume = seqEvent->perchanvol + channel = (volume & mbVIA2.LSB) >> 7 // Clever - mbVIA2.0 will be $80 if it exists + if volume & $0F + // + // Note on + // + for i = 0 to MAX_MBCH_NOTES-1 + // + // Look for available slot in active note table + // + if !notes[channel, i].LSB //or notes[channel, i] == note + break + fin + next + // + // Full note table, kick one out + // + if i == MAX_MBCH_NOTES + i = overflow + overflow = (overflow + 1) % MAX_MBCH_NOTES + else + numNotes++ + fin + notes[channel, i] = note | (volume << 8) + periods[channel, i] = mbOctave0[note & $0F] >> ((note >> 4) & $07) + else + // + // Note off + // + for i = 0 to MAX_MBCH_NOTES-1 + // + // Remove from active note table + // + if notes[channel, i].LSB == note + notes[channel, i] = 0 + numNotes-- + break + fin + next + fin + updateTime = seqTime + else + // + // Percussion event + // + period = seqEvent->perchanvol + if period + if (period & $80) + psgWrite(mbVIA1, MIXER, $1C) // NG on C, Tone on B, A + psgWrite(mbVIA1, CENVAMP, $10) + psgWrite(mbVIA1, ENVSHAPE, (note >> 4) & $04) + psgWrite(mbVIA1, NGFREQ, (note >> 1) & $1F) + psgWrite(mbVIA1, ENVPERIOD+1, period & $7F) + elsif mbVIA2 + psgWrite(mbVIA2, MIXER, $1C) // NG on C, Tone on B, A + psgWrite(mbVIA2, CENVAMP, $10) + psgWrite(mbVIA2, ENVSHAPE, (note >> 4) & $04) + psgWrite(mbVIA2, NGFREQ, (note >> 1) & $1F) + psgWrite(mbVIA2, ENVPERIOD+1, period) + fin + else + if seqRepeat + // + // Reset sequence + // + musicPlay(seqTrack, TRUE) + seqTime = -1 // Offset seqTime++ later + else + musicStop + fin + quit = TRUE // Exit out + break + fin + fin + // + // Next event + // + seqEvent = seqEvent + t_event + eventTime = seqEvent->deltatime + eventTime + loop + if updateTime <= seqTime + // + // Time slice active note tables (arpeggio) + // + for channel = 0 to 1 + // + // Multiplex oscillator A + // + i = indexA[channel] + repeat + i = (i + 3) % MAX_MBCH_NOTES + n = notes[channel, i] + if n // Non-zero volume + break + fin + until i == indexA[channel] + if n.LSB <> noteA[channel] + psgWriteTone(mbVIAs[channel], AFREQ, periods[channel, i], n.MSB) + noteA[channel] = n.LSB + indexA[channel] = i + fin + // + // Multiplex oscillator B + // + i = indexB[channel] + repeat + i = (i + 3) % MAX_MBCH_NOTES + n = notes[channel, i] + if n // Non-zero volume + break + fin + until i == indexB[channel] + if n.LSB <> noteB[channel] + psgWriteTone(mbVIAs[channel], BFREQ, periods[channel, i], n.MSB) + noteB[channel] = n.LSB + indexB[channel] = i + fin + // + // Multiplex oscillator C + // + i = indexC[channel] + repeat + i = (i + 3) % MAX_MBCH_NOTES + n = notes[channel, i] + if n // Non-zero volume + break + fin + until i == indexC[channel] + if n.LSB <> noteC[channel] + psgWrite(mbVIAs[channel], MIXER, $38) // Tone on C, B, A + psgWriteTone(mbVIAs[channel], CFREQ, periods[channel, i], n.MSB) + noteC[channel] = n.LSB + indexC[channel] = i + fin + next + updateTime = seqTime + MB_ARPEGGIO - (numNotes >> 2) + fin + // + // Increment time tick + // + seqTime++ + while !(mbVIA1->IFR & $40) // Wait for T1 interrupt + if ^$C000 > 127; quit = TRUE; break; fin + *rndseed++ + loop + mbVIA1->IFR = $40 // Clear interrupt + if yieldTime <= seqTime; func()#0; yieldTime = seqTime + yield; fin + until quit + psgWrite(mbVIA1, MIXER, $FF) // Turn everything off + psgWrite(mbVIA1, AENVAMP, $00) + psgWrite(mbVIA1, BENVAMP, $00) + psgWrite(mbVIA1, CENVAMP, $00) + if mbVIA2 + psgWrite(mbVIA2, MIXER, $FF) + psgWrite(mbVIA2, AENVAMP, $00) + psgWrite(mbVIA2, BENVAMP, $00) + psgWrite(mbVIA2, CENVAMP, $00) + fin + mbVIA1->ACR = $00 // Stop T1 countdown + mbVIA1->IER = $7F // Mask all interrupts + mbVIA1->IFR = $40 // Clear interrupt + setStatusReg(status)) +end +// +// Sequence notes through Apple II speaker +// +def spkrSequence(yield, func)#0 + word period, duration, yieldTime + byte note, i, n, overflow + + // + // Start sequencing + // + overflow = 0 + if yield and func + yieldTime = seqTime + yield + else + yieldTime = $7FFF + fin + updateTime = seqTime + repeat + while eventTime == seqTime + note = seqEvent->percnote + if note & $80 + // + // Note event + // + if seqEvent->perchanvol & $0F + // + // Note on + // + for i = 0 to MAX_SPKR_NOTES-1 + // + // Look for available slot in active note table + // + if !notes1[i] or note == notes1[i] + break + fin + next + if i == MAX_SPKR_NOTES + // + // Full note table, kick one out + // + overflow = (overflow + 1) & (MAX_SPKR_NOTES-1) + i = overflow + elsif !notes1[i] + // + // Add new note + // + numNotes++ + fin + notes1[i] = note + periods1[i] = spkrOctave0[note & $0F] >> ((note >> 4) & $07) + else + // + // Note off + // + for i = 0 to MAX_SPKR_NOTES-1 + // + // Remove from active note table + // + if notes1[i] == note + notes1[i] = 0 + numNotes-- + break + fin + next + fin + else + // + // Percussion event + // + if seqEvent->perchanvol + //spkrPWM($D000, 0, 64) // Play some random sample as percussion + else + if seqRepeat + musicPlay(seqTrack, TRUE) + else + musicStop + fin + return + fin + fin + // + // Next event + // + seqEvent = seqEvent + t_event + eventTime = eventTime + seqEvent->deltatime + loop + if numNotes > 1 + for i = 0 to MAX_SPKR_NOTES-1 + if notes1[i] + spkrTone(periods1[i], arpeggioDuration[numNotes]) + fin + *rndseed++ + next + seqTime++ + else + period = 0 + for i = 0 to MAX_SPKR_NOTES-1 + if notes1[i] + period = periods1[i] + break; + fin + *rndseed++ + next + duration = eventTime - seqTime + seqTime = duration + seqTime + spkrTone(period, DUR16TH * duration) + fin + if ^$C000 > 127; return; fin + if yieldTime <= seqTime; func()#0; yieldTime = seqTime + yield; fin + until FALSE +end +// +// No sequence, just waste time and yield +// +def noSequence(yield, func)#0 + // + // Start wasting time + // + if !yield or !func + yield = 0 + fin + seqTime = 0 + repeat + seqTime++ + if seqTime < 0; seqTime = 1; fin // Capture wrap-around + *rndseed++ + spkrTone(0, DUR16TH) // Waste 16th of a second playing silence + if ^$C000 > 127; return; fin + if yield == seqTime; func()#0; seqTime = 0; fin + until FALSE +end +// +// Start sequencing music track +// +export def musicPlay(track, rept)#0 + byte i + + // + // First time search for MockingBoard + // + if mbVIA1 == -1 + if !mbSearch(0) + // + // No MockingBoard - scale octave0 for speaker + // + for i = 0 to 11 + spkrOctave0[i] = mbOctave0[i]/NOTEDIV + next + fin + fin + // + // Zero out active notes + // + for i = 0 to MAX_MBCH_NOTES-1; notes1[i] = 0; notes2[i] = 0; next + for i = 0 to MAX_MBCH_NOTES-1; periods1[i] = 0; periods2[i] = 0; next + // + // Start sequencing + // + seqRepeat = rept + seqTrack = track + seqEvent = seqTrack + seqTime = 0 + eventTime = seqEvent->deltatime + numNotes = 0 + // + // Select proper sequencer based on hardware + // + if mbVIA1 + musicSequence = @mbSequence + else + musicSequence = @spkrSequence + fin +end +// +// Stop sequencing music track +// +export def musicStop#0 + musicSequence = @noSequence +end +// +// Get a keystroke and convert it to upper case +// +export def getKey(backgroundProc)#1 + byte key + + while ^$C000 < 128 + musicSequence($08, backgroundProc)#0 // Call background proc every half second + loop + key = ^$C000 & $7F + ^$C010 + return key +end +done + +//////////////////////////////////////////////////////////////////////////////// + +There are three main externally callable routines in this module: + +musicPlay(trackPtr, trackRepeat) + Start playing a track sequence in the getUpperKey routine + Params: + Pointer to a track sequence created from the cvtmidi.py tool + Repeat flag - TRUE or FALSE. + The first time its is called, it will try and search for a MockingBoard. + However, it is noted that this can cause problems if a Z-80 card is installed. + The scanning routine might cause a hang if it encounters a Z-80 card before + it finds a MockingBoard. In order to make this robust, it might be best to + prompt the user to search for the MockingBoard, enter the actual MockingBoard + slot, or skip the MockingBoard and use the internal speaker. + +musicStop() + Stop playing a track sequence in the getUpperKey routine + The getUpperKey routine will call a dummy sequence routine that will + keep the correct timing for any background processing + +getKey() + Wait for a keypress and return the character + While waiting for the keypress, the track sequence will be played though + either the MockingBoard (if present) or the internal speaker. Optionally, + a background function can be called periodically based on the sequencer + timing, so its pretty accurate. + +The low level internal speaker routines used to generate tones and waveforms +can be called for warnings, sound effects, etc: + +spkrTone(period, duration) + Play a tone + Params: + (1020000 / 64 / period) Hz + (duration * 32 * 256 / 1020000) seconds + +spkrPWM(samples, speed, len) + Play a Pulse Width Modulated waveform + Params: + Pointer to 8 bit pulse width samples + Speed to play through samples + Length of sample + +The main routines for sequencing music are: + +mbSequence(yield, func) +spkrSequence(yield, func) +noSequence(yield, func) + + All three try and provide more functionality than would be present in + previous music sequencers. The MockingBoard sequencer will attempt to play up + to 9 tones per sound generator (18 if a MockingBoard II is found). Up to + four notes will be played simultaneously on the internal speaker. In order + to play more notes than the hardware normally supports, a technique using + arpeggio (playing multiple notes in a quick sequence rather than concurrently) + pulls off this feat. The sequencers will immediately return if a keypress is + detected. Finally, during the sequencing, a background function can be periodically + called every 'yield' time which has a resolution of a 16th of a second. Pass + in zero for 'yield' and/or 'func' to disable any background calls. diff --git a/src/makefile b/src/makefile index 122c28c..90675c8 100755 --- a/src/makefile +++ b/src/makefile @@ -23,6 +23,8 @@ CONIO = CONIO\#FE1000 SANE = SANE\#FE1000 FPSTR = FPSTR\#FE1000 FPU = FPU\#FE1000 +SNDSEQ = SNDSEQ\#FE1000 +PLAYSEQ = PLAYSEQ\#FE1000 SANITY = SANITY\#FE1000 RPNCALC = RPNCALC\#FE1000 WIZNET = WIZNET\#FE1000 @@ -49,6 +51,7 @@ TESTLIB = TESTLIB\#FE1000 PROFILE = PROFILE\#FE1000 MEMMGR = MEMMGR\#FE1000 MEMTEST = MEMTEST\#FE1000 +FIBERTEST = FIBERTEST\#FE1000 FIBER = FIBER\#FE1000 LONGJMP = LONGJMP\#FE1000 PLASM = plasm @@ -72,7 +75,7 @@ TXTTYPE = .TXT #SYSTYPE = \#FF2000 #TXTTYPE = \#040000 -all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(LONGJMP) $(ED) $(MON) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1) $(TONE) $(DGR) $(DGRTEST) $(FILEIO) $(CONIO) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC) +all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(FIBERTEST) $(LONGJMP) $(ED) $(MON) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1) $(TONE) $(DGR) $(DGRTEST) $(FILEIO) $(CONIO) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC) $(SNDSEQ) $(PLAYSEQ) clean: -rm *FE1000 *FF2000 $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03) @@ -156,6 +159,18 @@ $(FIBER): libsrc/fiber.pla $(PLVM02) $(PLASM) ./$(PLASM) -AMOW < libsrc/fiber.pla > libsrc/fiber.a acme --setpc 4094 -o $(FIBER) libsrc/fiber.a +$(FIBERTEST): samplesrc/fibertest.pla $(PLVM02) $(PLASM) + ./$(PLASM) -AMOW < samplesrc/fibertest.pla > samplesrc/fibertest.a + acme --setpc 4094 -o $(FIBERTEST) samplesrc/fibertest.a + +$(SNDSEQ): libsrc/sndseq.pla $(PLVM02) $(PLASM) + ./$(PLASM) -AMOW < libsrc/sndseq.pla > libsrc/sndseq.a + acme --setpc 4094 -o $(SNDSEQ) libsrc/sndseq.a + +$(PLAYSEQ): samplesrc/playseq.pla $(PLVM02) $(PLASM) + ./$(PLASM) -AMOW < samplesrc/playseq.pla > samplesrc/playseq.a + acme --setpc 4094 -o $(PLAYSEQ) samplesrc/playseq.a + $(LONGJMP): libsrc/longjmp.pla $(PLVM02) $(PLASM) ./$(PLASM) -AMOW < libsrc/longjmp.pla > libsrc/longjmp.a acme --setpc 4094 -o $(LONGJMP) libsrc/longjmp.a diff --git a/src/mkrel b/src/mkrel new file mode 100755 index 0000000..ba20ee9 --- /dev/null +++ b/src/mkrel @@ -0,0 +1,88 @@ +cp CMD#FF2000 prodos/CMD.BIN +cp PLASMA.SYSTEM#FF2000 prodos/PLASMA.SYSTEM.SYS +cp PLASMA16.SYSTEM#FF2000 prodos/PLASMA16.SYSTEM.SYS + +mkdir prodos/sys +cp ARGS#FE1000 prodos/sys/ARGS.REL +cp CONIO#FE1000 prodos/sys/CONIO.REL +cp DGR#FE1000 prodos/sys/DGR.REL +cp DHCP#FE1000 prodos/sys/DHCP.REL +cp ED#FE1000 prodos/sys/ED.REL +cp ETHERIP#FE1000 prodos/sys/ETHERIP.REL +cp FIBER#FE1000 prodos/sys/FIBER.REL +cp FILEIO#FE1000 prodos/sys/FILEIO.REL +cp FPSTR#FE1000 prodos/sys/FPSTR.REL +cp FPU#FE1000 prodos/sys/FPU.REL +cp INET#FE1000 prodos/sys/INET.REL +cp LONGJMP#FE1000 prodos/sys/LONGJMP.REL +cp MEMMGR#FE1000 prodos/sys/MEMMGR.REL +cp PORTIO#FE1000 prodos/sys/PORTIO.REL +cp SANE#FE1000 prodos/sys/SANE.REL +cp SDFAT#FE1000 prodos/sys/SDFAT.REL +cp SPIPORT#FE1000 prodos/sys/SPIPORT.REL +cp SNDSEQ#FE1000 prodos/sys/SNDSEQ.REL +cp UTHERNET#FE1000 prodos/sys/UTHERNET.REL +cp UTHERNET2#FE1000 prodos/sys/UTHERNET2.REL +cp ../sysfiles/FP6502.CODE#060000 prodos/sys/FP6502.CODE.BIN +cp ../sysfiles/ELEMS.CODE#060000 prodos/sys/ELEMS.CODE.BIN + +mkdir prodos/demos +cp DGRTEST#FE1000 prodos/demos/DGRTEST.REL +cp RPNCALC#FE1000 prodos/demos/RPNCALC.REL +cp ROD#FE1000 prodos/demos/ROD.REL + +mkdir prodos/demos/rogue +cp ROGUE#FE1000 prodos/demos/rogue/ROGUE.REL +cp ROGUECOMBAT#FE1000 prodos/demos/rogue/ROGUECOMBAT.REL +cp ROGUEIO#FE1000 prodos/demos/rogue/ROGUEIO.REL +cp ROGUEMAP#FE1000 prodos/demos/rogue/ROGUEMAP.REL +cp samplesrc/LEVEL0#040000 prodos/demos/rogue/LEVEL0.TXT +cp samplesrc/LEVEL1#040000 prodos/demos/rogue/LEVEL1.TXT + +mkdir prodos/demos/sdutils +cp FATCAT#FE1000 prodos/demos/sdutils/FATCAT.REL +cp FATGET#FE1000 prodos/demos/sdutils/FATGET.REL +cp FATPUT#FE1000 prodos/demos/sdutils/FATPUT.REL +cp FATREADDSK#FE1000 prodos/demos/sdutils/FATREADDSK.REL +cp FATWRITEDSK#FE1000 prodos/demos/sdutils/FATWRITEDSK.REL + +mkdir prodos/demos/net +cp HTTPD#FE1000 prodos/demos/net/HTTPD.REL + +mkdir prodos/demos/music +cp PLAYSEQ#FE1000 prodos/demos/music/PLAYSEQ.REL +cp mockingboard/ultima3.seq prodos/demos/music/ULTIMA3.SEQ.BIN + +mkdir prodos/bld +cp PLASM#FE1000 prodos/bld/PLASM.REL +cp CODEOPT#FE1000 prodos/bld/CODEOPT.REL +cp samplesrc/dgrtest.pla prodos/bld/DGRTEST.PLA.TXT +cp samplesrc/hello.pla prodos/bld/HELLO.PLA.TXT +cp samplesrc/fibertest.pla prodos/bld/FIBERTEST.PLA.TXT +cp samplesrc/mon.pla prodos/bld/MON.PLA.TXT +cp samplesrc/memtest.pla prodos/bld/MEMTEST.PLA.TXT +cp samplesrc/rod.pla prodos/bld/ROD.PLA.TXT +cp samplesrc/sieve.pla prodos/bld/SIEVE.PLA.TXT +cp samplesrc/test.pla prodos/bld/TEST.PLA.TXT +cp samplesrc/testlib.pla prodos/bld/TESTLIB.PLA.TXT +cp samplesrc/playseq.pla prodos/bld/PLAYSEQ.PLA.TXT +cp samplesrc/rpncalc.pla prodos/bld/RPNCALC.PLA.TXT + +mkdir prodos/bld/inc +cp inc/args.plh prodos/bld/inc/ARGS.PLH.TXT +cp inc/cmdsys.plh prodos/bld/inc/CMDSYS.PLH.TXT +cp inc/conio.plh prodos/bld/inc/CONIO.PLH.TXT +cp inc/dgr.plh prodos/bld/inc/DGR.PLH.TXT +cp inc/fiber.plh prodos/bld/inc/FIBER.PLH.TXT +cp inc/fileio.plh prodos/bld/inc/FILEIO.PLH.TXT +cp inc/fpstr.plh prodos/bld/inc/FPSTR.PLH.TXT +cp inc/fpu.plh prodos/bld/inc/FPU.PLH.TXT +cp inc/inet.plh prodos/bld/inc/INET.PLH.TXT +cp inc/longjmp.plh prodos/bld/inc/LONGJMP.PLH.TXT +cp inc/memmgr.plh prodos/bld/inc/MEMMGR.PLH.TXT +cp inc/sane.plh prodos/bld/inc/SANE.PLH.TXT +cp inc/portio.plh prodos/bld/inc/PORTIO.PLH.TXT +cp inc/sdfat.plh prodos/bld/inc/SDFAT.PLH.TXT +cp inc/sndseq.plh prodos/bld/inc/SNDSEQ.PLH.TXT +cp inc/spiport.plh prodos/bld/inc/SPIPORT.PLH.TXT +cp inc/testlib.plh prodos/bld/inc/TESTLIB.PLH.TXT diff --git a/src/samplesrc/fibertest.pla b/src/samplesrc/fibertest.pla new file mode 100644 index 0000000..cc806aa --- /dev/null +++ b/src/samplesrc/fibertest.pla @@ -0,0 +1,24 @@ +// +// Test Fiber library +// + +include "inc/cmdsys.plh" +include "inc/fiber.plh" + +def fbrTest(fid, param)#0 + byte i + + for i = 1 to param + puth(fid); putc($0D) + fbrYield + next +end + +//puts("fbrSwap = "); puth(@fbrSwap); putln +fbrInit(4) +fbrStart(@fbrTest, 3) +fbrStart(@fbrTest, 2) +fbrStart(@fbrTest, 1) +fbrYield; fbrYield; fbrYield; fbrYield + +done diff --git a/src/samplesrc/playseq.pla b/src/samplesrc/playseq.pla new file mode 100644 index 0000000..c602b41 --- /dev/null +++ b/src/samplesrc/playseq.pla @@ -0,0 +1,39 @@ +include "inc/cmdsys.plh" +include "inc/args.plh" +include "inc/fileio.plh" +include "inc/sndseq.plh" + +/////////////////////////////////////////////////////////////////////////////// +// +// These are utility sequences/routines needed to test the music sequencer code. +// +word arg +word ref +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// More utility routines to test the getKey routine +// +// Sample background process +// +def backgroundProc#0 + ^$0400++ +end + +arg = argNext(argFirst) +if ^arg + ref = fileio:open(arg) + if ref + fileio:read(ref, heapmark(), heapavail()) + fileio:close(ref) + musicPlay(heapmark(), TRUE) + getKey(@backgroundProc) + musicStop + else + puts("File not found.\n") + fin +fin + +done +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/samplesrc/rogue.combat.pla b/src/samplesrc/rogue.combat.pla index e305891..3809663 100644 --- a/src/samplesrc/rogue.combat.pla +++ b/src/samplesrc/rogue.combat.pla @@ -1,7 +1,8 @@ include "inc/cmdsys.plh" +include "inc/conio.plh" import rogueio - word rnd, getkb, home, gotoxy, tone + word rnd, getkb, tone end import roguemap predef moveplayer @@ -138,28 +139,28 @@ export def fight(player, enemy) word p_atck, e_atck repeat - home() - gotoxy(0, 0) + conio:home() + conio:gotoxy(0, 0) puts(player+name) - gotoxy(1, 2) + conio:gotoxy(1, 2) puts("Skill :"); puti(player->skill) - gotoxy(1, 3) + conio:gotoxy(1, 3) puts("Health :"); puti(player->health) - gotoxy(1, 4) + conio:gotoxy(1, 4) puts("Energy :"); puti(player->energy) - gotoxy(20, 0) + conio:gotoxy(20, 0) puts(entity[enemy->kind]) - gotoxy(21, 2) + conio:gotoxy(21, 2) puts("Power :"); puti(enemy->power) - gotoxy(21, 3) + conio:gotoxy(21, 3) puts("Life :"); puti(enemy->life) for e_atck = 0 to 9 - gotoxy(0, 10 + e_atck) + conio:gotoxy(0, 10 + e_atck) puts(@ascii_warrior + e_atck * 11) - gotoxy(20, 10 + e_atck) + conio:gotoxy(20, 10 + e_atck) puts(ascii_entity[enemy->kind] + e_atck * 11) next - gotoxy(12, 8); puts("F)ight or R)un?") + conio:gotoxy(12, 8); puts("F)ight or R)un?") if toupper(getkb()) == 'R' return 1 else diff --git a/src/samplesrc/rogue.io.pla b/src/samplesrc/rogue.io.pla index ddf40e9..31b349a 100644 --- a/src/samplesrc/rogue.io.pla +++ b/src/samplesrc/rogue.io.pla @@ -1,7 +1,5 @@ include "inc/cmdsys.plh" - -const modkeep = $2000 -const modinitkeep = $4000 +include "inc/conio.plh" byte[] initstr byte = " ( )\n" @@ -22,10 +20,7 @@ word titlestr = @initstr // Machine specific routines // -export word rnd, getkb, home, gotoxy, tone -export word open, read, close, newline - -byte noapple1 = "APPLE 1 NOT SUPPORTED." +export word rnd, getkb, tone const ENV_REG = $FFDF @@ -35,8 +30,6 @@ const a2rndnum = $4E // ZP location of RND const a2rndl = $4E const a2rndh = $4F -word iobuff - word a3rndnum = 12345 def a3rnd @@ -60,7 +53,7 @@ def a2tone(duration, delay) ^SPEAKER for i = 0 to delay next - duration = duration - 1 + duration-- loop return 0 end @@ -75,183 +68,41 @@ def a3tone(duration, pitch) return 0 end -// -// ProDOS file routines -// - -def a2open(path, access) - byte params[6] - - params.0 = 3 - params:1 = path - params:3 = heapallocalign($0400, 8, @iobuff) - params.5 = 0 - syscall($C8, @params) - return params.5 -end -def a2close(refnum) - byte params[2] - - if iobuff - heaprelease(iobuff) - iobuff = 0 - fin - params.0 = 1 - params.1 = refnum - return syscall($CC, @params) -end -def a2read(refnum, buff, len) - byte params[8] - - params.0 = 4 - params.1 = refnum - params:2 = buff - params:4 = len - params:6 = 0 - syscall($CA, @params) - return params:6 -end -def a2newline(refnum, emask, nlchar) - byte params[4] - - params.0 = 3 - params.1 = refnum - params.2 = emask - params.3 = nlchar - return syscall($C9, @params) -end - -// -// SOS file routines -// - -def a3open(path, access) - byte params[7] - - params.0 = 4 - params:1 = path - params.3 = 0 - params:4 = @access - params.6 = 1 - syscall($C8, @params) - return params.3 -end -def a3close(refnum) - byte params[2] - - params.0 = 1 - params.1 = refnum - return syscall($CC, @params) -end -def a3read(refnum, buff, len) - byte params[8] - - params.0 = 4 - params.1 = refnum - params:2 = buff - params:4 = len - params:6 = 0 - syscall($CA, @params) - return params:6 -end -def a3newline(refnum, emask, nlchar) - byte params[4] - - params.0 = 3 - params.1 = refnum - params.2 = $FF - params.3 = nlchar - return syscall($C9, @params) -end - // // Apple /// console routines // -def dev_status(devnum, code, list) - byte params[5] - - params.0 = 3 - params.1 = devnum - params.2 = code - params:3 = list - return syscall($82, @params) -end -def a3keypressed - byte count - dev_status(cmdsys.devcons, 5, @count) - return count -end - def a3getkb - while not a3keypressed + while not conio:keypressed() a3rndnum = a3rndnum + 123 loop return getc() end -def a3home - putc(28) - return 0 -end - -def a3gotoxy(ch, cv) - putc(24) - putc(ch) - putc(25) - putc(cv) - return 0 -end - -// -// Apple ][ console routines -// - -def a2home - return call($FC58, 0, 0, 0, 0) // home() -end - -def a2gotoxy(x, y) - ^$24 = x + ^$20 - return call($FB5B, y + ^$22, 0, 0, 0) -end - // // Set machine specific routines // when MACHID & $C8 is $08 // Apple 1 - puts(@noapple1) + puts("APPLE 1 NOT SUPPORTED.") return -1 is $C0 // Apple /// rnd = @a3rnd getkb = @a3getkb - home = @a3home - gotoxy = @a3gotoxy tone = @a3tone - open = @a3open - read = @a3read - close = @a3close - newline = @a3newline break otherwise // Apple ][ rnd = @a2rnd getkb = @a2getkb - home = @a2home - gotoxy = @a2gotoxy tone = @a2tone - open = @a2open - read = @a2read - close = @a2close - newline = @a2newline wend // // Print title page // -home() +conio:home() while ^titlestr puts(titlestr) titlestr = titlestr + ^titlestr + 1 diff --git a/src/samplesrc/rogue.map.pla b/src/samplesrc/rogue.map.pla index 3010c68..0f33e2a 100644 --- a/src/samplesrc/rogue.map.pla +++ b/src/samplesrc/rogue.map.pla @@ -2,13 +2,15 @@ // Map module // include "inc/cmdsys.plh" +include "inc/conio.plh" +include "inc/fileio.plh" import rogueio const O_READ = 1 const O_WRITE = 2 const O_READ_WRITE = 3 - word rnd, getkb, home, gotoxy, tone, open, read, close, newline + word rnd, getkb, tone end // @@ -175,14 +177,14 @@ export def loadmap(level) // Set level map and read it // catacomb[catacomb] = '0' + level - mapref = open(@catacomb, O_READ) + mapref = fileio:open(@catacomb) if mapref - newline(mapref, $7F, $0D) + fileio:newline(mapref, $7F, $0D) for row = 1 to maprows - 2 - l = read(mapref, map + (row << 6) + 1, mapcols) + l = fileio:read(mapref, map + (row << 6) + 1, mapcols) ^(map + (row << 6) + l) = WALL_TILE next - close(mapref) + fileio:close(mapref) return TRUE fin return FALSE @@ -260,7 +262,7 @@ export def drawmap(xorg, yorg, viewfield, viewdir, lightdist, viewdist) // // Clear screen // - home() + conio:home() // // Draw background map if in light // @@ -302,96 +304,96 @@ export def drawmap(xorg, yorg, viewfield, viewdir, lightdist, viewdist) occluded = 1 when o & 7 is 0 - // - // Run through lit octant beam points - // + // + // Run through lit octant beam points + // for l = 1 to dbeam[lightdist] - // - // Check parent visiblity - // + // + // Check parent visiblity + // if vispix[vbeam[l]] imap = ((yorg - ybeam[l]) << rowshift) + xorg + xbeam[l] tile = ^(map + imap) if tile & OPAQUE_TILE - // - // The view stops here - // + // + // The view stops here + // vispix[l] = 0 else - // - // This tile is transparent - // + // + // This tile is transparent + // vispix[l] = 1 - // - // Check adjacent tile for opaqueness - improves wall display - // + // + // Check adjacent tile for opaqueness - improves wall display + // adjtile = ^(map + imap + 1) & INV_TILE if adjtile & OPAQUE_TILE ^(viewmap + imap + 1) = adjtile | VIEWED_TILE screen.[ycentr-ybeam[l], xcentr+xbeam[l]+1] = adjtile - fin + fin fin - // - // Update view - // + // + // Update view + // ^(viewmap + imap) = tile | VIEWED_TILE - if tile <> PIT_TILE + if tile <> PIT_TILE screen.[ycentr-ybeam[l], xcentr+xbeam[l]] = tile & INV_TILE - fin + fin else vispix[l] = 0 fin next - // - // Run through visible octant beam points - // + // + // Run through visible octant beam points + // for l = l to dbeam[viewdist] - // - // Check parent visiblity - // + // + // Check parent visiblity + // if vispix[vbeam[l]] imap = ((yorg - ybeam[l]) << rowshift) + xorg + xbeam[l] tile = ^(map + imap) if tile & OPAQUE_TILE - // - // The view stops here - // + // + // The view stops here + // vispix[l] = 0 else - // - // This tile is transparent - // + // + // This tile is transparent + // vispix[l] = 1 - occluded = 0 + occluded = 0 fin - // - // If the tile is in light, update view - // - if tile & LIT_TILE + // + // If the tile is in light, update view + // + if tile & LIT_TILE ^(viewmap + imap) = tile | VIEWED_TILE screen.[ycentr-ybeam[l], xcentr+xbeam[l]] = tile & INV_TILE darkness = 0 - fin + fin else vispix[l] = 0 fin - // - // Advance beam distance - // - if l == dbeam[dist] - if occluded // - // Beam fully occluded + // Advance beam distance // - break - fin - // - // Update distance - // + if l == dbeam[dist] + if occluded + // + // Beam fully occluded + // + break + fin + // + // Update distance + // occluded = 1 dist = dist + 1 - fin - next + fin + next break is 1 for l = 1 to dbeam[lightdist] diff --git a/src/samplesrc/rogue.pla b/src/samplesrc/rogue.pla index 5c2c2a5..7b2e58d 100755 --- a/src/samplesrc/rogue.pla +++ b/src/samplesrc/rogue.pla @@ -1,4 +1,5 @@ include "inc/cmdsys.plh" +include "inc/conio.plh" import roguemap const xcentr = 20 @@ -41,7 +42,7 @@ import roguecombat end import rogueio - word rnd, getkb, home, gotoxy, tone + word rnd, getkb, tone end const maxlight = 10 @@ -200,24 +201,24 @@ end // def status#0 - gotoxy(0, statusline) + conio:gotoxy(0, statusline) puts(@helthstr) puti(player.health) - gotoxy(9, statusline) + conio:gotoxy(9, statusline) puts(@enrgystr) puti(player.energy) - gotoxy(17, statusline) + conio:gotoxy(17, statusline) puts(@oilstr) puti(player:oil/10) - gotoxy(25, statusline) + conio:gotoxy(25, statusline) puts(@goldstr) puti(player.gold) if player.raft - gotoxy(32, statusline) + conio:gotoxy(32, statusline) puts(@raftstr) fin if player.key - gotoxy(36, statusline) + conio:gotoxy(36, statusline) puts(@keystr) fin end @@ -461,7 +462,7 @@ def play if player.health == 0 return FALSE fin - gotoxy(xcentr, ycentr) + conio:gotoxy(xcentr, ycentr) when toupper(getkb()) is 'I' if totaldarkness @@ -598,7 +599,7 @@ def play break is 'X' clearstatus - gotoxy(0, statusline) + conio:gotoxy(0, statusline) puts(@quitstr) if toupper(getkb()) == 'Y' player.health = 0 @@ -637,7 +638,7 @@ while loadmap(level) totaldarkness = drawmap(player.xpos, player.ypos, player.fov, player.angle, player.lamp, maxview) if not totaldarkness drawentities - gotoxy(xcentr, ycentr) + conio:gotoxy(xcentr, ycentr) putc(vplayer[player.angle]) fin status @@ -647,7 +648,7 @@ while loadmap(level) player.key = 0 level = level + 1 clearstatus - gotoxy(0, statusline) + conio:gotoxy(0, statusline) if player.health == 0 break fin