Now supports animating title screen and final win screen.

This commit is contained in:
Martin Haye 2016-10-23 10:42:11 -07:00
parent ee16d7a0d6
commit f3aaa7c6ad
4 changed files with 92 additions and 66 deletions

View File

@ -72,8 +72,6 @@ class A2PackPartitions
def bytecodes = [:] // module name to bytecode.num, bytecode.buf
def fixups = [:] // module name to fixup.num, fixup.buf
def fooFlg = false
def itemNameToFunc = [:]
def playerNameToFunc = [:]
@ -766,10 +764,12 @@ class A2PackPartitions
def packFrameImage(imgEl)
{
def name = imgEl.@name ?: "img$num"
def hash = calcImageHash(imgEl)
if (!grabFromCache("frame", frames, name, hash))
addToCache("frame", frames, name, hash, parseFrameData(imgEl))
def (name, animFrameNum, animFlags) = decodeImageName(imgEl.@name ?: "img$num")
if (!frames.containsKey(name)) {
def num = frames.size() + 1
frames[name] = [num:num, anim:new AnimBuf()]
}
frames[name].anim.addImage(animFrameNum, animFlags, parseFrameData(imgEl))
}
def packPortrait(imgEl)
@ -777,7 +777,6 @@ class A2PackPartitions
def (name, animFrameNum, animFlags) = decodeImageName(imgEl.@name ?: "img$num")
if (!portraits.containsKey(name)) {
def num = portraits.size() + 1
fooFlg = (num == 1)
portraits[name] = [num:num, anim:new AnimBuf()]
}
portraits[name].anim.addImage(animFrameNum, animFlags, parse126Data(imgEl))
@ -1761,8 +1760,8 @@ class A2PackPartitions
dataIn.image.sort{it.@name.toLowerCase()}.each { image ->
def category = image.@category?.toLowerCase()
def name = image.@name.toLowerCase()
if (category == "fullscreen" && name == "title")
def (name, animFrameNum, animFlags) = decodeImageName(image.@name)
if (category == "fullscreen" && name.equalsIgnoreCase("title"))
titleImgs << image
else if (category == "uiframe")
uiFrameImgs << image
@ -1778,20 +1777,24 @@ class A2PackPartitions
println "Warning: couldn't classify image named '${name}', category '${category}'."
}
assert titleImgs.size() == 1 : "Couldn't find title image. Should be category='FULLSCREEN', name='title'"
assert titleImgs.size() >= 1 : "Couldn't find title image. Should be category='FULLSCREEN', name='title'"
assert uiFrameImgs.size() == 2 : "Need exactly 2 UI frames, found ${uiFramesImgs.size()} instead."
// Pack each image, which has the side-effect of filling in the image name map.
titleImgs.each { image -> packFrameImage(image) }
uiFrameImgs.each { image -> packFrameImage(image) }
fullscreenImgs.each { image -> packFrameImage(image) }
if (!grabEntireFromCache("frames", frames, xmlLastMod)) {
titleImgs.each { image -> packFrameImage(image) }
uiFrameImgs.each { image -> packFrameImage(image) }
fullscreenImgs.each { image -> packFrameImage(image) }
frames.each { name, frame ->
frame.buf = frame.anim.pack()
frame.anim = null
}
addEntireToCache("frames", frames, xmlLastMod)
}
textureImgs.each { image -> packTexture(image) }
if (!grabEntireFromCache("portraits", portraits, xmlLastMod)) {
portraitImgs.each { image -> packPortrait(image) }
portraits.each { name, portrait ->
fooFlg = (portrait.num == 1)
if (fooFlg)
println "Packing portrait $name."
portrait.buf = portrait.anim.pack()
portrait.anim = null
}
@ -2512,7 +2515,19 @@ end
portraits[name] = [] // placeholder during dataGen phase
}
}
out.println "const PO_LAST = $portraitNum"
out.println "const PO_LAST = $portraitNum\n"
def frameNum = 3 // 1-3 are title, UI 2d, UI 3d respectively
dataIn.image.sort{it.@name.toLowerCase()}.each { image ->
def category = image.@category?.toLowerCase()
def (name, animFrameNum, animFlags) = decodeImageName(image.@name)
if (category == "fullscreen" && animFrameNum == 1 && !name.equalsIgnoreCase("title")) {
++frameNum
out.println "const PF${humanNameToSymbol(name, false)} = $frameNum"
frames[name] = [] // placeholder during dataGen phase
}
}
out.println "const PF_LAST = $frameNum"
}
replaceIfDiff("build/src/plasma/gen_images.plh")
@ -3419,26 +3434,18 @@ end
def addImage(animFrameNum, animFlags, imgBuf)
{
dbg("addImage: $animFrameNum=$animFrameNum size=${imgBuf.position()}")
if (animFrameNum == 1)
this.animFlags = animFlags
buffers << imgBuf
assert animFrameNum == buffers.size() : "Missing animation frame"
}
def dbg(str)
{
if (fooFlg)
System.out.println(str)
}
def pack()
{
def outBuf = ByteBuffer.allocate(50000) // plenty of room
// If no animation, add a stub to the start of the (only) image and return it
assert buffers.size() >= 1
dbg("nBuffers=${buffers.size()}")
if (buffers.size() == 1) {
outBuf.put((byte)0)
outBuf.put((byte)0)
@ -3449,8 +3456,6 @@ end
// At start of buffer, put offset to animation header, then the first frame
def offset = buffers[0].position() + 2 // 2 for the offset itself
dbg("Initial offset=$offset")
dbg(String.format("First image byte=\$%x", buffers[0].get(0)))
outBuf.put((byte)(offset & 0xFF))
outBuf.put((byte)((offset >> 8) & 0xFF))
buffers[0].flip()
@ -3466,8 +3471,6 @@ end
case "r" : flagByte = 4; break
default : throw new Exception("Unrecognized animation flags '$animFlags'")
}
dbg("flagByte=$flagByte")
dbg("nFrames=${buffers.size()}")
outBuf.put((byte)flagByte)
outBuf.put((byte)1) // used to store current anim dir; start with 1=forward
outBuf.put((byte)(buffers.size())) // number of frames

View File

@ -3014,6 +3014,8 @@ advanceAnims: !zone {
and #$F ; get type
cmp #RES_TYPE_PORTRAIT
beq .anim ; found an animated resource type
cmp #RES_TYPE_SCREEN
beq .anim
bne .next ; not animated; skip
.anim lda tSegAdrLo,x ; pointer to start of resource
sta pTmp
@ -3177,7 +3179,7 @@ applyPatch:
pla
jsr .srcadd ; skip pSrc past last partial page in patch
jmp -
+
+ !if DEBUG = 2 { jsr .dbgC2 }
; pSrc now points at the patch to apply
; pDst now points at the base data to modify
@ -3228,6 +3230,10 @@ applyPatch:
+prStr : !text "apply ",0
+prByte reqLen
jmp .dbgout
.dbgC2 jsr .dbgin
+prStr : !text "patch ",0
+prWord pSrc
jmp .dbgout
} ; end of debug
} ; end of zone

View File

@ -283,8 +283,7 @@ def _newOrLoadGame(ask)
puts("\n N)ew game, or L)oad last game? ")
while TRUE
key = rdkey() & $7F
if key > $60; key = key - $20; fin // convert to upper-case
key = getUpperKey()
if key == 'N'
^$c052
newGame()

View File

@ -49,7 +49,7 @@ word global // the global heap object, from which all live objects must be reac
///////////////////////////////////////////////////////////////////////////////////////////////////
// Predefined functions, for circular calls or out-of-order calls
predef setWindow2, initCmds, nextAnimFrame, checkEncounter, doCombat, clearPortrait, showMapName
predef doRender, playerDeath, startGame, loadFrameImg
predef doRender, playerDeath, startGame, loadFrameImg, showAnimFrame, finalWin
///////////////////////////////////////////////////////////////////////////////////////////////////
// Global variables
@ -69,7 +69,7 @@ byte skipEncounterCheck = FALSE
word skyNum = 9
word groundNum = 10
byte portraitNum = 1
byte portraitNum = POgunWoman1-1
word triggerOriginX, triggerOriginY
word triggerTbl
@ -97,7 +97,8 @@ byte decimalBuf[7]
byte tabBuf[5]
// Animation tracking
word curPortrait = 0
word curPortrait = NULL
word curFullscreenImg = NULL
byte animDirCt
byte anyAnims = TRUE
word animPauseCt
@ -1004,7 +1005,7 @@ export def getUpperKey()
*seed = *seed + 1
animPauseCt = animPauseCt - 1
if animPauseCt < 0
if curPortrait and anyAnims
if anyAnims
nextAnimFrame()
fin
animPauseCt = ANIM_PAUSE_MAX
@ -1021,7 +1022,7 @@ export def pause(count)
while count >= 0
animPauseCt = animPauseCt - 1
if animPauseCt < 0
if curPortrait and anyAnims
if anyAnims
nextAnimFrame()
fin
animPauseCt = ANIM_PAUSE_MAX
@ -1054,9 +1055,7 @@ end
export def setSky(num)
// hack for end-game screen
if num == 99
flipToPage1()
loadFrameImg(4)
while 1; loop // 1 infinite loop
finalWin()
fin
skyNum = num
setColor(0, skyNum)
@ -1086,22 +1085,27 @@ end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Load the Frame Image, and lock it.
def loadFrameImg(img)
word tmpBuf
// Skip redundant reload
if frameLoaded == img; return; fin
// Temporarily load the image in aux mem
tmpBuf = auxMmgr(QUEUE_LOAD, img<<8 | RES_TYPE_SCREEN)
// Free prev img and/or portrait (if any)
clearPortrait()
// Load the image data into aux mem
auxMmgr(START_LOAD, 1) // partition 1 is where full screen images live
curFullscreenImg = auxMmgr(QUEUE_LOAD, img<<8 | RES_TYPE_SCREEN)
auxMmgr(FINISH_LOAD, 0)
// Blit to the graphics screen.
// No need to lock hi-res pg 1, mem mgr has done it for us.
blit(tmpBuf, $2000, 192, 40)
// And clean up
auxMmgr(FREE_MEMORY, tmpBuf)
frameLoaded = img
anyAnims = TRUE // for now; might get cleared if we discover otherwise on advance
animDirCt = 1
animPauseCt = ANIM_PAUSE_MAX
// And show the first frame of the screen image
showAnimFrame()
// Do not render over the image
needRender = FALSE
end
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -1283,6 +1287,8 @@ def initMap(x, y, dir)
// Load the frame image, then raycaster or tile engine
mmgr(START_LOAD, 1) // partition 1 is where code lives
loadFrameImg(mapIs3D+2)
auxMmgr(FREE_MEMORY, curFullscreenImg)
curFullscreenImg = NULL
mmgr(SET_MEM_TARGET, displayEngine)
if mapIs3D
mmgr(QUEUE_LOAD, CODE_RENDER<<8 | RES_TYPE_CODE)
@ -1326,6 +1332,7 @@ def initMap(x, y, dir)
textDrawn = FALSE
curEngine = NULL
curPortrait = 0
curFullscreenImg = NULL
if global->b_curAvatar <> 0 and !mapIs3D
setAvatar(global->b_curAvatar)
doRender()
@ -1358,7 +1365,12 @@ end
export def clearPortrait()
if curPortrait
auxMmgr(FREE_MEMORY, curPortrait)
curPortrait = 0
curPortrait = NULL
needRender = TRUE
fin
if curFullscreenImg
auxMmgr(FREE_MEMORY, curFullscreenImg)
curFullscreenImg = NULL
needRender = TRUE
fin
end
@ -1678,27 +1690,25 @@ end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Show the current animation frame
def showAnimFrame()
word pData
// Determine data pointer based on current animation frame
if !curPortrait; return; fin
pData = curPortrait + 2 // skip anim-hdr offset
// Show it on-screen
if frameLoaded == 3 // 3D-mode frame? Note: don't check mapIs3D, because we might be in an engine
blit(pData, $2182, 128, 18) // start at 3rd text line
else
blit(pData, $2202, 128, 18) // start at 4th text line
if curPortrait
// Blit portrait to the appropriate area on the screen
if frameLoaded == 3 // 3D-mode frame? Note: don't check mapIs3D, because we might be in an engine
blit(curPortrait + 2, $2182, 128, 18) // start at 3rd text line
else
blit(curPortrait + 2, $2202, 128, 18) // start at 4th text line
fin
needRender = FALSE // suppress display of map for this frame
elsif curFullscreenImg
blit(curFullscreenImg + 2, $2000, 192, 40) // the +2 is to skip anim hdr offset
needRender = FALSE // suppress display of map for this frame
fin
needRender = FALSE // suppress display of map for this frame
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Advance to next frame of current animation, if any
def nextAnimFrame()
word flags
if !curPortrait or !anyAnims; return; fin
if !anyAnims; return; fin
// Choose a new direction based on the flags. Do this the first time, and once every 3-7 frames.
animDirCt = animDirCt - 1
@ -2083,6 +2093,13 @@ def printMem
rdkey
^$c050
end
def finalWin()
flipToPage1()
loadFrameImg(4) // total hack
while 1 // 1 infinite loop
getUpperKey()
loop
end
def setCheatCmds
// install cheat commands
cmdTbl['T'] = @kbdTeleport
@ -2093,6 +2110,7 @@ def setCheatCmds
cmdTbl['Y'] = @nextSky
cmdTbl['G'] = @nextGround
cmdTbl['&'] = @printMem
cmdTbl['_'] = @finalWin
end
def enableGodMode()
if ^$C061 >= 128 and ^$C062 >= 128