Added sound generator, and a godmode tester for it.

This commit is contained in:
Martin Haye 2021-10-10 09:30:40 -07:00
parent 8851d88415
commit e6aae21937
8 changed files with 204 additions and 13 deletions

View File

@ -2432,6 +2432,7 @@ class A2PackPartitions
assembleCode("fontEngine", "src/font/")
assembleCode("tileEngine", "src/tile/")
assembleCode("marks", "src/marks/")
assembleCode("sound", "src/sound/")
assembleCode("gen_mapSpecials", "src/mapScripts/")
assembleCode("gen_mapExits", "src/mapScripts/")

View File

@ -0,0 +1,12 @@
;****************************************************************************************
; Copyright (C) 2021 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
; (the "License"); you may not use this file except in compliance with the License.
; You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
; Unless required by applicable law or agreed to in writing, software distributed under
; the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
; ANY KIND, either express or implied. See the License for the specific language
; governing permissions and limitations under the License.
;****************************************************************************************
; in main LC, bank 1
genSound = $FF80

View File

@ -1448,8 +1448,6 @@ def _combat_zoneEncounter(s_encZone)#1
is TYPE_ENEMY
if enemyCombatTurn(p); combatPause(); fin
break
otherwise
brk()
wend
fin
p = p=>p_combatNext

View File

@ -22,6 +22,8 @@ const fontEngine = $EC00 // main mem LC
const fontEngineLen = $F00 // really a bit less, but this leaves space for debug code
const fontData = $FB00 // main mem LC
const fontDataLen = $4FA // really only $474, but we need to fill all gaps
const soundCode = $FF80 // main mem LC
const soundLen = $7A // FF80.FFF9
const expandVec = $200 // aux mem (only for raycaster)
const expandMax = $3600 // max size of unsplit expander
@ -179,13 +181,14 @@ end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Load and display the title screen, set up everything in memory
def _startup()#1
word pEngine, pFont, pMarks, pExpand, expanderSize
word pEngine, pFont, pMarks, pExpand, expanderSize, pSound
puts("Loading game.\n")
auxMmgr(FREE_MEMORY, $800) // was temporarily reserved by gameloop to keep diskops bytecode out
// Allocate and permanently lock mem for the font engine and its font (up in LC ram)
// Also we can load the sound generator now.
mmgr(START_LOAD, 1) // partition 1 is where code lives
mmgr(SET_MEM_TARGET, fontEngine)
mmgr(REQUEST_MEMORY, fontEngineLen)
@ -198,6 +201,7 @@ def _startup()#1
// Load them into lo mem
pEngine = mmgr(QUEUE_LOAD, CODE_FONT_ENGINE<<8 | RES_TYPE_CODE)
pFont = mmgr(QUEUE_LOAD, 1<<8 | RES_TYPE_FONT)
pSound = mmgr(QUEUE_LOAD, CODE_SOUND<<8 | RES_TYPE_CODE)
mmgr(FINISH_LOAD, 0)
// Relocate font engine and font data to their final spots up in the language card
@ -207,7 +211,11 @@ def _startup()#1
// Tell the font engine where to find its font
setFont(fontData)
// Relocate the sound routine to its proper place
memcpy(pSound, soundCode, soundLen, 0)
// Load the title screen and show it.
pResourceIndex = 0 // special case - can't load resourceIndex yet because future expander
loadFrameImg(1) // title screen is fixed at #1
^$C050 // graphics
^$C057 // hi-res
@ -247,6 +255,7 @@ def _startup()#1
mmgr(FREE_MEMORY, pExpand)
// To reduce fragmentation, load the resource index in the lowest possible aux mem spot.
// Note: this has to be done after the expander, since it temporarily uses this space.
pResourceIndex = $800
auxMmgr(SET_MEM_TARGET, pResourceIndex)
auxMmgr(QUEUE_LOAD, CODE_RESOURCE_INDEX<<8 | RES_TYPE_CODE)

View File

@ -24,7 +24,6 @@ import gamelib
predef beep()#0
predef benchPlayer()#0
predef blit(isAux, srcData, dstScreenPtr, nLines, lineSize)#0
predef brk()#0
predef buildString()#0
predef buySell(storeCode, profitRatio)#0
predef calcPlayerArmor(player)#0
@ -33,6 +32,7 @@ import gamelib
predef callProRWTS(cmdPlusOpenFlg, filename, addr, size)#1
predef charToUpper(c)#1
predef checkEncounter(x, y, force)#0
predef clampByte(val)#1
predef clearEncounterZones()#0
predef clearPortrait()#0
predef clearWindow()#0
@ -58,6 +58,7 @@ import gamelib
predef forEach(p, do)#0
predef forSome(p, sel, do)#0
predef fullAddItem(pItem, doit)#1
predef genSound(dnnoise, dnvelo, dndelay, upnoise, upvelo, updelay, negdur)#0
predef getCharResponse()#1
predef getCursor()#2
predef getDir()#1

View File

@ -220,6 +220,7 @@ asm _defs
!source "../../include/plasma.i"
!source "../../include/mem.i"
!source "../../include/fontEngine.i"
!source "../../include/sound.i"
!source "../../include/prorwts.i"
; Optional debug printing support
@ -826,11 +827,10 @@ asm getFloppyFlg()#1
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Execute a monitor breakpoint
export asm brk()#0
bit setText
bit page1
brk
// Generate a sound on the Apple II speaker
export asm genSound(dnnoise, dnvelo, dndelay, upnoise, upvelo, updelay, dur)#0
+asmPlasmNoRet 7
jmp genSound
end
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -1703,6 +1703,9 @@ export def lookupResourcePart(sectionNum, resourceNum)#1
word ptr
byte n, i
// Special case: main frame img laods before resource index
if !pResourceIndex; return 1; fin
// Skip to the requested section (starting just after version num)
ptr = pResourceIndex
while sectionNum > 0
@ -1712,7 +1715,7 @@ export def lookupResourcePart(sectionNum, resourceNum)#1
// And grab the number from that section's table
n = readAuxByte(ptr)
if resourceNum > n; fatal("lkupFail1"); fin
if resourceNum > n; fatal("lkup1"); fin
n = readAuxByte(ptr + resourceNum)
// If resource is on the current map's disk, prefer that
@ -2088,7 +2091,7 @@ def initMap(x, y, dir)#0
// Load the map
curMapPartition = lookupResourcePart(mapIs3D+1, mapNum)
if !curMapPartition; fatal("lkupFail2"); fin
if !curMapPartition; fatal("lkup2"); fin
mmgr(START_LOAD, curMapPartition)
pCurMap = mmgr(QUEUE_LOAD, mapNum<<8 | (RES_TYPE_2D_MAP+mapIs3D))
mmgr(FINISH_LOAD, 0)
@ -2721,7 +2724,7 @@ export def setPortrait(portraitNum)#0
// Load the portrait image and display it
part = lookupResourcePart(3, portraitNum)
if !part; fatal("lkupFail2"); fin
if !part; fatal("lkup3"); fin
// Commented out below, because it prevents cycling thru all portraits (in god mode)
// NO: if part > 1; part = curMapPartition; fin // Look on disk 1 or current disk only
mmgr(START_LOAD, part)
@ -3201,6 +3204,7 @@ def initCmds()#0
cmdTbl['G'] = @cheatCmd // next ground
cmdTbl['&'] = @printMem // print mem
cmdTbl['^'] = @cheatCmd // edit flags
cmdTbl['*'] = @cheatCmd // soundGen test
fin
// Commands handled differently in 3D vs 2D
@ -3555,7 +3559,7 @@ export def hisHerTheir(gender)#1
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def clampByte(val)#1
export def clampByte(val)#1
return max(0, min(255, val))
end

View File

@ -25,6 +25,8 @@ predef _addItem()#1
predef _addPlayer()#1
word[] funcTbl = @_cheatCmd, @_addItem, @_addPlayer
predef parseDecWithDefault(str, default)#1
asm _defs
; Use hi-bit ASCII for Apple II
@ -59,6 +61,49 @@ asm readStr()#1
rts
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def testSoundGen()#0
word pStr, n, dur, updelay, upvelo, upnoise, dndelay, dnvelo, dnnoise, print
^$C051; ^$C054
updelay = 0
upvelo = 0
dndelay = 0
dnvelo = 0
upnoise = 0
dnnoise = 0
dur = 1000
print = TRUE
while TRUE
if print
puts("\n")
printf3("Up: A:dly=%d B:velo=%d C:noise=%d\n", updelay, upvelo, upnoise)
printf3("Dn: D:dly=%d E:velo=%d F:noise=%d\n", dndelay, dnvelo, dnnoise)
printf1("Dur: G=%d\n", dur)
fin
puts("Noise cmd, e.g. 50G: ")
pStr = readStr()
if ^pStr >= 2
print = TRUE
n = parseDec(pStr)
when charToUpper(^(pStr + ^pStr))
is 'A'; updelay = n; break
is 'B'; upvelo = n; break
is 'C'; upnoise = clampByte(n); break
is 'D'; dndelay = n; break
is 'E'; dnvelo = n; break
is 'F'; dnnoise = clampByte(n); break
is 'G'; dur = n; break
otherwise
puts("Error.\n")
wend
else
print = FALSE
^$25 = ^$25 - 1
fin
genSound(dnnoise, dnvelo, dndelay, upnoise, upvelo, updelay, dur)
loop
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def parseDecWithDefault(str, default)#1
if ^str == 0
@ -221,6 +266,7 @@ def _cheatCmd(key)#1
is 'Y'; nextSky(); break
is 'G'; nextGround(); break
is '^'; editFlags(); break
is '*'; testSoundGen(); break
otherwise fatal("gmcmd")
wend
return 0

View File

@ -0,0 +1,120 @@
;****************************************************************************************
; Copyright (C) 2021 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
; (the "License"); you may not use this file except in compliance with the License.
; You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
; Unless required by applicable law or agreed to in writing, software distributed under
; the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
; ANY KIND, either express or implied. See the License for the specific language
; governing permissions and limitations under the License.
;****************************************************************************************
; Use hi-bit ASCII for Apple II
!convtab "../include/hiBitAscii.ct"
; Global definitions
!source "../include/global.i"
!source "../include/mem.i"
!source "../include/sound.i"
!source "../include/plasma.i"
* = genSound
; hardware
spkr = $C030
; init
doGenSound:
!zone {
; stack offsets
.o_delay = 0
.o_velo = 1
.o_noise = 2
; variables
.negdur = $2 ; 2 bytes
.upx = $4
.dnx = $5
.pbits = $6 ; 2 bytes
.rnd = $8
eor #$FF
sta .negdur
tya
eor #$FF
sta .negdur+1
inx
stx .upx
inx
inx
inx
stx .dnx
lda #$EC
sta .pbits+1
ldy #0
sty .pbits ; 28 bytes
.cycle:
sta spkr
lda .o_velo+evalStkL,x
clc
adc .o_delay+evalStkL,x
sta .o_delay+evalStkL,x
lda .o_velo+evalStkH,x
adc .o_delay+evalStkH,x
pha
ror ; carry out from the addition...
eor .o_velo+evalStkH,x ; ... should match sign of the velocity
asl ; stach match status in carry
pla
bcc + ; if match, accept the result...
lda .o_delay+evalStkH,x ; ... else over/underflow occurred; revert.
+ sta .o_delay+evalStkH,x
sec
- sbc #1
pha
pla
pha
pla
bcs -
.calcnoise:
lda .rnd
asl ; cute trick: asl + adc #0 is a lossless rotate that also clears carry
adc (.pbits),y
sta .rnd
dey
bne .npause
inc .pbits+1
bne +
ldy #$EC
sty .pbits+1
+ ldy #$FF
.npause:
and .o_noise+evalStkL,x
sec
- sbc #1
pha
pla
pha
pla
bcs -
.flip
cpx .dnx
ldx .upx
bcs +
ldx .dnx
+
.nextdur:
inc .negdur
bne .cycle
inc .negdur+1
bne .cycle
stop:
rts
}