Implemented auto-save, and sped up saving in general. Fixes for the improved help screen.

This commit is contained in:
Martin Haye 2020-08-22 10:50:45 -07:00
parent 7b9a9b4eb6
commit 91be4d56bf
6 changed files with 148 additions and 112 deletions

View File

@ -4974,13 +4974,30 @@ end
{
if (valBlk[0].@type == 'text')
{
def text = getSingle(getSingle(valBlk, null, 'text').field, 'TEXT').text()
if (!text) // interpret lack of text as a single empty string
text = ""
// Break up long strings into shorter chunks for PLASMA.
// Note: this used to be 253, but still had some random mem overwrites.
// Decreasing to chunks of 200 seems to fix it.
def text = getSingle(getSingle(valBlk, null, 'text').field, 'TEXT').text()
def chunks = text.findAll(/.{200}|.*/).grep(~/.+/)
if (!text || text == "") // interpret lack of text as a single empty string
chunks = [""]
// Decreasing to chunks of 200 seems to fix it.
// Note: Take special care not to break things like "^M" into two separate chunks.
def chunks = []
def buf = new StringBuilder()
def count = 0
text.each { ch ->
buf << ch
if (ch != '^')
++count
if (count >= 200) {
chunks << buf.toString()
buf.setLength(0)
count = 0
}
}
chunks << buf.toString()
// Now display each string
chunks.eachWithIndex { chunk, idx ->
String str = (idx == chunks.size()-1 && finishWithNewline) ? chunk+"\\n" : chunk
outIndented("scriptDisplayStr(" + escapeString(str) + ")\n")

View File

@ -18,18 +18,6 @@ include "gen_images.plh"
include "gen_modules.plh"
include "gen_players.plh"
const RWTS_SEEK = 0
const RWTS_READ = 1
const RWTS_WRITE = 2
const RWTS_DRV1 = 0
const RWTS_DRV2 = $80
const RWTS_RDWRPART = (0<<8)
const RWTS_OPENDIR = (1<<8)
const LOAD_SAVE_BUF = $4E00
const fontEngine = $EC00 // main mem LC
const fontEngineLen = $F00 // really a bit less, but this leaves space for debug code
const fontData = $FB00 // main mem LC
@ -41,14 +29,12 @@ const expandMax = $3600 // max size of unsplit expander
// Exported functions go here. First a predef for each one, then a table with function pointers
// in the same order as the constants are defined in the the header.
predef _startup()#1
predef _saveGame()#1
predef _loadGame()#1
predef _newOrLoadGame(ask)#1
//AUTOMAP_CHECK// predef _checkAutomap()#1
word[] funcTbl = @_startup, @_saveGame, @_loadGame, @_newOrLoadGame
word[] funcTbl = @_startup, @_loadGame, @_newOrLoadGame
//AUTOMAP_CHECK// word = @_checkAutomap
byte[] game1_filename = "GAME.1.SAVE"
byte[] legendos_filename = "LEGENDOS.SYSTEM"
// For checking automap mark sizes
@ -176,53 +162,6 @@ asm clearMarkBits(pMarks)#0
rts
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Params: cmd | open<<8, filename, addr, size. Returns: status (for open only)
asm callProRWTS(cmdPlusOpenFlg, filename, addr, size)#1
+asmPlasmRet 4
; Params come to us from PLASMA in reverse order
sta setAuxZP
sta sizelo
sty sizehi
sta clrAuxZP
lda evalStkL+1,x
ldy evalStkH+1,x
sta setAuxZP
sta ldrlo
sty ldrhi
sta clrAuxZP
lda evalStkL+2,x
ldy evalStkH+2,x
sta setAuxZP
sta namlo
sty namhi
sta clrAuxZP
lda evalStkL+3,x
ldy evalStkH+3,x
sta setAuxZP
sta reqcmd
lda #0
sta auxreq
bit setLcRW+lcBank1
bit setLcRW+lcBank1
tya
bne +
jsr proRWTS
clc
bcc ++
+ jsr proRWTS+3
++ lda status
ldy #0
bit setLcRW+lcBank2
bit setLcRW+lcBank2
sta clrAuxZP
rts
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// It's a little tricky reseeking ProRWTS's file marker
asm reseekRwts#0
@ -321,25 +260,11 @@ def _startup()#1
return 0
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def _rwGame(cmd)#0
while TRUE
if callProRWTS(cmd | RWTS_OPENDIR, @game1_filename, LOAD_SAVE_BUF, HEAP_SIZE) == 0
break
fin
textHome()
^$c051
puts("Insert disk 1")
rdkey()
^$c050
loop
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def readDiskMarks()#1
word size
// First, read in the marks. Seek past the heap, then read the length
if callProRWTS(RWTS_SEEK | RWTS_OPENDIR, @game1_filename, NULL, HEAP_SIZE) <> 0
if callProRWTS(RWTS_SEEK | RWTS_OPENDIR, @S_GAME1_FILENAME, NULL, HEAP_SIZE) <> 0
fatal("read marks")
fin
callProRWTS(RWTS_READ | RWTS_RDWRPART, NULL, LOAD_SAVE_BUF, 2)
@ -388,26 +313,12 @@ end
//AUTOMAP_CHECK// return 0
//AUTOMAP_CHECK// end
///////////////////////////////////////////////////////////////////////////////////////////////////
def _saveGame()#1
// Perform garbage collection and record the size of the heap so we can restore it correctly
// (also does a CHECK_MEM to be sure we never save corrupted heap)
heapCollect()
//AUTOMAP_CHECK// readDiskMarks; checkMarks
// Copy data to main memory, and write it out.
memcpy(HEAP_BOTTOM, LOAD_SAVE_BUF, HEAP_SIZE, 0) // LC to low mem
_rwGame(RWTS_WRITE)
return 0
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def loadInternal()#1
word p_loaded
// Load data to main memory
_rwGame(RWTS_READ)
rwGame(RWTS_READ)
// Copy the heap up, and init it with the correct size.
p_loaded = LOAD_SAVE_BUF
@ -445,7 +356,7 @@ def gameExists()#1
word p_loaded
// Load first part of save game into mem... 1 block should be plenty to verify it's real.
if callProRWTS(RWTS_READ | RWTS_OPENDIR, @game1_filename, LOAD_SAVE_BUF, 512) == 0
if callProRWTS(RWTS_READ | RWTS_OPENDIR, @S_GAME1_FILENAME, LOAD_SAVE_BUF, 512) == 0
// If heap size is reasonable and type hash matches, chances are high that it's a real save game.
p_loaded = LOAD_SAVE_BUF
if p_loaded=>w_heapSize >= 100 and p_loaded=>w_heapSize <= HEAP_SIZE and p_loaded=>w_typeHash == typeHash
@ -515,7 +426,8 @@ def importGame()#1
^$25 = 20
puts("\n Game imported.")
reinsert()
_saveGame()
memcpy(HEAP_BOTTOM, LOAD_SAVE_BUF, HEAP_SIZE, 0) // LC to low mem
rwGame(RWTS_WRITE)
return TRUE
fin
puts("\n Not found.")
@ -587,7 +499,7 @@ def clearDiskMarks()#0
// First, read in the marks.
size = readDiskMarks()
if callProRWTS(RWTS_SEEK | RWTS_OPENDIR, @game1_filename, NULL, HEAP_SIZE) <> 0
if callProRWTS(RWTS_SEEK | RWTS_OPENDIR, @S_GAME1_FILENAME, NULL, HEAP_SIZE) <> 0
fatal("read marks")
fin
callProRWTS(RWTS_READ | RWTS_RDWRPART, NULL, LOAD_SAVE_BUF, 2)

View File

@ -10,7 +10,6 @@
// Each module-exported function needs its own constant, 0..n
const diskops_startup = 0
const diskops_saveGame = 2
const diskops_loadGame = 4
const diskops_newOrLoadGame = 6
const diskops_loadGame = 2
const diskops_newOrLoadGame = 4
//AUTOMAP_CHECK// const diskops_checkAutomap = 8

View File

@ -30,6 +30,7 @@ import gamelib
predef calcPlayerArmor(player)#0
predef calcWidth(pStr)#1
predef callGlobalFunc(moduleNum, arg1, arg2, arg3)#1
predef callProRWTS(cmdPlusOpenFlg, filename, addr, size)#1
predef charToUpper(c)#1
predef checkEncounter(x, y, force)#0
predef clearEncounterZones()#0
@ -116,6 +117,7 @@ import gamelib
predef rightJustifyStr(str, rightX)#0
predef rollDice(encoded)#1
predef roomInPack(p_player)#1
predef rwGame(cmd)#0
predef scanForNamedObj(p_obj, name)#1
predef scriptCombat(mapCode)#1
predef scriptCopyTile(fromX, fromY, toX, toY)#0
@ -192,4 +194,7 @@ import gamelib
// Next: other useful strings
byte[] S_HIS, S_HER, S_THEIR
// Load/save filename
byte[] S_GAME1_FILENAME
end

View File

@ -75,6 +75,7 @@ predef pause(count)#1
predef printf1(str, arg1)#0
predef printf2(str, arg1, arg2)#0
predef playerDeath()#0
predef saveGame()#1
predef setStat(player, statName, val)#0
predef startGame(firstTime, ask)#0
predef showAnimFrame()#0
@ -98,6 +99,7 @@ byte texturesLoaded = FALSE
byte textDrawn = FALSE
byte anyInteraction = FALSE
byte textClearCountdown = 0
byte forceRawScrDisp = FALSE
export byte isPlural = 0
byte inScript = FALSE
export byte isFloppyVer
@ -164,6 +166,8 @@ export byte nextSignificantMinute
byte snoozeX0, snoozeX1, snoozeY
word timeEventFunc
export byte[] S_GAME1_FILENAME = "GAME.1.SAVE"
// Context for lambda functions (in lieu of closures, for now at least)
export word ctx
@ -211,6 +215,7 @@ asm _defs
!source "../../include/plasma.i"
!source "../../include/mem.i"
!source "../../include/fontEngine.i"
!source "../../include/prorwts.i"
; Optional debug printing support
DEBUG = 0
@ -1161,6 +1166,53 @@ asm scanScripts(x, y, triggerTbl, mapScripts)#1
}
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Params: cmd | open<<8, filename, addr, size. Returns: status (for open only)
export asm callProRWTS(cmdPlusOpenFlg, filename, addr, size)#1
+asmPlasmRet 4
; Params come to us from PLASMA in reverse order
sta setAuxZP
sta sizelo
sty sizehi
sta clrAuxZP
lda evalStkL+1,x
ldy evalStkH+1,x
sta setAuxZP
sta ldrlo
sty ldrhi
sta clrAuxZP
lda evalStkL+2,x
ldy evalStkH+2,x
sta setAuxZP
sta namlo
sty namhi
sta clrAuxZP
lda evalStkL+3,x
ldy evalStkH+3,x
sta setAuxZP
sta reqcmd
lda #0
sta auxreq
bit setLcRW+lcBank1
bit setLcRW+lcBank1
tya
bne +
jsr proRWTS
clc
bcc ++
+ jsr proRWTS+3
++ lda status
ldy #0
bit setLcRW+lcBank2
bit setLcRW+lcBank2
sta clrAuxZP
rts
end
///////////////////////////////////////////////////////////////////////////////////////////////////
// The following only used for speed testing
//asm readNoSlotClock(dstBuf)#0 // param: dstBuf (will receive 8 BCD bytes)
@ -2098,6 +2150,7 @@ export def textureControl(flg)#0
util3d = NULL
fin
showingLamp = FALSE
needRender = FALSE
fin
fin
texturesLoaded = flg
@ -2191,13 +2244,17 @@ end
// Called by scripts to display a string. We set the flag noting that something has been
// displayed, then use an assembly routine to do the work.
def _scriptDisplayStr(str)#0
if renderLoaded and !curPortrait and !curFullscreenImg and needRender
if needRender and renderLoaded and texturesLoaded and !curPortrait and !curFullscreenImg
doRender()
flipToPage1()
needRender = FALSE
fin
if textClearCountdown; clearTextWindow(); fin
displayStr(str)
if forceRawScrDisp
rawDisplayStr(str)
else
displayStr(str)
fin
textDrawn = TRUE
anyInteraction = TRUE
end
@ -2381,6 +2438,7 @@ export def setMap(is3D, num, x, y, dir)#0
mapIs3D = is3D
mapNum = num
initMap(x, y, dir)
saveGame
fin
// Don't send enter event, because we often land on an "Exit to wilderness?" script
//NO:scriptEvent(S_ENTER, NULL)
@ -2480,7 +2538,7 @@ export def showMapName(mapName)#0
if newNameHash <> mapNameHash
setWindow1()
clearWindow()
rawDisplayf1("^Y%s^N", mapName)
centerStr(mapName, 84)
if mapIs3D and texturesLoaded; copyWindow(0); fin
mapNameHash = newNameHash
fin
@ -2919,13 +2977,45 @@ export def checkEncounter(x, y, force)#0
fin
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def rwGame(cmd)#0
while TRUE
if callProRWTS(cmd | RWTS_OPENDIR, @S_GAME1_FILENAME, LOAD_SAVE_BUF, HEAP_SIZE) == 0
break
fin
textHome()
^$c051
puts("Insert disk 1")
rdkey()
^$c050
loop
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def saveGame()#1
word cursX, cursY
cursX, cursY = getCursor()
saveMapPos()
flipToPage1()
showMapName("Saving game...")
loadEngine(MOD_DISKOPS)=>diskops_saveGame()
returnFromEngine(TRUE)
textureControl(FALSE) // also flips to page 1
// Perform garbage collection and record the size of the heap so we can restore it correctly
// (also does a CHECK_MEM to be sure we never save corrupted heap)
heapCollect()
//AUTOMAP_CHECK// readDiskMarks; checkMarks
// Copy data to main memory, and write it out.
memcpy(HEAP_BOTTOM, LOAD_SAVE_BUF, HEAP_SIZE, 0) // LC to low mem
rwGame(RWTS_WRITE)
mapNameHash = 0; showMapName(global=>s_mapName)
doRender
setWindow2()
setCursor(cursX, cursY)
return 0
end
@ -2948,7 +3038,9 @@ end
def help()#1
flipToPage1
setBigWindow; clearWindow
forceRawScrDisp = TRUE
loadEngine(GS_HELP)()
forceRawScrDisp = FALSE
returnFromEngine(TRUE)
return 0
end
@ -3577,8 +3669,6 @@ def startGame(firstTime, ask)#0
initMap(q_x, q_y, q_dir)
saveGame()
promptHelp
showMoveMode
displayStr("Ctrl-C to change.\n")
setTextCountdown
else
q_mapNum = 0

View File

@ -93,4 +93,17 @@ const EMUSIG_2D_MAP = $C022 // e.g. wilderness
const EMUSIG_3D_MAP = $C023 // e.g. in town
const EMUSIG_AUTOMAP = $C024 // all color except the map title
const EMUSIG_STORY = $C025 // all text except a portrait
const EMUSIG_TITLE = $C026 // all color except title screen menu area
const EMUSIG_TITLE = $C026 // all color except title screen menu area
// Game load/save
const RWTS_SEEK = 0
const RWTS_READ = 1
const RWTS_WRITE = 2
const RWTS_DRV1 = 0
const RWTS_DRV2 = $80
const RWTS_RDWRPART = (0<<8)
const RWTS_OPENDIR = (1<<8)
const LOAD_SAVE_BUF = $4E00