Animations working in-engine for the first time.

This commit is contained in:
Martin Haye 2015-12-17 09:19:49 -08:00
parent a1b60a490c
commit 604857a4d2
2 changed files with 177 additions and 31 deletions

View File

@ -702,7 +702,7 @@ class PackPartitions
{
def num = portraits.size() + 1
def name = imgEl.@name ?: "img$num"
def animFrameNum
def animFrameNum = 0
def animFlags
def m = (name =~ /^(.*)\*(\d+)(\w*)$/)
if (m) {
@ -733,14 +733,18 @@ class PackPartitions
else if (animFrameNum > 1) {
if (!portraits[name])
throw new Exception("Can't find first frame for animation '$name'")
num = portraits.size() // in other words, do not increment
buf.flip() // crazy stuff to append one buffer to another
buf.get() // skip 1st byte - unused flags
def out = portraits[name].buf
out.put(buf)
// Increment the frame count
def endPos = out.position()
def endPos = out.position()
out.position(0)
out.put((byte)(out.get() + 1))
def before = out.get()
out.position(0)
out.put((byte)(before+1))
out.position(endPos)
}
else
@ -1511,12 +1515,22 @@ class PackPartitions
// Translate image names to constants
new File("src/plasma/gen_images.plh").withWriter { out ->
def portraitNum = 0
dataIn.image.each { image ->
dataIn.image.sort{it.@name.toLowerCase()}.each { image ->
def category = image.@category?.toLowerCase()
def name = image.@name
if (category == "portrait") {
++portraitNum
out.println "const PORTRAIT_${humanNameToSymbol(name, true)} = $portraitNum"
def animFrameNum = 0
def animFlags
def m = (name =~ /^(.*)\*(\d+)(\w*)$/)
if (m) {
name = m[0][1]
animFrameNum = m[0][2].toInteger()
animFlags = m[0][3].toLowerCase()
}
if (animFrameNum <= 1) {
++portraitNum
out.println "const PORTRAIT_${humanNameToSymbol(name, true)} = $portraitNum"
}
}
}
}

View File

@ -24,8 +24,17 @@ const heapSize = $800
// Other constants
const callbacks = $300
const kbd = $C000
const kbdStrobe = $C010
const CHAR_WND_LIFE_X = 91
const CHAR_WND_GUN_X = 114
const CHAR_WND_GUN_X = 114
const ANIM_FLAG_FWD = $20
const ANIM_FLAG_FWD_BKWD = $40
const ANIM_FLAG_RANDOM = $80
const ANIM_PAUSE_MAX = 250
include "playtype.plh"
include "gen_images.plh"
@ -35,7 +44,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
predef setWindow2, initCmds, nextAnimFrame
///////////////////////////////////////////////////////////////////////////////////////////////////
// Global variables
@ -66,8 +75,15 @@ byte q_dir
byte decimalBuf[7]
byte tabBuf[5]
// Game library functions
// Animation tracking
word curPortrait = 0
byte animFlags
byte animDir
byte animNumFrames
byte animFrame
word animPauseCt
// Game library functions
predef _getGlobals, _rand16
predef _printf1, _printf2, _printf3, _printf4
predef _displayf1, _displayf2, _displayf3, _displayf4
@ -112,7 +128,7 @@ ysav1 = $35
; 16-bit random number seed - incremented by ROM kbd routine
seed = $4E
magic = $2227 ; there are 2048 magic values that work; this one caught my eye.
magic = $2227 ; there are 2048 magic values that work; this one caught my eye. - MH
; NOTE ABOUT ABSOLUTE ADDRESSES
; You cannot use them: this code, including variable space, can be loaded *anywhere*.
@ -159,6 +175,43 @@ asm render // no params
jmp $6018
end
///////////////////////////////////////////////////////////////////////////////////////////////////
asm setAuxCopy
rts
end
///////////////////////////////////////////////////////////////////////////////////////////////////
asm readAuxByte // params: ptr; ret: char
+asmPlasm 1
; Create the following subroutine, used to copy one char from aux to main:
;0010- 8D 03 C0 STA $C003
;0013- AD XX XX LDA $XXXX
;0016- 8D 02 C0 STA $C002
;0019- 60 RTS
sta $14
sty $15
lda #$8D
sta $10
sta $16
ldx #2
stx $17
inx
stx $11
lda #$C0
sta $12
sta $18
lda #$AD
sta $13
lda #$60
sta $19
; And call the routine
ldy #0
jmp $10
end
///////////////////////////////////////////////////////////////////////////////////////////////////
asm pushAuxStr // params: none; ret: $200 (inbuf)
stx tmp ; save PLASMA's X reg eval stack index
@ -369,7 +422,7 @@ asm blitPortrait // params: srcData, dstScreenPtr
; Outer copy loop
ldx #128 ; line count
.loop ldy #17 ; byte count minus 1
.loop ldy #17 ; byte count minus 1. There are 18 bytes per line
jsr $10 ; copy pixel bytes
; Advance to next row of data
@ -924,7 +977,19 @@ end
// Get a keystroke and convert it to upper case
def _getUpperKey()
byte key
key = rdkey() & $7F
while ^kbd < 128
*seed = *seed + 1
animPauseCt = animPauseCt - 1
if animPauseCt < 0
if curPortrait and animNumFrames > 1
nextAnimFrame()
fin
animPauseCt = ANIM_PAUSE_MAX
fin
loop
key = ^kbd
^kbdStrobe
key = key & $7F
if key >= $60
key = key - $20
fin
@ -1175,6 +1240,19 @@ def checkScripts()
loop
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Perform rendering, copy if necessary, clear appropriate flags
def doRender()
if curPortrait
auxMmgr(FREE_MEMORY, curPortrait)
curPortrait = 0
fin
render()
if textDrawn and mapIs3D; copyWindow(); fin
needRender = FALSE
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Advance one step forward (3D maps only)
def moveForward()
@ -1184,9 +1262,7 @@ def moveForward()
// If not blocked, render at the new position.
if val > 0
if !mapIs3D
render()
if textDrawn and mapIs3D; copyWindow(); fin
needRender = FALSE
doRender()
else
needRender = TRUE
fin
@ -1402,9 +1478,7 @@ def kbdLoop()
q_mapNum = 0
fin
if needRender
render()
if textDrawn and mapIs3D; copyWindow(); fin
needRender = FALSE
doRender()
fin
loop
end
@ -1480,6 +1554,68 @@ def _getYN()
loop
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Show the current animation frame
def showAnimFrame()
word pData
// Determine data pointer based on current animation frame
if !curPortrait; return; fin
pData = curPortrait + 1 + (animFrame * 2304) // 18*128 = 2304
// Show it on-screen
if mapIs3D
blitPortrait(pData, $2182) // start at 3rd text line
else
blitPortrait(pData, $2202) // start at 4th text line
fin
needRender = FALSE // suppress display of map for this frame
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Advance to next frame of current animation, if any
def nextAnimFrame()
word oldAnimFrame
if !curPortrait; return; fin
oldAnimFrame = animFrame
// Choose a new direction based on the flags. Do this the first time, and about once per 4 frames.
if !animDir or (rand16() % 4) == 0
if animFlags & ANIM_FLAG_FWD
animDir = 'F'
elsif animFlags & ANIM_FLAG_FWD_BKWD
if rand16() % 2
animDir = 'F'
else
animDir = 'B'
fin
elsif (animFlags & ANIM_FLAG_RANDOM)
animDir = 'R'
else
animDir = 0
fin
fin
// Advance in the current direction
if animDir == 'F' // forward
animFrame = (animFrame+1) % animNumFrames
elsif animDir == 'B' // backward
animFrame = (animFrame-1) % animNumFrames
elsif animDir == 'R' // random
animFrame = rand16() % animNumFrames
fin
// And show it.
if animFrame <> oldAnimFrame
showAnimFrame()
fin
// Reset the animation pause
animPauseCt = ANIM_PAUSE_MAX
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Display a portrait drawing (typically called from scripts)
def _setPortrait(portraitNum)
@ -1500,26 +1636,22 @@ def _setPortrait(portraitNum)
restoreCursor()
// Load the portrait image and display it
srcData = auxMmgr(QUEUE_LOAD, portraitNum<<8 | RES_TYPE_PORTRAIT)
curPortrait = auxMmgr(QUEUE_LOAD, portraitNum<<8 | RES_TYPE_PORTRAIT)
mmgr(FINISH_LOAD, 0) // 0 = close
animFrame = 0
animFlags = readAuxByte(curPortrait)
animNumFrames = animFlags & $F
animDir = 0
animPauseCt = ANIM_PAUSE_MAX
if mapIs3D
blitPortrait(srcData, $2182) // start at 3rd text line
else
blitPortrait(srcData, $2202) // start at 4th text line
fin
needRender = FALSE // suppress display of map for this frame
auxMmgr(FREE_MEMORY, srcData)
// And show the first frame
showAnimFrame()
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Clear the displayed portrait drawing
def clrPortrait()
render()
if textDrawn and mapIs3D; copyWindow(); fin
needRender = FALSE
doRender()
end
///////////////////////////////////////////////////////////////////////////////////////////////////