More 2d work: tileset division, show avatar in center, fix load bug.

This commit is contained in:
Martin Haye 2015-02-16 16:18:00 -08:00
parent 17d8c6d082
commit 792b8854ac
4 changed files with 184 additions and 62 deletions

View File

@ -400,7 +400,7 @@ class PackPartitions
buf.put((byte)0);
}
def write2DMap(mapName, rows, tileSetNum, tileMap)
def write2DMap(mapName, rows)
{
def width = rows[0].size()
def height = rows.size()
@ -428,21 +428,23 @@ class PackPartitions
(0..<nVertSections).each { vsect ->
(0..<nHorzSections).each { hsect ->
def hOff = hsect * TILES_PER_ROW
def vOff = vsect * ROWS_PER_SECTION
// Header: first come links to other map sections - north, east, south, west
def (tileSetNum, tileMap) = packTileSet(rows, hOff, TILES_PER_ROW, vOff, ROWS_PER_SECTION)
// Header: first come links to other map sections
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
buf.put((byte) (hsect < nHorzSections-1) ? sectionNums[vsect][hsect+1] : 0xFF) // east
buf.put((byte) (vsect < nVertSections-1) ? sectionNums[vsect+1][hsect] : 0xFF) // south
buf.put((byte) (hsect > 0) ? sectionNums[vsect][hsect-1] : 0xFF) // west
buf.put((byte) (hsect > 0) ? sectionNums[vsect][hsect-1] : 0xFF) // west
// Then links to the tile set and script library
buf.put((byte) tileSetNum)
buf.put((byte) 0xFF) // script library placeholder
def hOff = hsect * TILES_PER_ROW
def vOff = vsect * ROWS_PER_SECTION
// After the header comes the raw data
(0..<ROWS_PER_SECTION).each { rowNum ->
def y = vOff + rowNum
@ -653,31 +655,104 @@ class PackPartitions
tiles[imgEl.@id] = buf
}
def packTileSet(rows)
/** Pack the global tiles, like the player avatar, into their own tile set. */
def packGlobalTileSet(dataIn)
{
def setNum = tileSets.size() + 1
def setName = "tileSet${setNum}"
def tileMap = [null:0]
assert setNum == 1 : "Special tile set must be first."
def setName = "tileSet_special"
def tileIds = [] as Set
def tileMap = [:]
def buf = ByteBuffer.allocate(50000)
// Start with the empty tile
(0..31).each { buf.put((byte)0) }
// Add each special tile to the set
dataIn.tile.each { tile ->
def name = tile.@name
def id = tile.@id
def data = tiles[id]
if (name.equalsIgnoreCase("Player avatar - 2D")) {
def num = tileMap.size()
tileIds.add(id)
tileMap[id] = num
data.flip() // crazy stuff to append one buffer to another
buf.put(data)
}
}
// Then add each non-null tile to the set
rows.each { row ->
row.each { tile ->
def id = tile?.@id
if (tile && !tileMap.containsKey(id)) {
def num = tileMap.size()
assert num < 32 : "Temporary, need to fix: Only 32 kinds of tiles are allowed on any given map."
tileMap[id] = num
tiles[id].flip() // crazy stuff to append one buffer to another
buf.put(tiles[id])
tiles[id].compact() // more of crazy stuff above
tileSets[setName] = [num:setNum, buf:buf, tileMap:tileMap, tileIds:tileIds]
return [setNum, tileMap]
}
/** Pack tile images referenced by map rows into a tile set */
def packTileSet(rows, xOff, width, yOff, height)
{
// First, determine the set of unique tile IDs for this map section
def tileIds = [] as Set
(yOff ..< yOff+height).each { y ->
def row = (y < rows.size) ? rows[y] : null
(xOff ..< xOff+height).each { x ->
def tile = (row && x < row.size) ? row[x] : null
tileIds.add(tile?.@id)
}
}
assert tileIds.size() > 0
// See if there's a good existing tile set we can use/add to.
def tileSet = null
def bestCommon = 0
tileSets.values().each {
// Can't combine with the special tileset
if (it.num > 1)
{
// See if the set we're considering has room for all our tiles
def inCommon = it.tileIds.intersect(tileIds)
def together = it.tileIds + tileIds
if (together.size() <= 32 && inCommon.size() > bestCommon) {
tileSet = it
bestCommon = inCommon.size()
}
}
}
tileSets[setName] = [num:setNum, buf:buf]
// If adding to an existing set, update it.
def setNum
if (tileSet) {
setNum = tileSet.num
//print "Adding to tileSet $setNum; had ${tileSet.tileIds.size()} tiles"
tileSet.tileIds.addAll(tileIds)
//println ", now ${tileSet.tileIds.size()}."
}
// If we can't add to an existing set, make a new one
else {
setNum = tileSets.size() + 1
//println "Creating new tileSet $setNum."
tileSet = [num:setNum, buf:ByteBuffer.allocate(50000), tileMap:[:], tileIds:tileIds]
tileSets["tileSet${setNum}"] = tileSet
}
// Start by assuming we'll create a new tileset
def tileMap = tileSet.tileMap
def buf = tileSet.buf
// Then add each non-null tile to the set
(yOff ..< yOff+height).each { y ->
def row = (y < rows.size) ? rows[y] : null
(xOff ..< xOff+height).each { x ->
def tile = (row && x < row.size) ? row[x] : null
def id = tile?.@id
if (tile && !tileMap.containsKey(id)) {
def num = tileMap.size()+1
assert num < 32 : "Error: Only 31 kinds of tiles are allowed on any given map."
tileMap[id] = num
tiles[id].flip() // crazy stuff to append one buffer to another
buf.put(tiles[id])
}
}
}
assert tileMap.size() > 0
assert buf.position() > 0
return [setNum, tileMap]
}
@ -687,8 +762,7 @@ class PackPartitions
def num = mapNames[name][1]
//println "Packing 2D map #$num named '$name'."
def rows = parseMap(mapEl, tileEls)
def (tileSetNum, tileMap) = packTileSet(rows)
write2DMap(name, rows, tileSetNum, tileMap)
write2DMap(name, rows)
}
def pack3DMap(mapEl, tileEls)
@ -992,10 +1066,12 @@ class PackPartitions
// Now compress it with LZ4
assert uncompressedLen < 327678 : "data block too big"
assert uncompressedLen > 0
def maxCompressedLen = compressor.maxCompressedLength(uncompressedLen)
def compressedData = new byte[maxCompressedLen]
def compressedLen = compressor.compress(uncompressedData, 0, uncompressedLen,
compressedData, 0, maxCompressedLen)
assert compressedLen > 0
// Then recompress to LZ4M (pretty much always smaller)
def recompressedLen = recompress(compressedData, compressedLen, uncompressedData, uncompressedLen)
@ -1101,15 +1177,24 @@ class PackPartitions
dataIn.tile.each {
packTile(it)
}
// Pack the global tile set before other tile sets (contains the player avatar, etc.)
packGlobalTileSet(dataIn)
// Pack each image, which has the side-effect of filling in the
// image name map. Handle frame images separately.
//
println "Packing frame images and textures."
dataIn.image.each { image ->
if (image.category.text() == "frame" || image.category.text() == "title")
if (image.category.text() == "title")
packFrameImage(image)
else if (image.category.text() == "126")
}
dataIn.image.each { image ->
if (image.category.text() == "frame")
packFrameImage(image)
}
dataIn.image.each { image ->
if (image.category.text() == "126")
pack126(image)
else
packTexture(image)

View File

@ -1267,7 +1267,9 @@ disk_finishLoad: !zone
!byte MLI_SET_MARK
!word .setMarkParams
bcs .prodosErr
!if DEBUG { +prStr : !text "Deco.",0 }
jsr lz4Decompress ; decompress (or copy if uncompressed)
!if DEBUG { +prStr : !text "Done.",0 }
.resume ldy .ysave
.next lda (pTmp),y ; lo byte of length
clc
@ -1301,7 +1303,7 @@ disk_finishLoad: !zone
.nFixups: !byte 0
!if DEBUG {
.debug1:+prStr : !text "Loading: t=",0
.debug1:+prStr : !text "Load: t=",0
+prByte resType
+prStr : !text "n=",0
+prByte resNum
@ -1311,7 +1313,7 @@ disk_finishLoad: !zone
.debug2:+prStr : !text "len=",0
+prWord reqLen
+prStr : !text "dst=",0
+prWord pDst : +crout
+prWord pDst
rts
} ; end DEBUG
@ -1678,7 +1680,7 @@ setupDecomp:
; Apply fixups to all modules that were loaded this round, and free the fixup
; resources from memory.
doAllFixups: !zone
!if DEBUG { +prStr : !text "Doing all fixups.",0 }
!if DEBUG >= 2 { +prStr : !text "Doing all fixups.",0 }
; copy the shadow code down to $100, so we can read aux mem bytes
ldx #.fixupShadow_end - .fixupShadow - 1
- lda .fixupShadow,x
@ -1732,7 +1734,7 @@ doAllFixups: !zone
lda tSegAdrHi,x
sta .auxBase+1
!if DEBUG { jsr .debug1 }
!if DEBUG >= 2 { jsr .debug1 }
; Process the fixups
.proc jsr .fetchFixup ; get key byte
@ -1745,7 +1747,7 @@ doAllFixups: !zone
txa
adc .mainBase+1
sta pDst+1
!if DEBUG { jsr .debug2 }
!if DEBUG >= 2 { jsr .debug2 }
clc
jsr .adMain
iny
@ -1765,7 +1767,7 @@ doAllFixups: !zone
and #$7F ; mask off the hi bit flag
adc .auxBase+1
sta pDst+1
!if DEBUG { jsr .debug3 }
!if DEBUG >= 2 { jsr .debug3 }
sta setAuxWr
jsr .adAux
iny
@ -1794,7 +1796,7 @@ doAllFixups: !zone
cmp #$03
bne .resume ; not a stub, resume scanning
; found a stub, adjust it.
!if DEBUG { jsr .debug4 }
!if DEBUG >= 2 { jsr .debug4 }
clc
ldx #0
jsr .adStub
@ -1839,7 +1841,7 @@ doAllFixups: !zone
rts
}
.fixupShadow_end = *
!if DEBUG {
!if DEBUG >= 2 {
.debug1 +prStr : !text "Found fixup, res=",0
+prByte resNum
+prStr : !text "mainBase=",0

View File

@ -586,13 +586,14 @@ end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Load the Frame Image, and lock it.
def loadFrameImg()
byte img
if titleLoaded
loader(UNLOCK_MEMORY,MAIN_MEM, $2000)
loader(FREE_MEMORY, MAIN_MEM, $2000)
titleLoaded = FALSE
fin
loader(SET_MEM_TARGET, MAIN_MEM, $2000)
loader(QUEUE_LOAD, MAIN_MEM, 1<<8 | RES_TYPE_SCREEN)
loader(QUEUE_LOAD, MAIN_MEM, (3-mapIs3D)<<8 | RES_TYPE_SCREEN)
loader(LOCK_MEMORY, MAIN_MEM, $2000)
end
@ -1056,7 +1057,7 @@ def loadTitle()
// Load the title screen
loader(SET_MEM_TARGET, MAIN_MEM, $2000)
loader(QUEUE_LOAD, MAIN_MEM, 2<<8 | RES_TYPE_SCREEN)
loader(QUEUE_LOAD, MAIN_MEM, 1<<8 | RES_TYPE_SCREEN) // title screen is fixed at #1
loader(LOCK_MEMORY, MAIN_MEM, $2000)
loader(FINISH_LOAD, MAIN_MEM, 1) // 1 = keep open
titleLoaded = TRUE

View File

@ -18,7 +18,7 @@ HEADER_LENGTH=6
SECTION_WIDTH=22
SECTION_HEIGHT=23
VIEWPORT_WIDTH=9
VIEWPORT_HEIGHT=8
VIEWPORT_HEIGHT=9
VIEWPORT_VERT_PAD=4 ; This is the distance between the center of the viewport and the top/bottom
VIEWPORT_HORIZ_PAD=4 ; This is the distance between the center of the viewport and the left/right
@ -48,6 +48,7 @@ NW_TILESET_LOC=$90
NE_TILESET_LOC=$92
SW_TILESET_LOC=$94
SE_TILESET_LOC=$96
GLOBAL_TILESET_LOC=$98
; Map section IDs (255 = not loaded)
NOT_LOADED=$FF
NW_MAP_ID=$5A
@ -135,10 +136,10 @@ LOAD_SECTION
;----------------------------------------------------------------------
; >> FINISH LOADING MAP SECTIONS
FINISH_MAP_LOAD
LDX #0 ; 1 to keep open for next load, 0 for close so you can flip to HGR page 2
LDA #FINISH_LOAD
JMP mainLoader
!macro finishLoad {
!macro finishLoad keepOpen {
LDX #keepOpen ; 1 to keep open for next load, 0 for close so you can flip to HGR page 2
JSR FINISH_MAP_LOAD
}
@ -204,7 +205,7 @@ LOAD_TILESET
;----------------------------------------------------------------------
; >> GET TILE IN CARDINAL DIRECTION AND FLAGS
; (Returns Tile # in Y, Flags in A)
; Each tile in memory can be 0-64, 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
; | | `- Script assigned, triggers script lookup
; | `--- Boundary (Can not walk on it)
@ -229,6 +230,7 @@ SET_XY
}
FREE_ALL_TILES
+freeResource GLOBAL_TILESET_LOC
+freeResource NW_TILESET_LOC
+freeResource NE_TILESET_LOC
+freeResource SW_TILESET_LOC
@ -239,12 +241,18 @@ FREE_ALL_TILES
}
LOAD_ALL_TILES
+startLoad
; global tileset first
LDX #RES_TYPE_TILESET
LDY #1 ; global tileset fixed at resource #1
LDA #QUEUE_LOAD
JSR mainLoader
STX GLOBAL_TILESET_LOC
STY GLOBAL_TILESET_LOC+1
; then the set for each map section in turn
+loadTileset NW_MAP_ID, NW_MAP_LOC, NW_TILESET_LOC
+loadTileset NE_MAP_ID, NE_MAP_LOC, NE_TILESET_LOC
+loadTileset SW_MAP_ID, SW_MAP_LOC, SW_TILESET_LOC
+loadTileset SE_MAP_ID, SE_MAP_LOC, SE_TILESET_LOC
+finishLoad
RTS
!macro loadAllTiles {
JSR LOAD_ALL_TILES
@ -305,12 +313,12 @@ CROSS_NORTH
PLA
STA NE_MAP_ID
+loadSection NE_MAP_LOC
+finishLoad
+finishLoad 1 ; keep open for further loading
+loadAllTiles
+finishLoad 0 ; all done
RTS
.noMap INC REL_Y
JMP bell
RTS
;----------------------------------------------------------------------
; >> CROSS EAST BOUNDARY (Load next section to the east)
!zone
@ -349,11 +357,12 @@ CROSS_EAST
PLA
STA SE_MAP_ID
+loadSection SE_MAP_LOC
+finishLoad
+finishLoad 1 ; keep open for further loading
+loadAllTiles
+finishLoad 0 ; all done
RTS
.noMap DEC REL_X
JMP bell
RTS
;----------------------------------------------------------------------
; >> CROSS SOUTH BOUNDARY (Load next section to the south)
!zone
@ -392,11 +401,12 @@ CROSS_SOUTH
PLA
STA SE_MAP_ID
+loadSection SE_MAP_LOC
+finishLoad
+finishLoad 1 ; keep open for further loading
+loadAllTiles
+finishLoad 0 ; all done
RTS
.noMap DEC REL_Y
JMP bell
RTS
;----------------------------------------------------------------------
; >> CROSS WEST BOUNDARY (load next section to the west)
!zone
@ -432,11 +442,12 @@ CROSS_WEST
PLA
STA SW_MAP_ID
+loadSection SW_MAP_LOC
+finishLoad
+finishLoad 1 ; keep open for further loading
+loadAllTiles
+finishLoad 0 ; all done
RTS
.noMap INC REL_X
JMP bell
RTS
;----------------------------------------------------------------------
; >> SET PLAYER TILE (A = tile)
;----------------------------------------------------------------------
@ -629,14 +640,14 @@ ROW_OFFSET = 3
LDX SECTION_Y_START
ADC tblMAPl,X
BCC +
INY ; handle carry from prev add
+ CPX #12 ; rows 0-11 are on 1st page of map, 12-22 on 2nd page
INY ; handle carry from prev add
+ CPX #12 ; rows 0-11 are on 1st page of map, 12-22 on 2nd page
BCC +
INY ; go to 2nd pg
INY ; go to 2nd pg
CLC
+ ADC SECTION_X_START
BCC +
INY ; handle carry from prev add
INY ; handle carry from prev add
+ SEC
SBC DRAW_X_START ; because it gets added back in later by indexing with X
BCS +
@ -649,9 +660,27 @@ ROW_OFFSET = 3
; Get tile
TXA
TAY
; show avatar in the center of the map
CMP #VIEWPORT_HORIZ_PAD
BNE .notAvatar
LDA Y_LOC
CMP #VIEWPORT_VERT_PAD
BNE .notAvatar
LDY GLOBAL_TILESET_LOC
LDA GLOBAL_TILESET_LOC+1
BNE .store_src ; always taken
.notAvatar
LDA #0
STA TILE_SOURCE+1
LDA (ROW_LOCATION), Y
BNE .not_empty ; zero means empty tile
.empty
LDY #<emptyTile
LDA #>emptyTile+1
BNE .store_src ; always taken
.not_empty
SEC
SBC #1 ; tile map is 1-based, tile set indexes are 0-based
; Calculate location of tile data == tile_base + ((tile & 31) * 32)
AND #31
ASL
@ -662,10 +691,12 @@ ROW_OFFSET = 3
ASL
ROL TILE_SOURCE+1
CLC
ADC TILE_BASE
STA TILE_SOURCE
ADC TILE_BASE
TAY
LDA TILE_SOURCE+1
ADC TILE_BASE + 1
.store_src
STY TILE_SOURCE
STA TILE_SOURCE+1
.doneCalculatingTileLocation
; Is there a NPC there?
@ -718,7 +749,7 @@ INIT
+startLoad
LDA NW_MAP_ID
+loadSection NW_MAP_LOC
+finishLoad
+finishLoad 1 ; keep open for further loading...
+startLoad
; from the NW section we can get the ID of the NE section
LDY #EAST
@ -730,7 +761,7 @@ INIT
LDA (NW_MAP_LOC),Y
STA SW_MAP_ID
+loadSection SW_MAP_LOC
+finishLoad
+finishLoad 1 ; keep open for further loading...
+startLoad
; if there's no SW section, there's also no SE section
LDA #$FF
@ -742,8 +773,9 @@ INIT
LDA (SW_MAP_LOC),Y
STA SE_MAP_ID
+loadSection SE_MAP_LOC
+ +finishLoad
+ +finishLoad 1 ; keep open for further loading
+loadAllTiles
+finishLoad 0 ; all done
; set up the X and Y coordinates
LDX #VIEWPORT_HORIZ_PAD
LDY #VIEWPORT_VERT_PAD
@ -763,3 +795,5 @@ tblHGRh
tblMAPl !for row, 23 {
!byte <((row-1)*22)+6
}
emptyTile !fill 32