diff --git a/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy b/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy index c94a8dfd..b08625da 100644 --- a/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy +++ b/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy @@ -1176,7 +1176,7 @@ class A2PackPartitions if (!new File(scriptDir).exists()) new File(scriptDir).mkdirs() ScriptModule module = new ScriptModule() - module.packMapScripts(mapName, new File(new File(scriptDir), name+".pla.new"), + module.packMapScripts(mapName, num, new File(new File(scriptDir), name+".pla.new"), mapEl.scripts ? mapEl.scripts[0] : [], totalWidth, totalHeight, xRange, yRange) replaceIfDiff(scriptDir + name + ".pla") @@ -3960,7 +3960,7 @@ end * Pack scripts from a map. Either the whole map, or optionally just an X and Y * bounded section of it. */ - def packMapScripts(mapName, outFile, inScripts, maxX, maxY, xRange = null, yRange = null) + def packMapScripts(mapName, moduleNum, outFile, inScripts, maxX, maxY, xRange = null, yRange = null) { startScriptFile(outFile) @@ -3997,7 +3997,7 @@ end // Always generate outer initialization code, because even if there were no scripts, // we still need an init to display the map name. - makeInit(mapName, initScript, timeScript, maxX, maxY) + makeInit(mapName, moduleNum, initScript, timeScript, maxX, maxY) out.close() } @@ -4845,12 +4845,12 @@ end out << "byte = \$FF\n\n" } - def makeInit(mapName, initScript, timeScript, maxX, maxY) + def makeInit(mapName, moduleNum, initScript, timeScript, maxX, maxY) { // Code to register the map name, trigger table, and map extent. def shortName = mapName.replaceAll(/[\s-]*[23][dD][-0-9]*$/, '').take(16) def timeFunc = timeScript ? "@${scriptNames[timeScript]}" : "NULL" - out << "setScriptInfo(\"$shortName\", $timeFunc, @triggerTbl, $maxX, $maxY)\n" + out << "setScriptInfo(\"$shortName\", $moduleNum, $timeFunc, @triggerTbl, $maxX, $maxY)\n" // Call init script if one was defined if (initScript) diff --git a/Platform/Apple/virtual/src/core/mem.s b/Platform/Apple/virtual/src/core/mem.s index 95336a5b..e2af6e81 100644 --- a/Platform/Apple/virtual/src/core/mem.s +++ b/Platform/Apple/virtual/src/core/mem.s @@ -1164,12 +1164,23 @@ grabSegment: !zone ; Input: None ; Output: Y-reg = segment grabbed ; Note: Does not disturb X reg - ldy unusedSeg ; first unused segment - beq .fail ; ran out? + lda #1 ; if we run out, we will try one reclaim + sta .reclaimFlg +.try ldy unusedSeg ; first unused segment + beq .many ; ran out? lda tSegLink,y ; no, grab next segment in list sta unusedSeg ; that is now first unused rts ; return with Y = the segment grabbed +.many dec .reclaimFlg + bmi .fail + txa + pha + jsr reclaim + pla + tax + jmp .try .fail: jsr inlineFatal : !text "MaxSegs", 0 +.reclaimFlg !byte 0 ;------------------------------------------------------------------------------ releaseSegment: !zone @@ -1302,6 +1313,9 @@ dispatch: + cmp #QUEUE_LOAD bne + jmp mem_queueLoad ++ cmp #FIND_IN_MEM + bne + + jmp mem_find + cmp #LOCK_MEMORY bne + jmp mem_lock @@ -1791,6 +1805,11 @@ mem_calcFree: !zone ;------------------------------------------------------------------------------ mem_queueLoad: !zone + clc + !byte $A5 ; to skip next instructon +mem_find: + sec + ror .findonly stx resType ; save resource type sty resNum ; save resource number cpx #RES_TYPE_MODULE ; loading a module? @@ -1822,6 +1841,8 @@ mem_queueLoad: !zone sta tSegRes,x ; fall through to re-load the resource .notFound: + bit .findonly + bmi .nullret ldx resType ; restore res type ldy resNum ; and number lda #QUEUE_LOAD ; set to re-try same operation @@ -1837,12 +1858,18 @@ mem_queueLoad: !zone ora #$80 ; reactivate bytecode if necessary sta tSegType,y bne .found ; (always taken) we have both parts -- no need for fixups +.nullret + ldy #0 ; find-only mode, not found: return null + ldx #0 + rts ; The following is for the unusual situation where somehow we have the main memory ; part (the module) without the aux part (the bytecode). If we allowed that to go ; forward, we'd end up running fixups on both parts, and double-fixing-up the module ; is a very bad thing (fixups should not be cumulative). So we force both parts out ; of memory before proceeding. -.reload jsr .scanForBytecode +.reload bit .findonly + bmi .nullret + jsr .scanForBytecode jsr .forceFree ; if bytecode without module, forcibly free it jsr .scanForModule jsr .forceFree ; if module without bytecode, forcibly free it @@ -1883,6 +1910,7 @@ mem_queueLoad: !zone + lda #0 sta tSegType,x ; force reload so fixup works right ++ rts +.findonly !byte 0 ;------------------------------------------------------------------------------ diskLoader: !zone diff --git a/Platform/Apple/virtual/src/include/mem.i b/Platform/Apple/virtual/src/include/mem.i index 35fa1116..beca4b43 100644 --- a/Platform/Apple/virtual/src/include/mem.i +++ b/Platform/Apple/virtual/src/include/mem.i @@ -339,20 +339,15 @@ ADVANCE_ANIMS = $1C ; or main) are processed. ;------------------------------------------------------------------------------ -CHAIN_LOADER = $1E - ; Input: X-reg / Y-reg - pointer to loader (X=lo, Y=hi) to add to chain +FIND_IN_MEM = $1D + ; Input: X-reg - resource type + ; Y-reg - resource number ; - ; Output: None + ; Output: X-reg(lo) / Y-reg (hi) - address of resource, or NULL ; - ; Add a loader to the chain just after this loader. The current next - ; loader (if there is one) will be passed to the new loader with another - ; CHAIN_LOADER command. - ; - ; The purpose of a loader chain is to insert faster devices between the - ; main/aux loader (fastest) and the disk loader (slowest). Note that the - ; main mem and aux mem loaders are conceptually one; a chained loader will - ; always be inserted after them, not between them. - + ; If the given resource is present in memory, mark it as active and return + ; its address. Otherwise returns 0000. + ;------------------------------------------------------------------------------ FATAL_ERROR = $1F ; Input: X-reg(lo) / Y-reg(hi): message pointer. Message can be: diff --git a/Platform/Apple/virtual/src/plasma/gamelib.plh b/Platform/Apple/virtual/src/plasma/gamelib.plh index 59d9d98c..d8914909 100644 --- a/Platform/Apple/virtual/src/plasma/gamelib.plh +++ b/Platform/Apple/virtual/src/plasma/gamelib.plh @@ -120,7 +120,7 @@ import gamelib predef useMapWindow()#0 predef setBigWindow()#0 predef setPortrait(portraitNum)#0 - predef setScriptInfo(mapName, timeFunc, trigTbl, wdt, hgt)#0 + predef setScriptInfo(mapName, moduleNum, timeFunc, trigTbl, wdt, hgt)#0 predef setSky(num)#0 predef setStat(player, statName, val)#0 predef setWindow(top, bottom, left, right)#0 diff --git a/Platform/Apple/virtual/src/plasma/gameloop.pla b/Platform/Apple/virtual/src/plasma/gameloop.pla index 02a8559c..b6acad41 100644 --- a/Platform/Apple/virtual/src/plasma/gameloop.pla +++ b/Platform/Apple/virtual/src/plasma/gameloop.pla @@ -95,6 +95,9 @@ byte textClearCountdown = 0 export byte isPlural = 0 // valid values: 0 or $40 byte inScript = FALSE +byte scriptModule = 0 +byte prevScriptModule = 0 + export word skyNum = 9 export word groundNum = 10 export byte portraitNum = 0 @@ -2627,17 +2630,14 @@ end /////////////////////////////////////////////////////////////////////////////////////////////////// // Get a key and dispatch it to a command. Then do it again, forever. def kbdLoop()#0 - word key, func - byte xreg, tmp + word key, func, tmp + byte xreg xreg = getXReg() while TRUE // If the asm routines all work correctly, by the time we get to the top of this loop // the X register should always have the same value. tmp = getXReg() - if tmp <> xreg - printHex(xreg<<8 | tmp) - fatal("xRegChg") - fin + if tmp <> xreg; printHex(xreg<<8 | tmp); fatal("xRegChg"); fin key = getUpperKey() if key >= 0 and key < $60 func = cmdTbl[key] @@ -2649,12 +2649,14 @@ def kbdLoop()#0 func() fin fin - if q_mapNum - setMap(q_mapIs3D, q_mapNum, q_x, q_y, q_dir) - q_mapNum = 0 - fin - if needRender - doRender() + if q_mapNum; setMap(q_mapIs3D, q_mapNum, q_x, q_y, q_dir); q_mapNum = 0; fin + if needRender; doRender(); fin + if prevScriptModule + if prevScriptModule <> scriptModule + tmp = mmgr(FIND_IN_MEM, prevScriptModule<<8 | RES_TYPE_MODULE) + if tmp; mmgr(FREE_MEMORY, tmp); fin + fin + prevScriptModule = 0 fin loop end @@ -2681,11 +2683,20 @@ end /////////////////////////////////////////////////////////////////////////////////////////////////// // Set initial info for the scripts on this map: the name of the map, its trigger table, and the // maximum extent (width, height). This is called by the init function for the scripts. -export def setScriptInfo(mapName, timeFn, trigTbl, wdt, hgt)#0 +export def setScriptInfo(mapName, moduleNum, timeFn, trigTbl, wdt, hgt)#0 + word tmp // Record the time event function, if any timeEventFunc = timeFn + // Record new script, and prepare to free old one. While theoretically there could be a + // circumstance where the old prev is still un-freed, it's rare enough that it'd be hard to + // get freeing it here correct. So we leave freeing to the main keyboard loop. + if scriptModule <> moduleNum + prevScriptModule = scriptModule + scriptModule = moduleNum + fin + // Grab the trigger table origins (used so the table can be more compact) triggerOriginX = trigTbl=>0 triggerOriginY = trigTbl=>2 diff --git a/Platform/Apple/virtual/src/plasma/globalDefs.plh b/Platform/Apple/virtual/src/plasma/globalDefs.plh index 7cabb52c..dd5c8c3d 100644 --- a/Platform/Apple/virtual/src/plasma/globalDefs.plh +++ b/Platform/Apple/virtual/src/plasma/globalDefs.plh @@ -61,7 +61,7 @@ const CALC_FREE = $19 const DEBUG_MEM = $1A const CHECK_MEM = $1B const ADVANCE_ANIMS = $1C -const CHAIN_LOADER = $1E +const FIND_IN_MEM = $1D const FATAL_ERROR = $1F const HEAP_SET = $20 const HEAP_ADD_TYPE = $21 diff --git a/Platform/Apple/virtual/src/plasma/godmode.pla b/Platform/Apple/virtual/src/plasma/godmode.pla index cb5dc9c1..a4492382 100644 --- a/Platform/Apple/virtual/src/plasma/godmode.pla +++ b/Platform/Apple/virtual/src/plasma/godmode.pla @@ -88,6 +88,8 @@ def kbdTeleport()#1 dir = getDir() printf3("Current: X=%d Y=%d Facing=%d\n", x, y, dir) + d3 = mapIs3D + num = mapNum printf1("3D [%d]: ", mapIs3D) d3 = parseDecWithDefault(readStr(), mapIs3D) if d3 > 1; d3 = 1; fin