mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-02-23 09:29:00 +00:00
Now supports animating title screen and final win screen.
This commit is contained in:
parent
ee16d7a0d6
commit
f3aaa7c6ad
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user