Initial infrastructure for event handling.

This commit is contained in:
Martin Haye 2016-09-15 11:08:43 -07:00
parent c09142a164
commit a2c8008755
4 changed files with 133 additions and 90 deletions

View File

@ -79,6 +79,27 @@ class A2PackPartitions
def cache = [:]
def buildDir
def memUsageFile
def stats = [
"intelligence": "@S_INTELLIGENCE",
"strength": "@S_STRENGTH",
"agility": "@S_AGILITY",
"stamina": "@S_STAMINA",
"spirit": "@S_SPIRIT",
"luck": "@S_LUCK",
"health": "@S_HEALTH",
"max health": "@S_MAX_HEALTH",
"aiming": "@S_AIMING",
"hand to hand": "@S_HAND_TO_HAND",
"dodging": "@S_DODGING",
"gold": "@S_GOLD"
]
def predefStrings = stats + [
"enter": "@S_ENTER",
"leave": "@S_LEAVE",
"use": "@S_USE"
]
/**
* Keep track of context within the XML file, so we can spit out more useful
@ -117,6 +138,10 @@ class A2PackPartitions
def escapeString(inStr)
{
// Commonly used strings (e.g. event handler names, attributes)
if (inStr in predefStrings)
return predefStrings[inStr]
def buf = new StringBuilder()
buf << '\"'
def prev = '\0'
@ -2988,21 +3013,9 @@ end
}
def nameToStat(name) {
switch (name.toLowerCase().trim()) {
case "intelligence": return "@S_INTELLIGENCE"; return
case "strength": return "@S_STRENGTH"; return
case "agility": return "@S_AGILITY"; return
case "stamina": return "@S_STAMINA"; return
case "spirit": return "@S_SPIRIT"; return
case "luck": return "@S_LUCK"; return
case "health": return "@S_HEALTH"; return
case "max health": return "@S_MAX_HEALTH"; return
case "aiming": return "@S_AIMING"; return
case "hand to hand": return "@S_HAND_TO_HAND"; return
case "dodging": return "@S_DODGING"; return
case "gold": return "@S_GOLD"; return
default: assert false : "Unrecognized stat '$name'"
}
def lcName = name.toLowerCase().trim()
assert lcName in stats : "Unrecognized stat '$name'"
return stats[lcName]
}
def packChangeStat(blk)

View File

@ -89,6 +89,11 @@ word q_x = 0
word q_y = 0
byte q_dir = 0
// Script tracking
const MAX_MAP_SCRIPTS = 4
byte nMapScripts = 0
word mapScripts[MAX_MAP_SCRIPTS]
// For decimal conversion and display tabbing
byte decimalBuf[7]
byte tabBuf[5]
@ -117,6 +122,7 @@ export byte[] S_HAND_TO_HAND = "hand to hand"
export byte[] S_DODGING = "dodging"
export byte[] S_GOLD = "gold"
export byte[] S_ENTER = "enter"
export byte[] S_LEAVE = "leave"
export byte[] S_USE = "use"
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -1201,6 +1207,82 @@ export def showParty()
needShowParty = FALSE
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def getArgCount(pFunc)
word pBytecode
// skip over JMP to plasma interp, get addr in aux mem
pBytecode = pFunc=>3
// Check if the function starts with ENTER op
if readAuxByte(pBytecode) == $58
return readAuxByte(pBytecode+2)
fin
// Zero-arg functions sometimes omit ENTER altogether.
return 0
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Send an event to the scripts on the current map square
def scriptEvent(event, param)
byte i
word script
if !nMapScripts; return; fin
setWindow2()
skipScripts = FALSE
for i = 0 to nMapScripts-1
script = mapScripts[i]
if getArgCount(script) == 2
script(event, param)
elsif event == @S_ENTER // zero-param scripts are assumed to be strictly 'enter' handlers
script()
fin
// Some scripts need to suppress running of any further scripts on the square
// because they swapped out the render engine.
if skipScripts; break; fin
next
clearPortrait()
if needShowParty; showParty(); fin
if global=>p_players=>w_health == 0; playerDeath(); fin
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Check for script(s) attached to the given location, and establish the array of map scripts.
// Does not call any of them -- that's the job of scriptEvent().
def scanScripts(x, y)
word p
word script
word pNext
nMapScripts = 0
x = x - triggerOriginX
y = y - triggerOriginY
p = triggerTbl
while p
if ^p == $FF
break
fin
pNext = p + p->1
if ^p == y
p = p + 2
while p < pNext
if x == ^p
if nMapScripts == MAX_MAP_SCRIPTS; fatal("maxScpts"); fin
mapScripts[nMapScripts] = p=>1
nMapScripts++
fin
p = p + 3
loop
fin
p = pNext
loop
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Load code and data, set up everything to display a 2D or 3D map
def initMap(x, y, dir)
@ -1268,6 +1350,9 @@ def initMap(x, y, dir)
doRender()
fin
// Populate script handlers for the current square, so that leave handlers will trigger right.
scanScripts(x, y)
// Display the party characters
showParty()
end
@ -1278,68 +1363,10 @@ export def scriptSetAvatar(avatarTileNum)
if renderLoaded; setAvatar(avatarTileNum); fin
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Send an event to the script
export def scriptEvent(event, param)
if global=>p_mapScript
return global=>p_mapScript(event, param)
fin
return -1
end
// Check for script(s) attached to the given location, and call them if there are any.
// Returns TRUE if any were triggered.
def checkScripts(x, y)
word p
word script
word pNext
byte anyTriggered
scriptEvent(EVENT_LEAVE, 0)
global=>p_mapScript = 0
anyTriggered = FALSE
x = x - triggerOriginX
y = y - triggerOriginY
p = triggerTbl
while p
if ^p == $FF
break
fin
pNext = p + p->1
if ^p == y
p = p + 2
while p < pNext
if x == ^p
script = p=>1
setWindow2()
skipScripts = FALSE
script() // When should the script be installed as an event handler?
clearPortrait()
// Some scripts need to suppress running of any further scripts on the square
// because they swapped out the render engine.
if skipScripts; return TRUE; fin
anyTriggered = TRUE
fin
p = p + 3
loop
fin
p = pNext
loop
if anyTriggered
scriptEvent(EVENT_ENTER, 0)
if global=>p_players=>w_health == 0
playerDeath()
fin
if needShowParty
showParty()
fin
fin
return anyTriggered
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def unloadTextures()
if renderLoaded and texturesLoaded
flipToPage1()
texControl(0)
texturesLoaded = FALSE
fin
@ -1391,20 +1418,25 @@ def moveForward()
fin
fin
// If we're on a new map tile, clear text from script(s) on the old tile.
if val >= 2 and textDrawn
clearWindow()
if mapIs3D; copyWindow(); fin
textDrawn = FALSE
// If we're on a new map tile, clear text from script(s) on the old tile, and run leave handlers.
if val >= 2
if textDrawn
clearWindow()
if mapIs3D; copyWindow(); fin
textDrawn = FALSE
fin
scriptEvent(@S_LEAVE, NULL)
nMapScripts = 0
fin
// If there are script(s) on the new tile, run them.
if val == 3
getPos(@x, @y)
if !checkScripts(x, y)
if global=>p_encounterZones
checkEncounter(x, y, FALSE)
fin
scanScripts(x, y)
if nMapScripts
scriptEvent(@S_ENTER, NULL)
elsif global=>p_encounterZones
checkEncounter(x, y, FALSE)
fin
elsif val >= 2 and global=>p_encounterZones
getPos(@x, @y)
@ -1533,8 +1565,8 @@ def setMap(is3D, num, x, y, dir)
initMap(x, y, dir)
allowZoneInit = FALSE
fin
// Don't check scripts, because we often land on an "Exit to wilderness?" script
//NO:checkScripts()
// Don't send enter event, because we often land on an "Exit to wilderness?" script
//NO:scriptEvent(S_ENTER, NULL)
end
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -1740,7 +1772,6 @@ export def setPortrait(portraitNum)
byte cx, cy
clearPortrait()
flipToPage1()
// We're going to switch windows. Save the cursor pos in the text window.
saveCursor()
@ -1873,6 +1904,7 @@ def loadEngine(moduleNum)
fin
mmgr(RESET_MEMORY, 0)
renderLoaded = FALSE
nMapScripts = 0
mapIs3D = FALSE
curPortrait = NULL
mmgr(START_LOAD, 1) // code is in partition 1
@ -2366,11 +2398,10 @@ end
export def createAndAddUnique(moduleID, creationFuncNum, pList)
word p_module, funcTbl, func, p_thing
// Unload textures to make room for the module
// Unload textures to make room for the module (also flips to page 1 if needed)
unloadTextures()
// Load the module that is capable of creating the thing
flipToPage1()
diskActivity($FF)
mmgr(START_LOAD, 1) // code is in partition 1
p_module = mmgr(QUEUE_LOAD, moduleID<<8 | RES_TYPE_MODULE)

View File

@ -25,7 +25,6 @@ struc Global
word w_mapX
word w_mapY
byte b_mapDir
word p_mapScript
// Shared player gold amount
word w_gold

View File

@ -1668,7 +1668,7 @@ pl_texControl: !zone {
jsr mainLoader
lda #0 ; don't re-init scripts
jmp loadTextures
.unload
.unload inc $4000 ; make diff from $2000, so we know to restore $4000 later.
- txa
pha
ldy texAddrHi,x