CF (CurrentFiles) – Methods
Here are psuedocode write-ups of the methods of CF. They should all be complete decompilations except for in the last “incomplete” section. Index of CF Methods (csv format).
All “get” and “set” methods are omitted; some are included in their context on the commits page. The ones named “DataCur” get/set file FC; “DataA” and “DataB” get/set FA/FB rsp.
chk <data> is a macro meaning sign the object with its checksum, i.e.:
<data>[chkIndex] = calcChecksum(<data>, chkIndex) (as appropriate)
where chkIndex is 0x53bc for Files and 0x20 for Tails.
File Methods
8000abc0
| fileInit(k)
k = 0,1; <callers: 801b9790 (k=1) on reset; 801bbdf0 (k=0) on starting new file >
set _u0[4] = true
set parameters on file = FA (k = 0), FB (k = 1):
5302 [2]: 24 // total hearts
5304 [2]: 24 // ??? hearts
5306 [2]: 24 // current hearts
5308 [2]: 0
531c [20]: "F405" // full [20] buffer copied from `80574aa8` (= r13 - 0x7bf8)
53a5 [1]: 0
53a9 [1]: 1
53ad [1]: 0
53ae [1]: 11
53b0 [1]: 8
53b1 [1]: 8
53b2 [1]: 8
8000d390
| fileLoadSelected()
FS → FA
cf.fileLoad(cf.selectedFileNo)
8000d3a0
| fileLoad(n)
Fn → FA
if n != 0,1,2: return
if cf.getFooter-chkB(n) == 0: // if checksum not stale
copy Fn → FA
copy st.tailsExt[n] → fileTail
else:
return cf.fileClearA()
8000dae0
| fileCopyFBToFCur()
FB → FC
copy FB → FC
8000e180
| fileSaveSelected()
FA → FS; <caller: 80014770 on save>
cf.fileSave(cf.selectedFileNo)
8000e190
| fileSave(n)
FA → Fn
if n != 0,1,2: return
chk FA
copy FA → Fn
chk fileTail
copy fileTail → sf.tailsInt[n]
8000e8e0
| fileCopy(m, n)
Fm → Fn; <caller: 80014610 on copy>
if m != 0,1,2 or n != 0,1,2: return
chk Fm
copy Fm → Fn
chk sf.tailsInt[m]
copy sf.tailsInt[m] → sf.tailsInt[n]
chk st.tailsExt[m]
copy st.tailsExt[m] → st.tailsExt[n]
8000f0a0
| fileSaveSelected-2()
FA → FS; <caller: 800146d0 on delete>
if s:=cf.selectedFileNo != 0,1,2: return
chk FA
copy FA → FS
chk fileTail
copy fileTail → sf.tailsInt[s]
copy fileTail → st.tailsExt[s]
8000f850
| fileCopyFCurToFB()
FC → FB
copy FC → FB
8000ff10
| tailSaveSelected()
if s:=cf.selectedFileNo != 0,1,2: return
chk fileTail
copy fileTail → st.tailsExt[s]
80010080
| fileClearA()
0 → FA; <caller: 800146d0 on delete>
set FA to 0
set FA[53ad] = 1
chk FA
set fileTail to 0
chk fileTail
Core Methods
80010560
| reset()
<caller: 801b9790 on reset> {put a memory breakpoint on FA}
More on loadToCurrent() on the commits page.
set FA to 0 // size [53c0]
set FB to 0 // size [53c0]
set fileTail to 0 // size [24]
loadToCurrent()
800115e0
| isFileInactive()
Determines FC, the current file. Return of false means FA; true means FB. In practice, FC = FA during gameplay or while a file is being anti-committed, and FB otherwise.
ptr = FUN_802e2d80(1,0) // seems to return *805789f4 – namely the respawner object
return ptr != 0 && (*(short*)(ptr + 8) == 0) // this data is 0 iff title-screen
&& cf.anticommitFlag == false // set during file selects/starts
800113d0
| calcChecksum(data, size)
return checksum(data, size) // the fn at 803b0ae0
Spawn Data Commits
80010340
| commitType1DataToFA(x)
Called during a save; commits Link’s co-ords and location.
FA := cf.getFileA() // fn 800113b0, returns 80955464
linkPtr := getLinkPtr() // fn 8005c6f0, returns 80578a18
spawnSlave := *805b6ae0 // see re/spawn
reloadLayer := *805789fc // adjacent to data used by reloader
reloaderPtr := *805789f4 // see re/spawn
if linkPtr != nullptr:
FA[0010] = linkPtr[0c0] // x pos (float) → FA t1 x-pos
FA[0014] = linkPtr[0c4] // y pos (float) → FA t1 y-pos
FA[0018] = linkPtr[0c8] // z pos (float) → FA t1 z-pos
FA[530e] = linkPtr[13e] // velocity angle (short) → FA t1 angle
if *805789c0 != nullptr:
FA[5308] = *805789c0[2398] // still dunno what this is (short)
if *80578958 != nullptr:
FA[08d0] = FUN_8019a050(*80578958) // gets area index (from *80578958[7964][12])
if reloaderPtr != nullptr:
FA[531c] = spawnSlave[0] // slave spawn area → FA t1 area
FA[53b3] = spawnSlave[25] // slave spawn night → FA t1 night
FA[53a5] = reloadLayer // reloader layer → FA t1 forced layer
FA[53a8] = spawnSlave[24] // slave spawn entrance → FA t1 entrance
FA[53a9] = x // unknown
*8052e8d8 = FA[539c] (copy 9B) // expanded fn 80195720: loadSkyKeepPuzzle()
80011650
| commitType2DataToFA()
FA := cf.getFileA() // fn 800113b0, returns 80955464
linkPtr := getLinkPtr() // fn 8005c6f0, returns 80578a18
if linkPtr != nullptr:
FA[001c] = linkPtr[0c0] // x pos (float) → FA t2 x-pos
FA[0020] = linkPtr[0c4] // y pos (float) → FA t2 y-pos
FA[0024] = linkPtr[0c8] // z pos (float) → FA t2 z-pos
FA[5310] = linkPtr[13e] // velocity angle (short) → FA t2 angle
if *805789c0 != nullptr:
FA[530a] = *805789c0[2398] // still dunno what this is (short)
if reloaderPtr != nullptr:
FA[533c] = spawnSlave[0] // slave spawn area → FA t2 area
FA[53a6] = reloadLayer // reloader layer → FA t2 forced layer
FA[53aa] = spawnSlave[24] // slave spawn entrance → FA t2 entrance
80011730
| commitType3DataToFC(pos, ang)
Called during a load; commits Link’s co-ords and location, then does something mysterious. Note that unlike the other 2 commits, this one targets FileC (so will commit to FileB, i.e. BiT file, when doing a load during BiT).
// expanded fn 8000b000: cf.setDataCur-0028(linkPos)
FC[0028] = pos[0] // x pos (float) → FC t3 x-pos
FC[002c] = pos[1] // y pos (float) → FC t3 y-pos
FC[0030] = pos[2] // z pos (float) → FC t3 z-pos
// the following 8 FC sets are all expanded function calls
FC[5312] = *(ang + 2) // velocity angle (short) → FC t3 angle
if *805789c0 != nullptr:
FC[530c] = *805789c0[2398] // still dunno what this is (short)
if reloaderPtr != nullptr:
FC[535c] = spawnSlave[0] // slave spawn area → FC t3 area
FC[53b4] = spawnSlave[25] // slave spawn night → FC t3 night
FC[53a7] = reloadLayer // reloader layer → FC t3 forced layer
FC[53ab] = spawnSlave[24] // slave spawn entrance → FC t3 entrance
FC[53a9] = 0
FC[53b5] = 2
**(*8057865c+24)(*8057865c, 0x77) // unknown dynamic function call
Footer
800113e0
| loadFooter()
cf.determineFooter-chkA()
cf.loadFSDataToFooter()
8000a120
| loadFSDataToFooter()
cf._u0[3] = false
for n in [0,3):
if (Fn[0x53ad] != 1 && cf.getFooter-chkB(n) != 1):
cf._u0[3] = true;
copy Fn.getOffset-heroname() → cf.heronames[n] // upto min(len,8) utf16, then appends \x0
cf.savetimes[n] = Fn[0x8]
cf.curhearts[n] = Fn[0x5306]
w = count for x in (0x7c0 + 0x4*i, i in [0,8)) if (*(uint*)Fn[x] & 0xffff) == 0x72
cf.widths[n] = max(w*4 + Fn[0x5302], 0x50)
SF/ST methods
8000a400
| initSFandFSData()
cf._u0[0] = true
cf.resetSFandFSData()
cf.opFlag = false
cf.selectedFileNo = 1
80010120
| resetSFandFSData()
set SF to 0 (size [fbe0])
cf.selectedFileNo = 0;
for n in [0,3): cf.chkA[n] = 0
for n in [0,3):
cf.heronames[n] = \x0
cf.savetimes[n] = 0 (size [8] each)
cf.curhearts[n] = 0
cf.widths[n] = 0
sf.initSOUJ() // writes "SOUJ" to first 4B of sf
sf->header + 0x1c = 0x1d (size [4])
for n in [0,3):
Fn[0x53ad] = 1
chk Fn
for n in [0,3):
chk sf.tailsInt[n]
cf.fileClearA()
cf._u0[1] = false
cf._u0[2] = false
cf._u0[3] = false
cf._u0[4] = false
cf._u0[5] = false
cf.errorFlag = false
for n in [0,3): cf.chkB[n] = 0
cf.resetST()
80010280
| resetST()
set ST to 0 // size [80]
for n in [0,3): chk st.tailsExt[n]
for n in [0,3): cf.chkC[n] = 0
80010470
| tailsCopySFtoST(n)
if cf.getFooter-chkB(n) == false:
copy sf.tailsInt[n] → st.tailsExt[n]
else:
set sf.tailsInt[n] to 0 // size [20]
chk sf.tailsInt[n]
cf.chkC[n] = false
80011510
| SFMatchesGameID
Checks if SF has the correct Game ID (including region)
return sf.gameID == "SOUJ" // compare 4 chars
Checksum Flag Tests
80011420
| determineFooter-chkA()
for n in [0,3): cf.chkA[n] = (Fn[0x53ad] == 1)
8000d2f0
| determineFooter-chkC()
for n in [0,3): cf.chkC[n] = (cf.saveTails[n][0x20] != calcChecksum(cf.saveTails[n], 0x20))
Note: chkB is determined during CF::verifySF()
80011590
| isSFFileChecksumCorrect(n)
return Fn[0x53bc] == calcChecksum(Fn, 0x53bc)
Incomplete
These decompilations are incomplete.
80009ed0
| CF (the constructor)
constructs something at offset 0x34 of FA and FB
for i in [0,3]: cf.heronames[i] = '\x0'
cf.area = '\0'
*(r13-0x4444) = this // assigns the static pointer for CF
initialises SF and stores ptr in cf.saveFiles
initialises ST and stores ptr in cf.saveTails
initSFandFSData(this)
return this
8000a050 |
_f0 assigns SF and ST? |
8000a090 |
_f1 backs up SF and ST? |
800105c0 |
_f2 generates a post-ending file (hero mode or pre-Demise) |
8000d1d0
| verifySF()
cf._u0[5] = _f3(???) == 0 || *(int *)(sf.header[0x1c]) != 0x1d
for n in [0,3):
cf.chkB[n] = (cf.isSFFileChecksumCorrect(n) == 0)
for n in [0,3):
if (*(uint *)(sf.tailsInt[n][0x20] != cf.calcChecksum(sf.tailsInt[n], 0x20)):
set sf.tailsInt[n] to 0 (size [20])
chk sf.tailsInt[n]