Expanded small-object heap to make more space for inventory. Started implementing pack size limits.

This commit is contained in:
Martin Haye 2017-09-12 08:21:23 -07:00
parent ea25619c78
commit 05d96b1243
12 changed files with 129 additions and 86 deletions

View File

@ -50,7 +50,7 @@ class A2PackPartitions
static final int FLOPPY_SIZE = 35*8 // good old 140k floppy = 280 blks static final int FLOPPY_SIZE = 35*8 // good old 140k floppy = 280 blks
static final int AC_KLUDGE = 2 // minus 1 to work around last-block bug in AppleCommander static final int AC_KLUDGE = 2 // minus 1 to work around last-block bug in AppleCommander
static final int DOS_OVERHEAD = 3 // only 3 blks overhead! ProRWTS is so freaking amazing. static final int DOS_OVERHEAD = 3 // only 3 blks overhead! ProRWTS is so freaking amazing.
static final int SAVE_GAME_SIZE = 7 // 6 blocks data, 1 block index static final int SAVE_GAME_SIZE = 10 // 9 blocks data, 1 block index
static final int MAX_DISKS = 20 // for now this should be way more than enough static final int MAX_DISKS = 20 // for now this should be way more than enough
def typeNumToName = [1: "Code", def typeNumToName = [1: "Code",
@ -2817,7 +2817,8 @@ end
"${parseByteAttr(row, "aiming")}, " + "${parseByteAttr(row, "aiming")}, " +
"${parseByteAttr(row, "hand-to-hand")}, " + "${parseByteAttr(row, "hand-to-hand")}, " +
"${parseByteAttr(row, "dodging")}, " + "${parseByteAttr(row, "dodging")}, " +
"${parseGenderAttr(row, "gender")})") "${parseGenderAttr(row, "gender")}, " +
"${parseByteAttr(row, "pack size")})")
row.attributes().sort().eachWithIndex { name, val, idx -> row.attributes().sort().eachWithIndex { name, val, idx ->
if (name =~ /^skill-(.*)/) { if (name =~ /^skill-(.*)/) {
out.println(" addToList(@p=>p_skills, " + out.println(" addToList(@p=>p_skills, " +
@ -3123,7 +3124,7 @@ def makePlayer_pt1(name, intelligence, strength, agility, stamina, charisma, spi
return p return p
end end
def makePlayer_pt2(p, health, level, aiming, handToHand, dodging, gender)#1 def makePlayer_pt2(p, health, level, aiming, handToHand, dodging, gender, packSize)#1
p=>w_health = health p=>w_health = health
p->b_level = level p->b_level = level
p=>w_maxHealth = health p=>w_maxHealth = health
@ -3133,6 +3134,13 @@ def makePlayer_pt2(p, health, level, aiming, handToHand, dodging, gender)#1
p->b_handToHand = handToHand p->b_handToHand = handToHand
p->b_dodging = dodging p->b_dodging = dodging
p->c_gender = gender p->c_gender = gender
if packSize
p->b_packSize = packSize
elsif global=>p_players
p->b_packSize = 15
else
p->b_packSize = 30
fin
initPlayerXP(p) initPlayerXP(p)
return p return p
end end
@ -3347,7 +3355,7 @@ end
else { else {
// Create empty save file // Create empty save file
newSave.withOutputStream { outStream -> newSave.withOutputStream { outStream ->
(0..3071).each { (0..(18*256 - 1)).each {
outStream.write( (byte) 0) outStream.write( (byte) 0)
} }
} }
@ -4198,7 +4206,7 @@ end
{ {
def name = getSingle(blk.field, "NAME").text().trim() def name = getSingle(blk.field, "NAME").text().trim()
assert itemNameToFunc.containsKey(name.toLowerCase()) : "Can't locate item '$name'" assert itemNameToFunc.containsKey(name.toLowerCase()) : "Can't locate item '$name'"
out << "playerHasItem(${escapeString(name)})" out << "partyHasItem(${escapeString(name)})"
} }
def packHasPlayer(blk) def packHasPlayer(blk)

View File

@ -212,7 +212,7 @@ init: !zone
; 5: main $2000 -> 6, active + locked ; 5: main $2000 -> 6, active + locked
; 6: main $6000 -> 7, inactive ; 6: main $6000 -> 7, inactive
; 7: main $BFFD -> 8, active + locked ; 7: main $BFFD -> 8, active + locked
; 8: main $E000 -> 9, inactive ; 8: main $DA00 -> 9, inactive
; 9: main $FFFA -> 0, active + locked ; 9: main $FFFA -> 0, active + locked
; First, the flags ; First, the flags
ldy #$C0 ; flags for active + locked (with no resource) ldy #$C0 ; flags for active + locked (with no resource)
@ -253,7 +253,7 @@ init: !zone
sta tSegAdrHi+5 sta tSegAdrHi+5
lda #$60 lda #$60
sta tSegAdrHi+6 sta tSegAdrHi+6
lda #$E0 lda #$DA
sta tSegAdrHi+8 sta tSegAdrHi+8
lda #$FA lda #$FA
sta tSegAdrLo+9 sta tSegAdrLo+9
@ -710,6 +710,25 @@ partFilename:
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; Heap management routines ; Heap management routines
;------------------------------------------------------------------------------
; Zero memory heapTop up to but not including $xx00 where XX is in A reg
heapClr: !zone
bit setLcRW+lcBank2 ; heap begins in bank 2
sta .cmp+1
lda #0
sta targetAddr+1 ; clear target addr now that we're done with heap top
ldx heapTop
ldy heapTop+1
.pg sty .st+2
.st sta $1000,x ; self-modified above
inx
bne .st
iny
.cmp cpy #11 ; self-modified above
bcc .pg
bit setLcRW+lcBank1 ; back to mmgr's bank
rts
; Check if blk pSrc is in GC hash; optionally add it if not. ; Check if blk pSrc is in GC hash; optionally add it if not.
; Input : pSrc = blk to check/add ; Input : pSrc = blk to check/add
; Carry set = add if not found, clear = check only, don't add ; Carry set = add if not found, clear = check only, don't add
@ -770,6 +789,7 @@ memCheck: !zone
heapCheck: !zone heapCheck: !zone
jsr startHeapScan jsr startHeapScan
.blklup bcc + ; if top-of-heap, we're done .blklup bcc + ; if top-of-heap, we're done
bit setLcRW+lcBank1 ; back to mmgr's bank
rts rts
+ bvs .isobj ; handle objects separately + bvs .isobj ; handle objects separately
; it's a string; check its characters ; it's a string; check its characters
@ -812,6 +832,7 @@ heapCorrupt:
; Begin a heap scan by setting pTmp to start-of-heap, then returns ; Begin a heap scan by setting pTmp to start-of-heap, then returns
; everything as per nextHeapBlk below ; everything as per nextHeapBlk below
startHeapScan: !zone startHeapScan: !zone
bit setLcRW+lcBank2 ; heap is in bank 2 (bulk of mmgr is in bnk 1)
lda #0 lda #0
ldx heapStartPg ldx heapStartPg
sta pDst ; used in gc2 sweep init sta pDst ; used in gc2 sweep init
@ -982,10 +1003,16 @@ heapCollect: !zone
lda nSegsQueued lda nSegsQueued
bne .unfin bne .unfin
jsr closePartFile jsr closePartFile
bit setLcRW+lcBank2 ; heap starts in bank 2
lda heapTop+1 ; save old heap top for end of later clear
pha
jsr gc1_mark ; mark reachable blocks jsr gc1_mark ; mark reachable blocks
jsr gc2_sweep ; sweep them into one place jsr gc2_sweep ; sweep them into one place
jsr gc3_fix ; adjust all pointers jsr gc3_fix ; adjust all pointers
jsr heapClr ; and clear newly freed space pla ; old heap top
clc
adc #1
jsr heapClr ; and clear newly freed space (switches back to bnk1 when done)
ldx heapTop ; return new top-of-heap in x=lo/y=hi ldx heapTop ; return new top-of-heap in x=lo/y=hi
ldy heapTop+1 ldy heapTop+1
rts rts
@ -995,6 +1022,7 @@ heapCollect: !zone
; And yes, type $80 is valid (conventionally used for the Global Object). ; And yes, type $80 is valid (conventionally used for the Global Object).
; And yes, string length $00 is valid (it's an empty string). ; And yes, string length $00 is valid (it's an empty string).
heapAlloc: !zone heapAlloc: !zone
bit setLcRW+lcBank2 ; heap starts in bank 2
lda heapTop lda heapTop
sta pSrc sta pSrc
lda heapTop+1 lda heapTop+1
@ -1014,6 +1042,7 @@ heapAlloc: !zone
+ sta heapTop + sta heapTop
sty heapTop+1 sty heapTop+1
retPSrc: retPSrc:
bit setLcRW+lcBank1 ; back to mmgr's bank
ldx pSrc ; return ptr in X=lo/Y=hi ldx pSrc ; return ptr in X=lo/Y=hi
ldy pSrc+1 ldy pSrc+1
rts rts
@ -1046,7 +1075,8 @@ heapIntern: !zone
.notfnd lda (pTmp),y ; get string length .notfnd lda (pTmp),y ; get string length
pha ; save it pha ; save it
tax tax
jsr heapAlloc ; make space for it jsr heapAlloc ; make space for it (switches to mmgr bank at end)
bit setLcRW+lcBank2 ; back to heap bank
pla ; string length back pla ; string length back
tax tax
inx ; add 1 to copy length byte also inx ; add 1 to copy length byte also
@ -1058,6 +1088,44 @@ heapIntern: !zone
bne .cplup bne .cplup
beq .found ; always taken beq .found ; always taken
;------------------------------------------------------------------------------
; Variables
targetAddr: !word 0
unusedSeg: !byte 0
scanStart: !byte 0, 1 ; main, aux
segNum: !byte 0
nextLdVec: jmp diskLoader
curPartition: !byte 0
partFileOpen: !byte 0
curMarkPos: !fill 4 ; really 3, but 1 extra to match ProRWTS needs
setMarkPos: !fill 3
nSegsQueued: !byte 0
bufferDigest: !fill 4
diskActState: !byte 0
floppyDrive: !byte 0
;------------------------------------------------------------------------------
; Heap management variables
MAX_TYPES = 12
nTypes !byte 0
typeTblL !fill MAX_TYPES
typeTblH !fill MAX_TYPES
typeLen !fill MAX_TYPES ; length does not include type byte
heapStartPg !byte 0
heapEndPg !byte 0
heapTop !word 0
gcHash_top !byte 0
lastLoMem = *
} ; end of !pseodupc $800
loMemEnd = *
;------------------------------------------------------------------------------
; The remainder of the code gets relocated up into the Language Card, bank 1.
hiMemBegin: !pseudopc $D000 {
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; Show or hide the disk activity icon (at the top of hi-res page 1). The icon consists of a 4x4 ; Show or hide the disk activity icon (at the top of hi-res page 1). The icon consists of a 4x4
; block of blue pixels surrounded by a black border. ; block of blue pixels surrounded by a black border.
@ -1089,44 +1157,6 @@ showDiskActivity: !zone
bne - bne -
.done rts .done rts
lastLoMem = *
} ; end of !pseodupc $800
loMemEnd = *
;------------------------------------------------------------------------------
; The remainder of the code gets relocated up into the Language Card, bank 1.
hiMemBegin: !pseudopc $D000 {
;------------------------------------------------------------------------------
; Variables
targetAddr: !word 0
unusedSeg: !byte 0
scanStart: !byte 0, 1 ; main, aux
segNum: !byte 0
nextLdVec: jmp diskLoader
curPartition: !byte 0
partFileOpen: !byte 0
curMarkPos: !fill 4 ; really 3, but 1 extra to match ProRWTS needs
setMarkPos: !fill 3
nSegsQueued: !byte 0
bufferDigest: !fill 4
diskActState: !byte 0
floppyDrive: !byte 0
;------------------------------------------------------------------------------
; Heap management variables
MAX_TYPES = 16
nTypes !byte 0
typeTblL !fill MAX_TYPES
typeTblH !fill MAX_TYPES
typeLen !fill MAX_TYPES ; length does not include type byte
heapStartPg !byte 0
heapEndPg !byte 0
heapTop !word 0
gcHash_top !byte 0
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
grabSegment: !zone grabSegment: !zone
; Input: None ; Input: None
@ -2557,7 +2587,7 @@ doAllFixups: !zone
glibBase !word $1111 glibBase !word $1111
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; More heap management routines ; More heap management routines (that don't need to actually access LC bank 2)
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; Establish a new heap ; Establish a new heap
@ -2587,21 +2617,8 @@ heapSet: !zone
ldy targetAddr ldy targetAddr
+ stx heapTop+1 ; set heap top + stx heapTop+1 ; set heap top
sty heapTop sty heapTop
; fall through to: lda heapEndPg
; Zero memory heapTop.heapEnd jmp heapClr ; clear out the new heap space
heapClr: !zone
lda #0
sta targetAddr+1 ; clear target addr now that we're done with heap top
ldx heapTop
ldy heapTop+1
.pg sty .st+2
.st sta $1000,x ; self-modified above
inx
bne .st
iny
cpy heapEndPg
bne .pg
rts
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; Set the table for the next type in order. Starts with type $80, then $81, etc. ; Set the table for the next type in order. Starts with type $80, then $81, etc.

View File

@ -27,7 +27,7 @@ const RWTS_DRV2 = $80
const RWTS_RDWRPART = (0<<8) const RWTS_RDWRPART = (0<<8)
const RWTS_OPENDIR = (1<<8) const RWTS_OPENDIR = (1<<8)
const LOAD_SAVE_BUF = $5000 const LOAD_SAVE_BUF = $4E00
// Exported functions go here. First a predef for each one, then a table with function pointers // Exported functions go here. First a predef for each one, then a table with function pointers
// in the same order as the constants are defined in the the header. // in the same order as the constants are defined in the the header.

View File

@ -77,10 +77,10 @@ import gamelib
predef numToPlayer(num)#1 predef numToPlayer(num)#1
predef parseDec(str)#1 predef parseDec(str)#1
predef partyHasPlayer(playerName)#1 predef partyHasPlayer(playerName)#1
predef partyHasItem(itemName)#1
predef pause(count)#0 predef pause(count)#0
predef payGold(amount)#1 predef payGold(amount)#1
predef percentToRatio(pct)#1 predef percentToRatio(pct)#1
predef playerHasItem(itemName)#1
predef printf1(fmt, arg1)#0 predef printf1(fmt, arg1)#0
predef printf2(fmt, arg1, arg2)#0 predef printf2(fmt, arg1, arg2)#0
predef printf3(fmt, arg1, arg2, arg3)#0 predef printf3(fmt, arg1, arg2, arg3)#0
@ -103,6 +103,7 @@ import gamelib
predef rollDice(encoded)#1 predef rollDice(encoded)#1
predef rollDiceWithLuck(encoded, luck)#1 predef rollDiceWithLuck(encoded, luck)#1
predef rollPercentileWithLuck(luck)#1 predef rollPercentileWithLuck(luck)#1
predef roomInPack(p_player)#1
predef scanForNamedObj(p_obj, name)#1 predef scanForNamedObj(p_obj, name)#1
predef scriptCombat(mapCode)#1 predef scriptCombat(mapCode)#1
predef scriptDisplayStr(str)#0 predef scriptDisplayStr(str)#0

View File

@ -141,6 +141,7 @@ export byte[] S_DODGING = "Dodging"
export byte[] S_GOLD = "Gold" export byte[] S_GOLD = "Gold"
export byte[] S_XP = "XP" export byte[] S_XP = "XP"
export byte[] S_SP = "SP" export byte[] S_SP = "SP"
export byte[] S_PACK_SIZE = "Pack size"
export byte[] S_ENTER = "Enter" export byte[] S_ENTER = "Enter"
export byte[] S_LEAVE = "Leave" export byte[] S_LEAVE = "Leave"
export byte[] S_USE = "Use" export byte[] S_USE = "Use"
@ -1431,7 +1432,7 @@ export def heapCollect()#0
word pct word pct
mmgr(CHECK_MEM, 0) mmgr(CHECK_MEM, 0)
global=>w_heapSize = mmgr(HEAP_COLLECT, 0) - HEAP_BOTTOM global=>w_heapSize = mmgr(HEAP_COLLECT, 0) - HEAP_BOTTOM
pct = min(99, max(0, ((global=>w_heapSize / 10) * 100) / 307)) pct = min(99, max(0, ((global=>w_heapSize / 10) * 100) / (HEAP_SIZE / 10)))
if pct <> curHeapPct if pct <> curHeapPct
curHeapPct = pct curHeapPct = pct
printHeapPct() printHeapPct()
@ -1518,10 +1519,12 @@ end
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
def clearTextWindow()#0 def clearTextWindow()#0
setWindow2(); clearWindow() if textDrawn or textClearCountdown
if mapIs3D and texturesLoaded; copyWindow(); fin setWindow2(); clearWindow()
textDrawn = FALSE if mapIs3D and texturesLoaded; copyWindow(); fin
textClearCountdown = 0 textDrawn = FALSE
textClearCountdown = 0
fin
end end
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
@ -2073,8 +2076,8 @@ def kbdLoop()#0
func = cmdTbl[key] func = cmdTbl[key]
if func if func
if textClearCountdown if textClearCountdown
if textClearCountdown == 1; clearTextWindow(); fin
textClearCountdown-- textClearCountdown--
if !textClearCountdown; clearTextWindow(); fin
fin fin
func() func()
fin fin
@ -2608,6 +2611,7 @@ def toggleGodMode()#1
flipToPage1() flipToPage1()
clearTextWindow() clearTextWindow()
displayf1("gm:%d\n", global->b_godmode & 1) displayf1("gm:%d\n", global->b_godmode & 1)
textDrawn = TRUE
beep; beep beep; beep
clearTextWindow() clearTextWindow()
saveMapPos(); restoreMapPos() // reload everything, including god module saveMapPos(); restoreMapPos() // reload everything, including god module
@ -2892,6 +2896,11 @@ export def createAndAddUnique(moduleID, creationFuncNum, pList)#1
return p_thing return p_thing
end end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def roomInPack(p_player)#1
return countList(p_player=>p_items) < p_player->b_packSize
end
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
export def giveItemToPlayer(p_player, itemFuncNum)#0 export def giveItemToPlayer(p_player, itemFuncNum)#0
createAndAddUnique(MOD_GEN_ITEMS, itemFuncNum, @p_player=>p_items) createAndAddUnique(MOD_GEN_ITEMS, itemFuncNum, @p_player=>p_items)
@ -2968,8 +2977,8 @@ export def addPlayerToParty(playerFuncNum)#0
beep beep
return return
fin fin
// Create the player (NPC flag will be established inside the creation func)
p = createAndAddUnique(MOD_GEN_PLAYERS, playerFuncNum, @global=>p_players) p = createAndAddUnique(MOD_GEN_PLAYERS, playerFuncNum, @global=>p_players)
p->b_playerFlags = p->b_playerFlags | PLAYER_FLAG_NPC
addXP(0) // to set initial skill pts addXP(0) // to set initial skill pts
needShowParty = TRUE needShowParty = TRUE
end end
@ -3010,8 +3019,14 @@ export def removePlayerFromParty(playerName)#0
end end
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
export def playerHasItem(itemName)#1 export def partyHasItem(itemName)#1
return scanForNamedObj(global=>p_players=>p_items, itemName) <> NULL word p_player
p_player = global=>p_players
while p_player
if scanForNamedObj(global=>p_players=>p_items, itemName) <> NULL; return TRUE; fin
p_player = p_player=>p_nextObj
loop
return FALSE
end end
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
@ -3038,6 +3053,7 @@ export def getStat(player, statName)#1
is streqi(statName, @S_GOLD); return global=>w_gold is streqi(statName, @S_GOLD); return global=>w_gold
is streqi(statName, @S_XP); return player=>w_curXP is streqi(statName, @S_XP); return player=>w_curXP
is streqi(statName, @S_SP); return player->b_skillPoints is streqi(statName, @S_SP); return player->b_skillPoints
is streqi(statName, @S_PACK_SIZE); return player->b_packSize
wend wend
pSkill = player=>p_skills pSkill = player=>p_skills
while pSkill while pSkill
@ -3078,7 +3094,8 @@ export def setStat(player, statName, val)#0
is streqi(statName, @S_DODGING); player->b_dodging = clampByte(val); break is streqi(statName, @S_DODGING); player->b_dodging = clampByte(val); break
is streqi(statName, @S_GOLD); global=>w_gold = max(0, val); needShowParty = TRUE; break is streqi(statName, @S_GOLD); global=>w_gold = max(0, val); needShowParty = TRUE; break
is streqi(statName, @S_XP); player=>w_curXP = max(player=>w_curXP, val); needShowParty = TRUE; break is streqi(statName, @S_XP); player=>w_curXP = max(player=>w_curXP, val); needShowParty = TRUE; break
is streqi(statName, @S_SP); player->b_skillPoints = max(0, val); needShowParty = TRUE; break is streqi(statName, @S_SP); player->b_skillPoints = clampByte(max(0, val)); needShowParty = TRUE; break
is streqi(statName, @S_PACK_SIZE); player->b_packSize = clampByte(max(player->b_packSize, val)); break
otherwise otherwise
pSkill = player=>p_skills pSkill = player=>p_skills
while pSkill while pSkill

View File

@ -69,8 +69,8 @@ const HEAP_INTERN = $23
const HEAP_COLLECT = $24 const HEAP_COLLECT = $24
// Heap location in memory // Heap location in memory
const HEAP_BOTTOM = $E000 const HEAP_BOTTOM = $DA00
const HEAP_SIZE = $C00 const HEAP_SIZE = $1200
// Event code // Event code
const EVENT_ENTER = 1 const EVENT_ENTER = 1

View File

@ -168,6 +168,7 @@ def showDerived(player)#0
rawDisplayf2("\n^T%D%s\n", STAT_X-5, "^I LEVEL UP ^N") rawDisplayf2("\n^T%D%s\n", STAT_X-5, "^I LEVEL UP ^N")
rawDisplayf2("^T%D%s\n", STAT_X-5+8, "in S)kills\n") rawDisplayf2("^T%D%s\n", STAT_X-5+8, "in S)kills\n")
fin fin
vspace()
rightJustifyNum(player=>w_curXP, STAT_X) rightJustifyNum(player=>w_curXP, STAT_X)
rawDisplayf2("^T%D%s\n", STATLBL_X, "Current XP") rawDisplayf2("^T%D%s\n", STATLBL_X, "Current XP")
rightJustifyNum(player=>w_nextXP, STAT_X) rightJustifyNum(player=>w_nextXP, STAT_X)
@ -202,9 +203,14 @@ def showDerived(player)#0
displayDice(dmg) displayDice(dmg)
rawDisplayf1("^T%DMelee\n", STATLBL_X) rawDisplayf1("^T%DMelee\n", STATLBL_X)
vspace()
rightJustifyStr(sprintf2("%d/%d", countList(player=>p_items), player->b_packSize), STAT_X)
rawDisplayf1("^T%DPack size\n", STATLBL_X)
vspace() vspace()
rightJustifyNum(global=>w_gold, STAT_X) rightJustifyNum(global=>w_gold, STAT_X)
rawDisplayf1("^T%DParty gold", STATLBL_X) rawDisplayf1("^T%DParty gold\n", STATLBL_X)
end end
def clearLittleArea(x, y)#0 def clearLittleArea(x, y)#0

View File

@ -80,7 +80,8 @@ struc Player
byte b_level byte b_level
word w_curXP word w_curXP
word w_nextXP word w_nextXP
word b_skillPoints byte b_skillPoints
byte b_packSize
// Lists // Lists
word p_skills // list:Modifier word p_skills // list:Modifier

View File

@ -254,13 +254,6 @@ def _buyFromStore(storeCode, profitPercent)#1
while TRUE while TRUE
if redisplay if redisplay
nItemsOnPage = displayBuyPage(pItemTbl, ratio, pageNum, nPages) nItemsOnPage = displayBuyPage(pItemTbl, ratio, pageNum, nPages)
flipToPage1 // FOO
^$c051
mmgr(DEBUG_MEM, 0)
rdkey
auxMmgr(DEBUG_MEM, 0)
rdkey
^$c050
fin fin
choice = getUpperKey() choice = getUpperKey()
redisplay = TRUE redisplay = TRUE