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())
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)

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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