Now packing scripts for 2D map sections.

This commit is contained in:
Martin Haye 2015-02-19 10:44:17 -08:00
parent 2d06dc337a
commit 430ee9ce65
3 changed files with 120 additions and 47 deletions

View File

@ -400,7 +400,7 @@ class PackPartitions
buf.put((byte)0); buf.put((byte)0);
} }
def write2DMap(mapName, rows) def write2DMap(mapName, mapEl, rows)
{ {
def width = rows[0].size() def width = rows[0].size()
def height = rows.size() def height = rows.size()
@ -434,6 +434,11 @@ class PackPartitions
def (tileSetNum, tileMap) = packTileSet(rows, hOff, TILES_PER_ROW, vOff, ROWS_PER_SECTION) def (tileSetNum, tileMap) = packTileSet(rows, hOff, TILES_PER_ROW, vOff, ROWS_PER_SECTION)
def xRange = hOff ..< hOff+TILES_PER_ROW
def yRange = vOff ..< vOff+ROWS_PER_SECTION
def sectName = "$mapName-$hsect-$vsect"
def (scriptModule, locationsWithTriggers) = packScripts(mapEl, sectName, xRange, yRange)
// Header: first come links to other map sections // Header: first come links to other map sections
def buf = buffers[vsect][hsect] def buf = buffers[vsect][hsect]
buf.put((byte) (vsect > 0) ? sectionNums[vsect-1][hsect] : 0xFF) // north buf.put((byte) (vsect > 0) ? sectionNums[vsect-1][hsect] : 0xFF) // north
@ -443,7 +448,7 @@ class PackPartitions
// Then links to the tile set and script library // Then links to the tile set and script library
buf.put((byte) tileSetNum) buf.put((byte) tileSetNum)
buf.put((byte) 0xFF) // script library placeholder buf.put((byte) scriptModule)
// After the header comes the raw data // After the header comes the raw data
(0..<ROWS_PER_SECTION).each { rowNum -> (0..<ROWS_PER_SECTION).each { rowNum ->
@ -452,7 +457,8 @@ class PackPartitions
(0..<TILES_PER_ROW).each { colNum -> (0..<TILES_PER_ROW).each { colNum ->
def x = hOff + colNum def x = hOff + colNum
def tile = (row && x < width) ? row[x] : null def tile = (row && x < width) ? row[x] : null
buf.put((byte)(tile ? tileMap[tile.@id] : 0)) def flags = ([colNum, rowNum] in locationsWithTriggers) ? 0x20 : 0
buf.put((byte)((tile ? tileMap[tile.@id] : 0) | flags))
} }
} }
} }
@ -543,10 +549,6 @@ class PackPartitions
} }
} }
// Make a map of all the locations with triggers
def locMap = [:]
locationsWithTriggers.each { x,y -> locMap[[x,y]] = true }
// Header: width and height // Header: width and height
buf.put((byte)width) buf.put((byte)width)
buf.put((byte)height) buf.put((byte)height)
@ -573,7 +575,7 @@ class PackPartitions
buf.put((byte)0xFF) // sentinel at start of row buf.put((byte)0xFF) // sentinel at start of row
row.eachWithIndex { tile,x -> row.eachWithIndex { tile,x ->
// Mark scripted locations with a flag // Mark scripted locations with a flag
def flags = locMap.containsKey([x,y]) ? 0x20 : 0 def flags = ([x,y] in locationsWithTriggers) ? 0x20 : 0
buf.put((byte)texMap[tile?.@id] | flags) buf.put((byte)texMap[tile?.@id] | flags)
} }
buf.put((byte)0xFF) // sentinel at end of row buf.put((byte)0xFF) // sentinel at end of row
@ -762,7 +764,7 @@ class PackPartitions
def num = mapNames[name][1] def num = mapNames[name][1]
//println "Packing 2D map #$num named '$name'." //println "Packing 2D map #$num named '$name'."
def rows = parseMap(mapEl, tileEls) def rows = parseMap(mapEl, tileEls)
write2DMap(name, rows) write2DMap(name, mapEl, rows)
} }
def pack3DMap(mapEl, tileEls) def pack3DMap(mapEl, tileEls)
@ -779,15 +781,17 @@ class PackPartitions
} }
} }
def packScripts(mapEl, mapName) def packScripts(mapEl, mapName, xRange = null, yRange = null)
{ {
if (!mapEl.scripts) if (!mapEl.scripts)
return 0 return [0, [] as Set]
ScriptModule module = new ScriptModule() ScriptModule module = new ScriptModule()
module.packScripts(mapEl.scripts[0]) if (!module.packScripts(mapEl.scripts[0], xRange, yRange))
return [0, [] as Set]
def num = modules.size() + 1 def num = modules.size() + 1
def name = "mapScript$num" def name = "mapScript$num"
//println "Packing scripts for map $mapName, to module $num." println "Packing scripts for map $mapName, to module $num."
modules[name] = [num:num, buf:wrapByteList(module.data)] modules[name] = [num:num, buf:wrapByteList(module.data)]
bytecodes[name] = [num:num, buf:wrapByteList(module.bytecode)] bytecodes[name] = [num:num, buf:wrapByteList(module.bytecode)]
fixups[name] = [num:num, buf:wrapByteList(module.fixups)] fixups[name] = [num:num, buf:wrapByteList(module.fixups)]
@ -1325,7 +1329,7 @@ class PackPartitions
def nScripts = 0 def nScripts = 0
def locationsWithTriggers = [] def locationsWithTriggers = [] as Set
def vec_locationTrigger = 0x300 def vec_locationTrigger = 0x300
def vec_displayStr = 0x303 def vec_displayStr = 0x303
@ -1344,18 +1348,42 @@ class PackPartitions
return addr return addr
} }
def packScripts(scripts) /**
* Pack scripts from a map. Either the whole map, or optionally just an X and Y
* bounded section of it.
*
* Returns true if any matching scripts were found.
*/
def packScripts(inScripts, xRange = null, yRange = null)
{ {
// If we're only processing a section of the map, make sure this script is
// referenced within that section.
//
def scripts = []
inScripts.script.eachWithIndex { script, idx ->
def name = script.name[0].text()
if (name.toLowerCase() == "init")
scripts << script
else if (script.locationTrigger.any { trig ->
(!xRange || trig.@x.toInteger() in xRange) &&
(!yRange || trig.@y.toInteger() in yRange) })
scripts << script
}
nScripts = scripts.script.size() nScripts = scripts.script.size()
if (nScripts == 0)
return false
makeStubs() makeStubs()
scripts.script.eachWithIndex { script, idx -> scripts.eachWithIndex { script, idx ->
packScript(idx, script) packScript(idx, script)
} }
makeInit(scripts) makeInit(scripts, xRange, yRange)
emitFixupByte(0xFF) emitFixupByte(0xFF)
//println "data: $data" //println "data: $data"
//println "bytecode: $bytecode" //println "bytecode: $bytecode"
//println "fixups: $fixups" //println "fixups: $fixups"
return true
} }
def makeStubs() def makeStubs()
@ -1381,6 +1409,7 @@ class PackPartitions
def name = script.name[0].text() def name = script.name[0].text()
if (name.toLowerCase() == "init") // this special script gets processed later if (name.toLowerCase() == "init") // this special script gets processed later
return return
//println " Script '$name'" //println " Script '$name'"
withContext("script '$name'") withContext("script '$name'")
{ {
@ -1455,36 +1484,47 @@ class PackPartitions
def emitDataByte(b) def emitDataByte(b)
{ {
assert b <= 255
data.add((byte)(b & 0xFF)) data.add((byte)(b & 0xFF))
} }
def emitDataWord(w) def emitDataWord(w)
{ {
emitDataByte(w) emitDataByte(w & 0xFF)
emitDataByte(w >> 8) emitDataByte(w >> 8)
} }
def emitCodeByte(b) def emitCodeByte(b)
{ {
assert b <= 255
bytecode.add((byte)(b & 0xFF)) bytecode.add((byte)(b & 0xFF))
} }
def emitCodeWord(w) def emitCodeWord(w)
{ {
emitCodeByte(w) emitCodeByte(w & 0xFF)
emitCodeByte(w >> 8) emitCodeByte(w >> 8)
} }
def emitFixupByte(b) def emitFixupByte(b)
{ {
assert b <= 255
fixups.add((byte)(b & 0xFF)) fixups.add((byte)(b & 0xFF))
} }
def emitDataFixup(toAddr)
{
// Src addr is reversed (i.e. it's hi then lo)
emitFixupByte(dataAddr() >> 8)
emitFixupByte(dataAddr() & 0xFF)
emitDataWord(toAddr)
}
def emitCodeFixup(toAddr) def emitCodeFixup(toAddr)
{ {
// Src addr is reversed (i.e. it's hi then lo) // Src addr is reversed (i.e. it's hi then lo), and marked by hi-bit flag.
emitFixupByte((bytecodeAddr() >> 8) | 0x80) emitFixupByte((bytecodeAddr() >> 8) | 0x80)
emitFixupByte(bytecodeAddr()) emitFixupByte(bytecodeAddr() & 0xFF)
emitCodeWord(toAddr) emitCodeWord(toAddr)
} }
@ -1624,11 +1664,16 @@ class PackPartitions
emitCodeByte(0x30) // DROP emitCodeByte(0x30) // DROP
} }
def makeInit(scripts) def makeInit(scripts, xRange, yRange)
{ {
//println " Script: special 'init'" //println " Script: special 'init'"
startFunc(0) startFunc(0)
scripts.script.eachWithIndex { script, idx ->
// Emit the code the user has stored for the init script. While we're scanning,
// might as well also collate all the location triggers into a sorted map.
//
TreeMap triggers = [:]
scripts.eachWithIndex { script, idx ->
def name = script.name[0].text() def name = script.name[0].text()
if (name.toLowerCase() == "init") if (name.toLowerCase() == "init")
{ {
@ -1645,21 +1690,49 @@ class PackPartitions
script.locationTrigger.each { trig -> script.locationTrigger.each { trig ->
def x = trig.@x.toInteger() def x = trig.@x.toInteger()
def y = trig.@y.toInteger() def y = trig.@y.toInteger()
locationsWithTriggers.add([x,y]) if ((!xRange || x in xRange) && (!yRange || y in yRange))
emitCodeByte(0x2A) // CB {
assert x >= 0 && x < 255 if (xRange)
emitCodeByte(x) x -= xRange[0]
emitCodeByte(0x2A) // CB if (yRange)
assert y >= 0 && y < 255 y -= yRange[0]
emitCodeByte(y) if (!triggers[y])
triggers[y] = [:] as TreeMap
triggers[y][x] = (idx+1) * 5 // address of function
}
}
}
}
// If any triggers, register and output a trigger table
if (triggers.size())
{
println("Putting trigger table at ${dataAddr()}")
// Code to register the table
emitCodeByte(0x26) // LA emitCodeByte(0x26) // LA
emitCodeFixup((idx+1) * 5) emitCodeFixup(dataAddr())
emitCodeByte(0x54) // CALL emitCodeByte(0x54) // CALL
emitCodeWord(vec_locationTrigger) emitCodeWord(vec_locationTrigger)
emitCodeByte(0x30) // DROP emitCodeByte(0x30) // DROP
// The table itself goes in the data segment.
triggers.each { y, xs ->
println(" Trigger row: y=$y size=${xs.size()}")
emitDataByte(y)
emitDataByte(xs.size() * 3) // 3 bytes per trigger (x, adrlo, adrhi)
xs.each { x, funcAddr ->
println(" col: x=$x funcAddr=$funcAddr")
emitDataByte(x)
emitDataFixup(funcAddr)
// Record a list of trigger locations for the caller's reference
locationsWithTriggers << [x, y]
} }
} }
emitDataByte(0xFF) // mark the end end of the trigger table
} }
// All done with the init function.
finishFunc() finishFunc()
} }

View File

@ -1749,13 +1749,13 @@ doAllFixups: !zone
sta pDst+1 sta pDst+1
!if DEBUG >= 2 { jsr .debug2 } !if DEBUG >= 2 { jsr .debug2 }
clc clc
jsr .adMain jsr .adMain ; recalc and store lo byte
iny iny
jsr .adMain jsr .adMain ; recalc and store hi byte
bne .proc ; always taken bne .proc ; always taken
.adMain lda (pDst),y .adMain lda (pDst),y ; get num to add to offset
adc .mainBase,y adc .mainBase,y ; add the offset
sta (pDst),y sta (pDst),y ; *STORE* back the result
rts rts
.fxAux cmp #$FF ; end of fixups? .fxAux cmp #$FF ; end of fixups?
beq .stubs ; if so, go do the stubs beq .stubs ; if so, go do the stubs
@ -1769,14 +1769,14 @@ doAllFixups: !zone
sta pDst+1 sta pDst+1
!if DEBUG >= 2 { jsr .debug3 } !if DEBUG >= 2 { jsr .debug3 }
sta setAuxWr sta setAuxWr
jsr .adAux jsr .adAux ; recalc and store lo byte
iny iny
jsr .adAux jsr .adAux ; recalc and store hi byte
sta clrAuxWr sta clrAuxWr
bne .proc ; always taken bne .proc ; always taken
.adAux jsr .getBytecode .adAux jsr .getBytecode ; get num to add to offset
adc .mainBase,y adc .mainBase,y ; add the offset
sta (pDst),y sta (pDst),y ; *STORE* back the result
rts rts
.stubs ; fix up the stubs .stubs ; fix up the stubs
lda .mainBase lda .mainBase

View File

@ -207,9 +207,9 @@ LOAD_TILESET
; (Returns Tile # in Y, Flags in A) ; (Returns Tile # in Y, Flags in A)
; Each tile in memory can be 0-32, the flags are the upper 3 bits ; Each tile in memory can be 0-32, the flags are the upper 3 bits
; 0 0 0 ; 0 0 0
; | | `- Script assigned, triggers script lookup ; | | `- Visible obstruction (Can not see behind it)
; | `--- Boundary (Can not walk on it) ; | `--- Boundary (Can not walk on it)
; `----- Visible obstruction (Can not see behind it) ; `----- Script assigned, triggers script lookup
;---------------------------------------------------------------------- ;----------------------------------------------------------------------
; >> SET X,Y COORDINATES FOR VIEWPORT CENTER ; >> SET X,Y COORDINATES FOR VIEWPORT CENTER
SET_XY SET_XY