Fixed bug where script module wasn't beeing freed when wandering (or teleporting) for a long time on the wilderness map.

This commit is contained in:
Martin Haye 2018-04-08 10:08:50 -07:00
parent 4964220863
commit 1e9813ba2a
7 changed files with 71 additions and 35 deletions

View File

@ -1176,7 +1176,7 @@ class A2PackPartitions
if (!new File(scriptDir).exists()) if (!new File(scriptDir).exists())
new File(scriptDir).mkdirs() new File(scriptDir).mkdirs()
ScriptModule module = new ScriptModule() 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] : [], mapEl.scripts ? mapEl.scripts[0] : [],
totalWidth, totalHeight, xRange, yRange) totalWidth, totalHeight, xRange, yRange)
replaceIfDiff(scriptDir + name + ".pla") 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 * Pack scripts from a map. Either the whole map, or optionally just an X and Y
* bounded section of it. * 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) startScriptFile(outFile)
@ -3997,7 +3997,7 @@ end
// Always generate outer initialization code, because even if there were no scripts, // Always generate outer initialization code, because even if there were no scripts,
// we still need an init to display the map name. // 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() out.close()
} }
@ -4845,12 +4845,12 @@ end
out << "byte = \$FF\n\n" 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. // Code to register the map name, trigger table, and map extent.
def shortName = mapName.replaceAll(/[\s-]*[23][dD][-0-9]*$/, '').take(16) def shortName = mapName.replaceAll(/[\s-]*[23][dD][-0-9]*$/, '').take(16)
def timeFunc = timeScript ? "@${scriptNames[timeScript]}" : "NULL" 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 // Call init script if one was defined
if (initScript) if (initScript)

View File

@ -1164,12 +1164,23 @@ grabSegment: !zone
; Input: None ; Input: None
; Output: Y-reg = segment grabbed ; Output: Y-reg = segment grabbed
; Note: Does not disturb X reg ; Note: Does not disturb X reg
ldy unusedSeg ; first unused segment lda #1 ; if we run out, we will try one reclaim
beq .fail ; ran out? sta .reclaimFlg
.try ldy unusedSeg ; first unused segment
beq .many ; ran out?
lda tSegLink,y ; no, grab next segment in list lda tSegLink,y ; no, grab next segment in list
sta unusedSeg ; that is now first unused sta unusedSeg ; that is now first unused
rts ; return with Y = the segment grabbed 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 .fail: jsr inlineFatal : !text "MaxSegs", 0
.reclaimFlg !byte 0
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
releaseSegment: !zone releaseSegment: !zone
@ -1302,6 +1313,9 @@ dispatch:
+ cmp #QUEUE_LOAD + cmp #QUEUE_LOAD
bne + bne +
jmp mem_queueLoad jmp mem_queueLoad
+ cmp #FIND_IN_MEM
bne +
jmp mem_find
+ cmp #LOCK_MEMORY + cmp #LOCK_MEMORY
bne + bne +
jmp mem_lock jmp mem_lock
@ -1791,6 +1805,11 @@ mem_calcFree: !zone
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
mem_queueLoad: !zone mem_queueLoad: !zone
clc
!byte $A5 ; to skip next instructon
mem_find:
sec
ror .findonly
stx resType ; save resource type stx resType ; save resource type
sty resNum ; save resource number sty resNum ; save resource number
cpx #RES_TYPE_MODULE ; loading a module? cpx #RES_TYPE_MODULE ; loading a module?
@ -1822,6 +1841,8 @@ mem_queueLoad: !zone
sta tSegRes,x sta tSegRes,x
; fall through to re-load the resource ; fall through to re-load the resource
.notFound: .notFound:
bit .findonly
bmi .nullret
ldx resType ; restore res type ldx resType ; restore res type
ldy resNum ; and number ldy resNum ; and number
lda #QUEUE_LOAD ; set to re-try same operation lda #QUEUE_LOAD ; set to re-try same operation
@ -1837,12 +1858,18 @@ mem_queueLoad: !zone
ora #$80 ; reactivate bytecode if necessary ora #$80 ; reactivate bytecode if necessary
sta tSegType,y sta tSegType,y
bne .found ; (always taken) we have both parts -- no need for fixups 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 ; 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 ; 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 ; 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 ; is a very bad thing (fixups should not be cumulative). So we force both parts out
; of memory before proceeding. ; of memory before proceeding.
.reload jsr .scanForBytecode .reload bit .findonly
bmi .nullret
jsr .scanForBytecode
jsr .forceFree ; if bytecode without module, forcibly free it jsr .forceFree ; if bytecode without module, forcibly free it
jsr .scanForModule jsr .scanForModule
jsr .forceFree ; if module without bytecode, forcibly free it jsr .forceFree ; if module without bytecode, forcibly free it
@ -1883,6 +1910,7 @@ mem_queueLoad: !zone
+ lda #0 + lda #0
sta tSegType,x ; force reload so fixup works right sta tSegType,x ; force reload so fixup works right
++ rts ++ rts
.findonly !byte 0
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
diskLoader: !zone diskLoader: !zone

View File

@ -339,20 +339,15 @@ ADVANCE_ANIMS = $1C
; or main) are processed. ; or main) are processed.
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
CHAIN_LOADER = $1E FIND_IN_MEM = $1D
; Input: X-reg / Y-reg - pointer to loader (X=lo, Y=hi) to add to chain ; 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 ; If the given resource is present in memory, mark it as active and return
; loader (if there is one) will be passed to the new loader with another ; its address. Otherwise returns 0000.
; 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.
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
FATAL_ERROR = $1F FATAL_ERROR = $1F
; Input: X-reg(lo) / Y-reg(hi): message pointer. Message can be: ; Input: X-reg(lo) / Y-reg(hi): message pointer. Message can be:

View File

@ -120,7 +120,7 @@ import gamelib
predef useMapWindow()#0 predef useMapWindow()#0
predef setBigWindow()#0 predef setBigWindow()#0
predef setPortrait(portraitNum)#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 setSky(num)#0
predef setStat(player, statName, val)#0 predef setStat(player, statName, val)#0
predef setWindow(top, bottom, left, right)#0 predef setWindow(top, bottom, left, right)#0

View File

@ -95,6 +95,9 @@ byte textClearCountdown = 0
export byte isPlural = 0 // valid values: 0 or $40 export byte isPlural = 0 // valid values: 0 or $40
byte inScript = FALSE byte inScript = FALSE
byte scriptModule = 0
byte prevScriptModule = 0
export word skyNum = 9 export word skyNum = 9
export word groundNum = 10 export word groundNum = 10
export byte portraitNum = 0 export byte portraitNum = 0
@ -2627,17 +2630,14 @@ end
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
// Get a key and dispatch it to a command. Then do it again, forever. // Get a key and dispatch it to a command. Then do it again, forever.
def kbdLoop()#0 def kbdLoop()#0
word key, func word key, func, tmp
byte xreg, tmp byte xreg
xreg = getXReg() xreg = getXReg()
while TRUE while TRUE
// If the asm routines all work correctly, by the time we get to the top of this loop // 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. // the X register should always have the same value.
tmp = getXReg() tmp = getXReg()
if tmp <> xreg if tmp <> xreg; printHex(xreg<<8 | tmp); fatal("xRegChg"); fin
printHex(xreg<<8 | tmp)
fatal("xRegChg")
fin
key = getUpperKey() key = getUpperKey()
if key >= 0 and key < $60 if key >= 0 and key < $60
func = cmdTbl[key] func = cmdTbl[key]
@ -2649,12 +2649,14 @@ def kbdLoop()#0
func() func()
fin fin
fin fin
if q_mapNum if q_mapNum; setMap(q_mapIs3D, q_mapNum, q_x, q_y, q_dir); q_mapNum = 0; fin
setMap(q_mapIs3D, q_mapNum, q_x, q_y, q_dir) if needRender; doRender(); fin
q_mapNum = 0 if prevScriptModule
fin if prevScriptModule <> scriptModule
if needRender tmp = mmgr(FIND_IN_MEM, prevScriptModule<<8 | RES_TYPE_MODULE)
doRender() if tmp; mmgr(FREE_MEMORY, tmp); fin
fin
prevScriptModule = 0
fin fin
loop loop
end 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 // 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. // 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 // Record the time event function, if any
timeEventFunc = timeFn 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) // Grab the trigger table origins (used so the table can be more compact)
triggerOriginX = trigTbl=>0 triggerOriginX = trigTbl=>0
triggerOriginY = trigTbl=>2 triggerOriginY = trigTbl=>2

View File

@ -61,7 +61,7 @@ const CALC_FREE = $19
const DEBUG_MEM = $1A const DEBUG_MEM = $1A
const CHECK_MEM = $1B const CHECK_MEM = $1B
const ADVANCE_ANIMS = $1C const ADVANCE_ANIMS = $1C
const CHAIN_LOADER = $1E const FIND_IN_MEM = $1D
const FATAL_ERROR = $1F const FATAL_ERROR = $1F
const HEAP_SET = $20 const HEAP_SET = $20
const HEAP_ADD_TYPE = $21 const HEAP_ADD_TYPE = $21

View File

@ -88,6 +88,8 @@ def kbdTeleport()#1
dir = getDir() dir = getDir()
printf3("Current: X=%d Y=%d Facing=%d\n", x, y, dir) printf3("Current: X=%d Y=%d Facing=%d\n", x, y, dir)
d3 = mapIs3D
num = mapNum
printf1("3D [%d]: ", mapIs3D) printf1("3D [%d]: ", mapIs3D)
d3 = parseDecWithDefault(readStr(), mapIs3D) d3 = parseDecWithDefault(readStr(), mapIs3D)
if d3 > 1; d3 = 1; fin if d3 > 1; d3 = 1; fin