mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-10-02 03:38:08 +03:00
Define a dedicated `vmvar_t` type for values stored in variable pages and propagate it through interfaces that expose those values. Keep the type as int for now so this commit does not change runtime behavior. This separates VM storage from ordinary int buffers and makes a later conversion to 16-bit storage mechanically checkable.
728 lines
18 KiB
C
728 lines
18 KiB
C
/*
|
|
* savedate.c セーブデータの管理
|
|
*
|
|
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
|
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
/* $Id: savedata.c,v 1.36 2003/07/21 23:06:47 chikama Exp $ */
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#ifdef __EMSCRIPTEN__
|
|
#include <emscripten.h>
|
|
#else
|
|
typedef int emscripten_align1_int;
|
|
#endif
|
|
|
|
#include "portab.h"
|
|
#include "savedata.h"
|
|
#include "scenario.h"
|
|
#include "xsystem35.h"
|
|
#include "LittleEndian.h"
|
|
#include "filecheck.h"
|
|
#include "windowframe.h"
|
|
#include "selection.h"
|
|
#include "message.h"
|
|
|
|
const char *save_signature[] = {
|
|
[SAVEFMT_XSYS35] = "System3.5 SavaData(c)ALICE-SOFT",
|
|
[SAVEFMT_SYS36] = "System3.5 SaveData(c)ALICE-SOFT",
|
|
[SAVEFMT_SYS38] = "System3.8 SaveData(c)ALICE-SOFT",
|
|
};
|
|
|
|
#define SAVE_DATAVERSION 0x350200
|
|
|
|
typedef struct {
|
|
uint16_t x;
|
|
uint16_t y;
|
|
uint16_t width;
|
|
uint16_t height;
|
|
} RectangleW;
|
|
|
|
typedef struct {
|
|
char ID[32];
|
|
int version;
|
|
char gameName[28];
|
|
uint8_t selMsgSize;
|
|
uint8_t selMsgColor;
|
|
uint8_t selBackColor;
|
|
uint8_t selFrameColor;
|
|
uint8_t msgMsgSize;
|
|
uint8_t msgMsgColor;
|
|
uint8_t msgBackColor;
|
|
uint8_t msgFrameColor;
|
|
uint8_t rsvB1;
|
|
uint8_t rsvB2;
|
|
uint8_t rsvB3;
|
|
uint8_t rsvB4;
|
|
uint8_t rsvB5;
|
|
uint8_t rsvB6;
|
|
uint8_t rsvB7;
|
|
uint8_t rsvB8;
|
|
int scoPage;
|
|
int scoIndex;
|
|
int rsvI1;
|
|
int rsvI2;
|
|
RectangleW selWinInfo[SELWINMAX];
|
|
RectangleW msgWinInfo[MSGWINMAX];
|
|
int stackinfo;
|
|
int varStr;
|
|
int rsvI3;
|
|
int rsvI4;
|
|
int varSys[256];
|
|
int rsvI[228];
|
|
} asd_baseHdr;
|
|
|
|
typedef struct {
|
|
int size;
|
|
int count;
|
|
int maxlen;
|
|
int rsv1;
|
|
} asd_strVarHdr;
|
|
|
|
typedef struct {
|
|
int size;
|
|
int rsv1;
|
|
int rsv2;
|
|
int rsv3;
|
|
} asd_stackHdr;
|
|
|
|
typedef struct {
|
|
emscripten_align1_int size;
|
|
emscripten_align1_int pageNo;
|
|
emscripten_align1_int rsv1;
|
|
emscripten_align1_int rsv2;
|
|
} asd_varPageHdr;
|
|
|
|
static enum save_format save_format = SAVEFMT_SYS38;
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
EM_JS(void, scheduleSync, (), {
|
|
xsystem35.shell.syncfs();
|
|
});
|
|
#else
|
|
#define scheduleSync()
|
|
#endif
|
|
|
|
static void fputw(uint16_t n, FILE *fp) {
|
|
fputc(n & 0xff, fp);
|
|
fputc(n >> 8, fp);
|
|
}
|
|
|
|
static int saveStack(enum save_format format, FILE *fp) {
|
|
int size;
|
|
uint8_t *data = sl_saveStack(format, &size);
|
|
|
|
asd_stackHdr head = { .size = size };
|
|
fwrite(&head, sizeof(head), 1, fp);
|
|
if (size > 0)
|
|
fwrite(data, size, 1, fp);
|
|
free(data);
|
|
return sizeof(head) + size;
|
|
}
|
|
|
|
static void loadStack(enum save_format format, char *buf) {
|
|
asd_stackHdr *head = (asd_stackHdr *)buf;
|
|
uint8_t *data = buf + sizeof(asd_stackHdr);
|
|
sl_loadStack(format, data, head->size);
|
|
}
|
|
|
|
static int saveStrVars(enum save_format format, FILE *fp) {
|
|
const int base = format == SAVEFMT_XSYS35 ? 1 : 0;
|
|
asd_strVarHdr head = {
|
|
.size = 0,
|
|
.count = svar_maxindex() + (1 - base),
|
|
.maxlen = (format == SAVEFMT_XSYS35 ? 101 : 0) // so that old versions of xystem35 can read this save file
|
|
};
|
|
fseek(fp, sizeof(head), SEEK_CUR);
|
|
|
|
for (int i = base; i <= svar_maxindex(); i++) {
|
|
const char *s = svar_get(i);
|
|
int len = strlen(s) + 1;
|
|
fwrite(s, len, 1, fp);
|
|
head.size += len;
|
|
}
|
|
if (ferror(fp))
|
|
return 0;
|
|
fseek(fp, -(sizeof(head) + head.size), SEEK_CUR);
|
|
fwrite(&head, sizeof(head), 1, fp);
|
|
fseek(fp, head.size, SEEK_CUR);
|
|
|
|
return sizeof(head) + head.size;
|
|
}
|
|
|
|
static void loadStrVars(enum save_format format, char *buf) {
|
|
asd_strVarHdr *head = (asd_strVarHdr *)buf;
|
|
const int base = format == SAVEFMT_XSYS35 ? 1 : 0;
|
|
|
|
int cnt = head->count;
|
|
if ((1 - base) + svar_maxindex() != cnt) {
|
|
WARNING("Unexpected number of strings in savedata (%d, expected %d)", cnt, (1 - base) + svar_maxindex());
|
|
svar_init(format == SAVEFMT_XSYS35 ? cnt : cnt - 1);
|
|
}
|
|
buf += sizeof(asd_strVarHdr);
|
|
for (int i = 0; i < cnt; i++) {
|
|
svar_set(i + base, buf);
|
|
buf += strlen(buf) + 1;
|
|
}
|
|
}
|
|
|
|
static int saveVarPage(int page, FILE *fp) {
|
|
if (!varPage[page].saveflag)
|
|
return 0;
|
|
int cnt = varPage[page].size;
|
|
vmvar_t *var = varPage[page].value;
|
|
if (!var)
|
|
return 0;
|
|
asd_varPageHdr head = {
|
|
.size = cnt * sizeof(uint16_t),
|
|
.pageNo = page
|
|
};
|
|
fwrite(&head, sizeof(head), 1, fp);
|
|
for (int i = 0; i < cnt; i++)
|
|
fputw(var[i], fp);
|
|
|
|
return sizeof(head) + head.size;
|
|
}
|
|
|
|
static int loadVarPage(char *buf) {
|
|
asd_varPageHdr *head = (asd_varPageHdr *)buf;
|
|
int page = head->pageNo;
|
|
|
|
int cnt = head->size / sizeof(uint16_t);
|
|
if (varPage[page].size < cnt || varPage[page].value == NULL) {
|
|
if (!v_allocatePage(page, cnt, true)) {
|
|
WARNING("Array allocation failed: page=%d size=%d", page, cnt);
|
|
return SAVE_LOADERR;
|
|
}
|
|
}
|
|
vmvar_t *var = varPage[page].value;
|
|
uint16_t *data = (uint16_t *)(buf + sizeof(asd_varPageHdr));
|
|
for (int i = 0; i < cnt; i++)
|
|
*var++ = *data++;
|
|
|
|
return SAVE_LOADOK;
|
|
}
|
|
|
|
static void writeAsdFooter(enum save_format format, FILE *fp) {
|
|
if (format != SAVEFMT_XSYS35) {
|
|
// Padding(?)
|
|
for (int i = 0; i < 256; i++)
|
|
fputc(0xff, fp);
|
|
// Write a mark to indicate that this file was created by xsystem35.
|
|
fputs("XS35", fp);
|
|
}
|
|
if (format == SAVEFMT_SYS38) {
|
|
// Stack info
|
|
struct stack_info sinfo;
|
|
sl_getStackInfo(&sinfo);
|
|
int size = sinfo.page_calls * 2 + sinfo.label_calls;
|
|
int *buf = calloc(size, sizeof(int));
|
|
int *ptr = buf + size;
|
|
int *vars = NULL;
|
|
int *label_calls = NULL;
|
|
struct stack_frame_info *sfi = NULL;
|
|
while ((sfi = sl_next_stack_frame(sfi)) != NULL) {
|
|
switch (sfi->tag) {
|
|
case STACK_NEARCALL:
|
|
if (label_calls)
|
|
(*label_calls)++;
|
|
vars = --ptr;
|
|
break;
|
|
case STACK_FARCALL:
|
|
vars = --ptr;
|
|
label_calls = --ptr;
|
|
break;
|
|
case STACK_VARIABLE:
|
|
if (vars)
|
|
(*vars)++;
|
|
break;
|
|
}
|
|
}
|
|
// Note that only the first `size` byte of the `size` words data is
|
|
// written, so information is lost.
|
|
fwrite(ptr, size, 1, fp);
|
|
fwrite(&size, 4, 1, fp);
|
|
free(buf);
|
|
fputs("INFS", fp);
|
|
}
|
|
}
|
|
|
|
/* ゲームデータのロード
|
|
|
|
no: セーブファイル番号 0~
|
|
*status: ステータス
|
|
*size: データの大きさを返すポインタ
|
|
|
|
あとで free(*buf)するのを忘れないように
|
|
*/
|
|
static void* loadGameData(int no, int *status, int *size) {
|
|
void *buf = NULL;
|
|
FILE *fp = fopen(nact->files.save_fname[no], "rb");
|
|
if (!fp)
|
|
goto errexit;
|
|
fseek(fp, 0L, SEEK_END);
|
|
long filesize = ftell(fp);
|
|
if (filesize == 0)
|
|
goto errexit;
|
|
|
|
buf = malloc(filesize);
|
|
if (buf == NULL)
|
|
goto errexit;
|
|
|
|
fseek(fp, 0L, SEEK_SET);
|
|
if (fread(buf, filesize, 1, fp) != 1)
|
|
goto errexit;
|
|
fclose(fp);
|
|
|
|
*size = (int)filesize;
|
|
*status = SAVE_LOADOK;
|
|
return buf;
|
|
|
|
errexit:
|
|
if (buf != NULL)
|
|
free(buf);
|
|
if (fp != NULL)
|
|
fclose(fp);
|
|
*status = SAVE_LOADERR;
|
|
return NULL;
|
|
}
|
|
|
|
static int saveGameData(int no, char *buf, int size) {
|
|
FILE *fp;
|
|
int status = SAVE_SAVEOK1;
|
|
|
|
fc_backup_oldfile(nact->files.save_fname[no]);
|
|
fp = fopen(nact->files.save_fname[no], "wb");
|
|
if (fp == NULL) {
|
|
return SAVE_SAVEERR;
|
|
}
|
|
if (1 != fwrite(buf, size, 1, fp)) {
|
|
status = SAVE_SAVEERR;
|
|
}
|
|
fclose(fp);
|
|
scheduleSync();
|
|
return status;
|
|
}
|
|
|
|
bool save_setFormat(const char *format_name) {
|
|
if (!strcmp(format_name, "xsystem35"))
|
|
save_format = SAVEFMT_XSYS35;
|
|
else if (!strcmp(format_name, "system36"))
|
|
save_format = SAVEFMT_SYS36;
|
|
else if (!strcmp(format_name, "system38"))
|
|
save_format = SAVEFMT_SYS38;
|
|
else if (!strcmp(format_name, "system39"))
|
|
save_format = SAVEFMT_SYS38;
|
|
else {
|
|
WARNING("unknown save format %s", format_name);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* savefile を参照 */
|
|
const char *save_get_file(int index) {
|
|
return nact->files.save_fname[index];
|
|
}
|
|
|
|
/* savefile を削除 */
|
|
int save_delete_file(int index) {
|
|
int ret = unlink(nact->files.save_fname[index]);
|
|
|
|
if (ret == 0) {
|
|
return 1;
|
|
}
|
|
return 1; /* とりあえず */
|
|
}
|
|
|
|
// QE command
|
|
int save_vars_to_file(char *fname_utf8, struct VarRef *src, int cnt) {
|
|
// FIXME: System39.exe does not truncate existing file.
|
|
FILE *fp = fc_open(fname_utf8, 'w');
|
|
if (!fp)
|
|
return SAVE_SAVEERR;
|
|
|
|
if (cnt > v_sliceSize(src)) {
|
|
WARNING("QE: array size too small (size = %d, data count = %d)", v_sliceSize(src), cnt);
|
|
cnt = v_sliceSize(src);
|
|
}
|
|
|
|
vmvar_t *p = v_resolveRef(src);
|
|
while (cnt--)
|
|
fputw(*p++, fp);
|
|
|
|
fclose(fp);
|
|
scheduleSync();
|
|
return SAVE_SAVEOK0;
|
|
}
|
|
|
|
// LE command
|
|
int load_vars_from_file(char *fname_utf8, struct VarRef *dest, int cnt) {
|
|
FILE *fp = fc_open(fname_utf8, 'r');
|
|
if (!fp)
|
|
return SAVE_LOADERR;
|
|
|
|
uint16_t *tmp = malloc(cnt * sizeof(uint16_t));
|
|
if (!tmp)
|
|
NOMEMERR();
|
|
|
|
size_t size = fread(tmp, sizeof(uint16_t), cnt, fp);
|
|
fclose(fp);
|
|
|
|
if (size != cnt) {
|
|
WARNING("LE: data file too small (requested = %d, loaded = %d)", cnt, size);
|
|
cnt = size;
|
|
// NOTE: System39.exe never returns SAVE_LOADSHORTAGE (254).
|
|
}
|
|
|
|
if (cnt > v_sliceSize(dest)) {
|
|
WARNING("LE: array size too small (size = %d, data count = %d)", v_sliceSize(dest), cnt);
|
|
cnt = v_sliceSize(dest);
|
|
}
|
|
|
|
vmvar_t *start = v_resolveRef(dest);
|
|
for (int i = 0; i < cnt; i++)
|
|
start[i] = SDL_SwapLE16(tmp[i]);
|
|
|
|
free(tmp);
|
|
return SAVE_LOADOK;
|
|
}
|
|
|
|
int save_strs_to_file(char *fname_utf8, int start, int cnt) {
|
|
FILE *fp = fc_open(fname_utf8, 'w');
|
|
if (!fp)
|
|
return SAVE_SAVEERR;
|
|
for (int i = 0; i < cnt; i++) {
|
|
fputs(svar_get(start + i), fp);
|
|
fputc('\0', fp);
|
|
}
|
|
fclose(fp);
|
|
scheduleSync();
|
|
return 0;
|
|
}
|
|
|
|
int load_strs_from_file(char *fname_utf8, int start, int cnt) {
|
|
FILE *fp = fc_open(fname_utf8, 'r');
|
|
if (!fp)
|
|
return SAVE_LOADERR;
|
|
|
|
fseek(fp, 0L, SEEK_END);
|
|
long filesize = ftell(fp);
|
|
char *buf = malloc(filesize + 1);
|
|
if (!buf)
|
|
NOMEMERR();
|
|
|
|
fseek(fp, 0L, SEEK_SET);
|
|
int r = fread(buf, filesize, 1, fp);
|
|
fclose(fp);
|
|
if (!r) {
|
|
free(buf);
|
|
return SAVE_LOADERR;
|
|
}
|
|
|
|
buf[filesize] = '\0'; // prevents buffer overrun
|
|
char *p = buf;
|
|
for (int i = 0; i < cnt; i++) {
|
|
if (p >= buf + filesize) {
|
|
free(buf);
|
|
return SAVE_LOADSHORTAGE;
|
|
}
|
|
svar_set(start + i, p);
|
|
p += strlen(p) + 1;
|
|
}
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
|
|
/* セーブファイルのコピー */
|
|
int save_copyAll(int dstno, int srcno) {
|
|
char *saveTop;
|
|
int status, filesize;
|
|
|
|
if (dstno >= SAVE_MAXNUMBER || srcno >= SAVE_MAXNUMBER) {
|
|
return SAVE_SAVEERR;
|
|
}
|
|
saveTop = loadGameData(srcno, &status, &filesize);
|
|
if (saveTop == NULL)
|
|
return SAVE_SAVEERR;
|
|
if (((asd_baseHdr *)saveTop)->version != SAVE_DATAVERSION) {
|
|
WARNING("endian mismatch");
|
|
free(saveTop);
|
|
return SAVE_SAVEERR;
|
|
}
|
|
status = saveGameData(dstno, saveTop, filesize);
|
|
|
|
free(saveTop);
|
|
|
|
return status;
|
|
}
|
|
|
|
/* データの一部ロード */
|
|
int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
|
if (no >= SAVE_MAXNUMBER)
|
|
return SAVE_SAVEERR;
|
|
|
|
cnt = min(cnt, v_sliceSize(vref));
|
|
vmvar_t *var = v_resolveRef(vref);
|
|
|
|
int status, filesize;
|
|
char *saveTop = loadGameData(no, &status, &filesize);
|
|
if (!saveTop)
|
|
return status;
|
|
|
|
if (filesize <= sizeof(asd_baseHdr))
|
|
goto errexit;
|
|
|
|
asd_baseHdr *save_base = (asd_baseHdr *)saveTop;
|
|
if (save_base->version != SAVE_DATAVERSION) {
|
|
WARNING("endian mismatch");
|
|
goto errexit;
|
|
}
|
|
|
|
if (save_base->varSys[vref->page] == 0)
|
|
goto errexit;
|
|
|
|
char *vtop = saveTop + save_base->varSys[vref->page] + sizeof(asd_varPageHdr);
|
|
uint16_t *tmp = (uint16_t *)vtop + vref->index;
|
|
for (int i = 0; i < cnt; i++) {
|
|
*var = *tmp; tmp++; var++;
|
|
}
|
|
free(saveTop);
|
|
return SAVE_LOADOK;
|
|
|
|
errexit:
|
|
if (saveTop != NULL)
|
|
free(saveTop);
|
|
|
|
return SAVE_LOADERR;
|
|
}
|
|
|
|
/* データの一部セーブ */
|
|
int save_savePartial(int no, struct VarRef *vref, int cnt) {
|
|
if (no >= SAVE_MAXNUMBER || !varPage[vref->page].saveflag)
|
|
return SAVE_SAVEERR;
|
|
|
|
cnt = min(cnt, v_sliceSize(vref));
|
|
vmvar_t *var = v_resolveRef(vref);
|
|
|
|
int status, filesize;
|
|
char *saveTop = loadGameData(no, &status, &filesize);
|
|
if (saveTop == NULL)
|
|
return status;
|
|
if (filesize <= sizeof(asd_baseHdr))
|
|
goto errexit;
|
|
asd_baseHdr *save_base = (asd_baseHdr *)saveTop;
|
|
if (save_base->version != SAVE_DATAVERSION) {
|
|
WARNING("endian mismatch");
|
|
goto errexit;
|
|
}
|
|
char *vtop = saveTop + save_base->varSys[vref->page] + sizeof(asd_varPageHdr);
|
|
uint16_t *tmp = (uint16_t *)vtop + vref->index;
|
|
for (int i = 0; i < cnt; i++) {
|
|
*tmp = (uint16_t)*var; tmp++; var++;
|
|
}
|
|
status = saveGameData(no, saveTop, filesize);
|
|
free(saveTop);
|
|
|
|
return status;
|
|
|
|
errexit:
|
|
if (saveTop != NULL)
|
|
free(saveTop);
|
|
|
|
return SAVE_SAVEERR;
|
|
}
|
|
|
|
|
|
/* データのロード */
|
|
int save_loadAll(int no) {
|
|
if (no >= SAVE_MAXNUMBER)
|
|
return SAVE_SAVEERR;
|
|
|
|
int status, filesize;
|
|
char *saveTop = loadGameData(no, &status, &filesize);
|
|
if (!saveTop)
|
|
return status;
|
|
if (filesize <= sizeof(asd_baseHdr))
|
|
goto errexit;
|
|
/* 各種データの反映 */
|
|
asd_baseHdr *save_base = (asd_baseHdr *)saveTop;
|
|
if (save_base->version != SAVE_DATAVERSION) {
|
|
WARNING("endian mismatch");
|
|
goto errexit;
|
|
}
|
|
enum save_format format = (enum save_format)-1;
|
|
for (int i = 0; i < sizeof(save_signature) / sizeof(save_signature[0]); i++) {
|
|
if (!strcmp(save_signature[i], save_base->ID)) {
|
|
format = i;
|
|
break;
|
|
}
|
|
}
|
|
if (format < 0) {
|
|
WARNING("unrecognized save format");
|
|
goto errexit;
|
|
}
|
|
|
|
nact->sel.MsgFontSize = save_base->selMsgSize;
|
|
nact->sel.MsgFontColor = save_base->selMsgColor;
|
|
nact->sel.WinBackgroundColor = save_base->selBackColor;
|
|
nact->sel.WinFrameColor = save_base->selFrameColor;
|
|
nact->msg.MsgFontSize = save_base->msgMsgSize;
|
|
nact->msg.MsgFontColor = save_base->msgMsgColor;
|
|
nact->msg.WinBackgroundColor = save_base->msgBackColor;
|
|
nact->msg.WinFrameColor = save_base->msgFrameColor;
|
|
sl_jmpFar2(save_base->scoPage - (format == SAVEFMT_XSYS35 ? 0 : 1), save_base->scoIndex);
|
|
|
|
for (int i = 0; i < SELWINMAX; i++) {
|
|
int j = format == SAVEFMT_XSYS35
|
|
? (i + 1) % SELWINMAX // For savedata compatibility
|
|
: i;
|
|
nact->sel.wininfo[j].x = save_base->selWinInfo[i].x;
|
|
nact->sel.wininfo[j].y = save_base->selWinInfo[i].y;
|
|
nact->sel.wininfo[j].width = save_base->selWinInfo[i].width;
|
|
nact->sel.wininfo[j].height = save_base->selWinInfo[i].height;
|
|
// nact->sel.wininfo[i].save = true;
|
|
}
|
|
for (int i = 0; i < MSGWINMAX; i++) {
|
|
int j = format == SAVEFMT_XSYS35
|
|
? (i + 1) % MSGWINMAX // For savedata compatibility
|
|
: i;
|
|
nact->msg.wininfo[j].x = save_base->msgWinInfo[i].x;
|
|
nact->msg.wininfo[j].y = save_base->msgWinInfo[i].y;
|
|
nact->msg.wininfo[j].width = save_base->msgWinInfo[i].width;
|
|
nact->msg.wininfo[j].height = save_base->msgWinInfo[i].height;
|
|
// nact->msg.wininfo[i].savedImage = NULL;
|
|
// nact->msg.wininfo[i].save = false;
|
|
}
|
|
/* スタックのロード */
|
|
loadStack(format, saveTop + save_base->stackinfo);
|
|
/* 文字列変数のロード */
|
|
loadStrVars(format, saveTop + save_base->varStr);
|
|
/* 数値・配列変数のロード */
|
|
for (int i = 0; i < 256; i++) {
|
|
if (save_base->varSys[i] != 0) {
|
|
if (SAVE_LOADOK != loadVarPage(saveTop + save_base->varSys[i]))
|
|
goto errexit;
|
|
|
|
}
|
|
}
|
|
free(saveTop);
|
|
return SAVE_LOADOK;
|
|
errexit:
|
|
free(saveTop);
|
|
return SAVE_LOADERR;
|
|
}
|
|
|
|
/* データのセーブ */
|
|
int save_saveAll(int no) {
|
|
enum save_format format = save_format;
|
|
asd_baseHdr save_base = {};
|
|
int totalsize = sizeof(asd_baseHdr);
|
|
|
|
if (no >= SAVE_MAXNUMBER)
|
|
return SAVE_SAVEERR;
|
|
|
|
fc_backup_oldfile(nact->files.save_fname[no]);
|
|
FILE *fp = fopen(nact->files.save_fname[no], "wb");
|
|
if (!fp)
|
|
return SAVE_SAVEERR;
|
|
|
|
/* 各種データのセーブ */
|
|
strncpy(save_base.ID, save_signature[format], 32);
|
|
save_base.version = SAVE_DATAVERSION;
|
|
save_base.selMsgSize = (uint8_t)nact->sel.MsgFontSize;
|
|
save_base.selMsgColor = (uint8_t)nact->sel.MsgFontColor;
|
|
save_base.selBackColor = (uint8_t)nact->sel.WinBackgroundColor;
|
|
save_base.selFrameColor = (uint8_t)nact->sel.WinFrameColor;
|
|
save_base.msgMsgSize = (uint8_t)nact->msg.MsgFontSize;
|
|
save_base.msgMsgColor = (uint8_t)nact->msg.MsgFontColor;
|
|
save_base.msgBackColor = (uint8_t)nact->msg.WinBackgroundColor;
|
|
save_base.msgFrameColor = (uint8_t)nact->msg.WinFrameColor;
|
|
save_base.scoPage = sl_getPage() + (format == SAVEFMT_XSYS35 ? 0 : 1);
|
|
save_base.scoIndex = sl_getIndex();
|
|
|
|
for (int i = 0; i < SELWINMAX; i++) {
|
|
int j = format == SAVEFMT_XSYS35
|
|
? (i + 1) % SELWINMAX // For savedata compatibility
|
|
: i;
|
|
save_base.selWinInfo[i].x = (uint16_t)nact->sel.wininfo[j].x;
|
|
save_base.selWinInfo[i].y = (uint16_t)nact->sel.wininfo[j].y;
|
|
save_base.selWinInfo[i].width = (uint16_t)nact->sel.wininfo[j].width;
|
|
save_base.selWinInfo[i].height = (uint16_t)nact->sel.wininfo[j].height;
|
|
}
|
|
|
|
for (int i = 0; i < MSGWINMAX; i++) {
|
|
int j = format == SAVEFMT_XSYS35
|
|
? (i + 1) % MSGWINMAX // For savedata compatibility
|
|
: i;
|
|
save_base.msgWinInfo[i].x = (uint16_t)nact->msg.wininfo[j].x;
|
|
save_base.msgWinInfo[i].y = (uint16_t)nact->msg.wininfo[j].y;
|
|
save_base.msgWinInfo[i].width = (uint16_t)nact->msg.wininfo[j].width;
|
|
save_base.msgWinInfo[i].height = (uint16_t)nact->msg.wininfo[j].height;
|
|
}
|
|
|
|
fseek(fp, sizeof(asd_baseHdr), SEEK_SET);
|
|
|
|
/* スタック情報 */
|
|
save_base.stackinfo = totalsize;
|
|
totalsize += saveStack(format, fp);
|
|
if (ferror(fp))
|
|
goto errexit;
|
|
|
|
/* 文字列変数 */
|
|
save_base.varStr = totalsize;
|
|
totalsize += saveStrVars(format, fp);
|
|
if (ferror(fp))
|
|
goto errexit;
|
|
|
|
/* 数値変数・配列変数 */
|
|
for (int i = 0; i < 256; i++) {
|
|
int size = saveVarPage(i, fp);
|
|
if (size) {
|
|
save_base.varSys[i] = totalsize;
|
|
totalsize += size;
|
|
} else {
|
|
save_base.varSys[i] = 0;
|
|
}
|
|
if (ferror(fp))
|
|
goto errexit;
|
|
}
|
|
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
if (1 != fwrite(&save_base, sizeof(asd_baseHdr), 1, fp))
|
|
goto errexit;
|
|
|
|
fseek(fp, 0L, SEEK_END);
|
|
writeAsdFooter(format, fp);
|
|
|
|
fclose(fp);
|
|
scheduleSync();
|
|
|
|
return SAVE_SAVEOK1;
|
|
|
|
errexit:
|
|
fclose(fp);
|
|
return SAVE_SAVEERR;
|
|
}
|