Merge state.c

This commit is contained in:
twinaphex
2015-08-06 13:09:39 +02:00
parent f40df99fe1
commit 8938dde948
3 changed files with 221 additions and 644 deletions

View File

@@ -1,365 +0,0 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
#include "fceu-types.h"
#include "x6502.h"
#include "fceu.h"
#include "sound.h"
#include "fceu-endian.h"
#include "fds.h"
#include "general.h"
#include "state.h"
#include "movie.h"
#include "fceu-memory.h"
#include "ppu.h"
#include "netplay.h"
#include "video.h"
static void (*SPreSave)(void);
static void (*SPostSave)(void);
static int SaveStateStatus[10];
static SFORMAT SFMDATA[64];
static int SFEXINDEX;
#define RLSB FCEUSTATE_RLSB //0x80000000
extern SFORMAT FCEUPPU_STATEINFO[];
extern SFORMAT FCEUSND_STATEINFO[];
extern SFORMAT FCEUCTRL_STATEINFO[];
SFORMAT SFCPU[] = {
{ &X.PC, 2 | RLSB, "PC\0" },
{ &X.A, 1, "A\0\0" },
{ &X.X, 1, "X\0\0" },
{ &X.Y, 1, "Y\0\0" },
{ &X.S, 1, "S\0\0" },
{ &X.P, 1, "P\0\0" },
{ &X.DB, 1, "DB"},
#ifdef COPYFAMI
{ RAM, 0x4000, "RAM" },
#else
{ RAM, 0x800, "RAM" },
#endif
{ 0 }
};
SFORMAT SFCPUC[] = {
{ &X.jammed, 1, "JAMM" },
{ &X.IRQlow, 4 | RLSB, "IQLB" },
{ &X.tcount, 4 | RLSB, "ICoa" },
{ &X.count, 4 | RLSB, "ICou" },
{ &timestampbase, sizeof(timestampbase) | RLSB, "TSBS" },
{ 0 }
};
static int SubWrite(memstream_t *mem, SFORMAT *sf)
{
uint32 acc=0;
while(sf->v)
{
if(sf->s==~0) /* Link to another struct. */
{
uint32 tmp;
if(!(tmp=SubWrite(mem, (SFORMAT *)sf->v)))
return(0);
acc+=tmp;
sf++;
continue;
}
acc+=8; /* Description + size */
acc+=sf->s&(~RLSB);
if(mem) /* Are we writing or calculating the size of this block? */
{
memstream_write(mem, sf->desc, 4);
write32le_mem(sf->s&(~RLSB), mem);
#ifdef MSB_FIRST
if(sf->s&RLSB)
FlipByteOrder(sf->v,sf->s&(~RLSB));
#endif
memstream_write(mem, (uint8 *)sf->v, sf->s&(~RLSB));
/* Now restore the original byte order. */
#ifdef MSB_FIRST
if(sf->s&RLSB)
FlipByteOrder(sf->v,sf->s&(~RLSB));
#endif
}
sf++;
}
return acc;
}
static int WriteStateChunk(memstream_t *mem, int type, SFORMAT *sf)
{
int bsize;
memstream_putc(mem, type);
bsize = SubWrite(0,sf);
write32le_mem(bsize, mem);
if (!SubWrite(mem, sf))
return 0;
return bsize + 5;
}
static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc)
{
while (sf->v)
{
if (sf->s == ~0)
{ /* Link to another SFORMAT structure. */
SFORMAT *tmp;
if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc)))
return(tmp);
sf++;
continue;
}
if (!strncmp(desc, sf->desc, 4))
{
if (tsize != (sf->s & (~RLSB)))
return(0);
return(sf);
}
sf++;
}
return(0);
}
static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size)
{
SFORMAT *tmp;
int temp;
temp=memstream_pos(mem);
while(memstream_pos(mem)<temp+size)
{
uint32 tsize;
char toa[4];
if(memstream_read(mem, toa, 4)<=0)
return 0;
read32le_mem(&tsize,mem);
if((tmp=CheckS(sf,tsize,toa)))
{
memstream_read(mem, (uint8 *)tmp->v, tmp->s&(~RLSB));
#ifdef MSB_FIRST
if(tmp->s&RLSB)
FlipByteOrder(tmp->v,tmp->s&(~RLSB));
#endif
}
else
memstream_seek(mem,tsize,SEEK_CUR);
}
return 1;
}
static int ReadStateChunks(memstream_t *st, int32 totalsize)
{
int t;
uint32 size;
int ret = 1;
while (totalsize > 0)
{
t = memstream_getc(st);
if (t == EOF)
break;
if (!read32le_mem(&size,st))
break;
totalsize -= size + 5;
switch(t)
{
case 1:
if (!ReadStateChunk(st, SFCPU, size))
ret = 0;
break;
case 2:
if (!ReadStateChunk(st, SFCPUC, size))
ret = 0;
else
X.mooPI = X.P; // Quick and dirty hack.
break;
case 3:
if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size))
ret = 0;
break;
case 4:
if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size))
ret = 0;
break;
case 5:
if (!ReadStateChunk(st, FCEUSND_STATEINFO, size))
ret = 0;
break;
case 0x10:
if (!ReadStateChunk(st, SFMDATA, size))
ret = 0;
break;
default:
if (memstream_seek(st, size, SEEK_CUR) < 0)
goto endo;
break;
}
}
endo:
return ret;
}
int CurrentState = 0;
extern int geniestage;
void FCEUSS_Save_Mem(void)
{
memstream_t *mem = memstream_open(1);
uint32 totalsize;
uint8 header[16] = {0};
header[0] = 'F';
header[1] = 'C';
header[2] = 'S';
header[3] = 0xFF;
FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC);
memstream_write(mem, header, 16);
FCEUPPU_SaveState();
totalsize = WriteStateChunk(mem, 1, SFCPU);
totalsize += WriteStateChunk(mem, 2, SFCPUC);
totalsize += WriteStateChunk(mem, 3, FCEUPPU_STATEINFO);
totalsize += WriteStateChunk(mem, 4, FCEUCTRL_STATEINFO);
totalsize += WriteStateChunk(mem, 5, FCEUSND_STATEINFO);
if (SPreSave)
SPreSave();
totalsize += WriteStateChunk(mem, 0x10, SFMDATA);
if (SPreSave)
SPostSave();
memstream_seek(mem, 4, SEEK_SET);
write32le_mem(totalsize, mem);
memstream_close(mem);
}
void FCEUSS_Load_Mem(void)
{
memstream_t *mem = memstream_open(0);
uint8 header[16];
int stateversion;
int x;
memstream_read(mem, header, 16);
if (memcmp(header,"FCS",3) != 0)
return;
if (header[3] == 0xFF)
stateversion = FCEU_de32lsb(header + 8);
else
stateversion = header[3] * 100;
x = ReadStateChunks(mem, *(uint32*)(header + 4));
if (stateversion < 9500)
X.IRQlow=0;
if (GameStateRestore)
GameStateRestore(stateversion);
if (x)
{
FCEUPPU_LoadState(stateversion);
FCEUSND_LoadState(stateversion);
}
memstream_close(mem);
}
void FCEUSS_CheckStates(void)
{
MEM_TYPE *st = NULL;
char *fn;
int ssel;
for (ssel = 0; ssel < 10; ssel++)
{
st = fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb");
free(fn);
if (st)
{
SaveStateStatus[ssel] = 1;
fclose(st);
}
else
SaveStateStatus[ssel] = 0;
}
CurrentState = 0;
}
void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
{
SPreSave = PreSave;
SPostSave = PostSave;
SFEXINDEX = 0;
}
void AddExState(void *v, uint32 s, int type, char *desc)
{
memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc));
if (desc)
strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc));
SFMDATA[SFEXINDEX].v = v;
SFMDATA[SFEXINDEX].s = s;
if (type) SFMDATA[SFEXINDEX].s |= RLSB;
if (SFEXINDEX < 63) SFEXINDEX++;
SFMDATA[SFEXINDEX].v = 0; // End marker.
}
void FCEU_DrawSaveStates(uint8 *XBuf)
{
}

View File

@@ -25,7 +25,7 @@
#include "palette.c"
#include "ppu.c"
#include "sound.c"
#include "drivers/libretro/fceu/state.c"
#include "state.c"
#include "video.c"
#include "vsuni.c"
//#include "wave.c"

View File

@@ -18,9 +18,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* TODO: Add (better) file io error checking */
/* TODO: Change save state file format. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -48,15 +45,12 @@ static void (*SPreSave)(void);
static void (*SPostSave)(void);
static int SaveStateStatus[10];
static int StateShow;
static SFORMAT SFMDATA[64];
static int SFEXINDEX;
#define RLSB FCEUSTATE_RLSB //0x80000000
extern SFORMAT FCEUPPU_STATEINFO[];
extern SFORMAT FCEUSND_STATEINFO[];
extern SFORMAT FCEUCTRL_STATEINFO[];
@@ -87,281 +81,274 @@ SFORMAT SFCPUC[] = {
{ 0 }
};
static int SubWrite(MEM_TYPE *st, SFORMAT *sf) {
uint32 acc = 0;
static int SubWrite(memstream_t *mem, SFORMAT *sf)
{
uint32 acc=0;
while (sf->v) {
if (sf->s == ~0) { // Link to another struct.
uint32 tmp;
while(sf->v)
{
if(sf->s==~0) /* Link to another struct. */
{
uint32 tmp;
if (!(tmp = SubWrite(st, (SFORMAT*)sf->v)))
return(0);
acc += tmp;
sf++;
continue;
}
if(!(tmp=SubWrite(mem, (SFORMAT *)sf->v)))
return(0);
acc+=tmp;
sf++;
continue;
}
acc += 8; // Description + size
acc += sf->s & (~RLSB);
acc+=8; /* Description + size */
acc+=sf->s&(~RLSB);
if (st) { // Are we writing or calculating the size of this block? */
fwrite(sf->desc, 1, 4, st);
write32le(sf->s & (~RLSB), st);
if(mem) /* Are we writing or calculating the size of this block? */
{
memstream_write(mem, sf->desc, 4);
write32le_mem(sf->s&(~RLSB), mem);
#ifdef MSB_FIRST
if (sf->s & RLSB)
FlipByteOrder(sf->v, sf->s & (~RLSB));
#endif
#ifdef MSB_FIRST
if(sf->s&RLSB)
FlipByteOrder(sf->v,sf->s&(~RLSB));
#endif
fwrite((uint8*)sf->v, 1, sf->s & (~RLSB), st);
/* Now restore the original byte order. */
#ifdef MSB_FIRST
if (sf->s & RLSB)
FlipByteOrder(sf->v, sf->s & (~RLSB));
#endif
}
sf++;
}
memstream_write(mem, (uint8 *)sf->v, sf->s&(~RLSB));
/* Now restore the original byte order. */
#ifdef MSB_FIRST
if(sf->s&RLSB)
FlipByteOrder(sf->v,sf->s&(~RLSB));
#endif
}
sf++;
}
return(acc);
return acc;
}
static int WriteStateChunk(MEM_TYPE *st, int type, SFORMAT *sf) {
int bsize;
static int WriteStateChunk(memstream_t *mem, int type, SFORMAT *sf)
{
int bsize;
fputc(type, st);
memstream_putc(mem, type);
bsize = SubWrite(0, sf);
write32le(bsize, st);
bsize = SubWrite(0,sf);
write32le_mem(bsize, mem);
if (!SubWrite(st, sf)) return(0);
return(bsize + 5);
if (!SubWrite(mem, sf))
return 0;
return bsize + 5;
}
static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc) {
while (sf->v) {
if (sf->s == ~0) { /* Link to another SFORMAT structure. */
SFORMAT *tmp;
if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc)))
return(tmp);
sf++;
continue;
}
if (!strncmp(desc, sf->desc, 4)) {
if (tsize != (sf->s & (~RLSB)))
return(0);
return(sf);
}
sf++;
}
return(0);
static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc)
{
while (sf->v)
{
if (sf->s == ~0)
{ /* Link to another SFORMAT structure. */
SFORMAT *tmp;
if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc)))
return(tmp);
sf++;
continue;
}
if (!strncmp(desc, sf->desc, 4))
{
if (tsize != (sf->s & (~RLSB)))
return(0);
return(sf);
}
sf++;
}
return(0);
}
static int ReadStateChunk(MEM_TYPE *st, SFORMAT *sf, int size) {
SFORMAT *tmp;
int temp;
temp = ftell(st);
static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size)
{
SFORMAT *tmp;
int temp;
temp=memstream_pos(mem);
while (ftell(st) < temp + size) {
uint32 tsize;
char toa[4];
if (fread(toa, 1, 4, st) <= 0)
return 0;
while(memstream_pos(mem)<temp+size)
{
uint32 tsize;
char toa[4];
if(memstream_read(mem, toa, 4)<=0)
return 0;
read32le(&tsize, st);
read32le_mem(&tsize,mem);
if ((tmp = CheckS(sf, tsize, toa))) {
fread((uint8*)tmp->v, 1, tmp->s & (~RLSB), st);
if((tmp=CheckS(sf,tsize,toa)))
{
memstream_read(mem, (uint8 *)tmp->v, tmp->s&(~RLSB));
#ifdef MSB_FIRST
if (tmp->s & RLSB)
FlipByteOrder(tmp->v, tmp->s & (~RLSB));
#endif
} else
fseek(st, tsize, SEEK_CUR);
} // while(...)
return 1;
#ifdef MSB_FIRST
if(tmp->s&RLSB)
FlipByteOrder(tmp->v,tmp->s&(~RLSB));
#endif
}
else
memstream_seek(mem,tsize,SEEK_CUR);
}
return 1;
}
static int ReadStateChunks(MEM_TYPE *st, int32 totalsize) {
int t;
uint32 size;
int ret = 1;
static int ReadStateChunks(memstream_t *st, int32 totalsize)
{
int t;
uint32 size;
int ret = 1;
while (totalsize > 0) {
t = fgetc(st);
if (t == EOF) break;
if (!read32le(&size, st)) break;
totalsize -= size + 5;
while (totalsize > 0)
{
t = memstream_getc(st);
if (t == EOF)
break;
if (!read32le_mem(&size,st))
break;
totalsize -= size + 5;
switch (t) {
case 1: if (!ReadStateChunk(st, SFCPU, size)) ret = 0; break;
case 2:
if (!ReadStateChunk(st, SFCPUC, size))
ret = 0;
else {
X.mooPI = X.P; // Quick and dirty hack.
}
break;
case 3: if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size)) ret = 0; break;
case 4: if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size)) ret = 0; break;
case 5: if (!ReadStateChunk(st, FCEUSND_STATEINFO, size)) ret = 0; break;
case 0x10: if (!ReadStateChunk(st, SFMDATA, size)) ret = 0;
break;
default: if (fseek(st, size, SEEK_CUR) < 0) goto endo; break;
}
}
endo:
return ret;
switch(t)
{
case 1:
if (!ReadStateChunk(st, SFCPU, size))
ret = 0;
break;
case 2:
if (!ReadStateChunk(st, SFCPUC, size))
ret = 0;
else
X.mooPI = X.P; // Quick and dirty hack.
break;
case 3:
if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size))
ret = 0;
break;
case 4:
if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size))
ret = 0;
break;
case 5:
if (!ReadStateChunk(st, FCEUSND_STATEINFO, size))
ret = 0;
break;
case 0x10:
if (!ReadStateChunk(st, SFMDATA, size))
ret = 0;
break;
default:
if (memstream_seek(st, size, SEEK_CUR) < 0)
goto endo;
break;
}
}
endo:
return ret;
}
int CurrentState = 0;
extern int geniestage;
int FCEUSS_SaveFP(MEM_TYPE *st) {
static uint32 totalsize;
uint8 header[16] = { 0 };
void FCEUSS_Save_Mem(void)
{
memstream_t *mem = memstream_open(1);
header[0] = 'F';
header[1] = 'C';
header[2] = 'S';
header[3] = 0xFF;
uint32 totalsize;
uint8 header[16] = {0};
header[0] = 'F';
header[1] = 'C';
header[2] = 'S';
header[3] = 0xFF;
header[3] = 0xFF;
FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC);
fwrite(header, 1, 16, st);
FCEUPPU_SaveState();
FCEUSND_SaveState();
totalsize = WriteStateChunk(st, 1, SFCPU);
totalsize += WriteStateChunk(st, 2, SFCPUC);
totalsize += WriteStateChunk(st, 3, FCEUPPU_STATEINFO);
totalsize += WriteStateChunk(st, 4, FCEUCTRL_STATEINFO);
totalsize += WriteStateChunk(st, 5, FCEUSND_STATEINFO);
if (SPreSave) SPreSave();
totalsize += WriteStateChunk(st, 0x10, SFMDATA);
if (SPreSave) SPostSave();
FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC);
memstream_write(mem, header, 16);
fseek(st, 4, SEEK_SET);
write32le(totalsize, st);
return(1);
FCEUPPU_SaveState();
totalsize = WriteStateChunk(mem, 1, SFCPU);
totalsize += WriteStateChunk(mem, 2, SFCPUC);
totalsize += WriteStateChunk(mem, 3, FCEUPPU_STATEINFO);
totalsize += WriteStateChunk(mem, 4, FCEUCTRL_STATEINFO);
totalsize += WriteStateChunk(mem, 5, FCEUSND_STATEINFO);
if (SPreSave)
SPreSave();
totalsize += WriteStateChunk(mem, 0x10, SFMDATA);
if (SPreSave)
SPostSave();
memstream_seek(mem, 4, SEEK_SET);
write32le_mem(totalsize, mem);
memstream_close(mem);
}
void FCEUSS_Save(char *fname) {
MEM_TYPE *st = NULL;
char *fn;
void FCEUSS_Load_Mem(void)
{
memstream_t *mem = memstream_open(0);
if (geniestage == 1) {
FCEU_DispMessage("Cannot save FCS in GG screen.");
return;
}
uint8 header[16];
int stateversion;
int x;
memstream_read(mem, header, 16);
if (fname)
st = FCEUD_UTF8fopen(fname, "wb");
else {
st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, CurrentState, 0), "wb");
free(fn);
}
if (memcmp(header,"FCS",3) != 0)
return;
if (st == NULL) {
FCEU_DispMessage("State %d save error.", CurrentState);
return;
}
if (header[3] == 0xFF)
stateversion = FCEU_de32lsb(header + 8);
else
stateversion = header[3] * 100;
FCEUSS_SaveFP(st);
x = ReadStateChunks(mem, *(uint32*)(header + 4));
SaveStateStatus[CurrentState] = 1;
fclose(st);
FCEU_DispMessage("State %d saved.", CurrentState);
if (stateversion < 9500)
X.IRQlow=0;
if (GameStateRestore)
GameStateRestore(stateversion);
if (x)
{
FCEUPPU_LoadState(stateversion);
FCEUSND_LoadState(stateversion);
}
memstream_close(mem);
}
int FCEUSS_LoadFP(MEM_TYPE *st) {
int x;
uint8 header[16];
int stateversion;
void FCEUSS_CheckStates(void)
{
MEM_TYPE *st = NULL;
char *fn;
int ssel;
fread(&header, 1, 16, st);
if (memcmp(header, "FCS", 3))
return(0);
for (ssel = 0; ssel < 10; ssel++)
{
st = fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb");
free(fn);
if (st)
{
SaveStateStatus[ssel] = 1;
fclose(st);
}
else
SaveStateStatus[ssel] = 0;
}
if (header[3] == 0xFF)
stateversion = FCEU_de32lsb(header + 8);
else
stateversion = header[3] * 100;
x = ReadStateChunks(st, *(uint32*)(header + 4));
if (stateversion < 9500) X.IRQlow = 0;
if (GameStateRestore) GameStateRestore(stateversion);
if (x) {
FCEUPPU_LoadState(stateversion);
FCEUSND_LoadState(stateversion);
}
return(x);
CurrentState = 0;
}
int FCEUSS_Load(char *fname) {
MEM_TYPE *st;
char *fn;
if (geniestage == 1) {
FCEU_DispMessage("Cannot load FCS in GG screen.");
return(0);
}
if (fname)
st = FCEUD_UTF8fopen(fname, "rb");
else {
st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, CurrentState, fname), "rb");
free(fn);
}
if (st == NULL) {
FCEU_DispMessage("State %d load error.", CurrentState);
SaveStateStatus[CurrentState] = 0;
return(0);
}
if (FCEUSS_LoadFP(st)) {
SaveStateStatus[CurrentState] = 1;
FCEU_DispMessage("State %d loaded.", CurrentState);
SaveStateStatus[CurrentState] = 1;
fclose(st);
return(1);
} else {
SaveStateStatus[CurrentState] = 1;
FCEU_DispMessage("Error(s) reading state %d!", CurrentState);
fclose(st);
return(0);
}
}
void FCEUSS_CheckStates(void) {
MEM_TYPE *st = NULL;
char *fn;
int ssel;
for (ssel = 0; ssel < 10; ssel++) {
st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb");
free(fn);
if (st) {
SaveStateStatus[ssel] = 1;
fclose(st);
} else
SaveStateStatus[ssel] = 0;
}
CurrentState = 0;
StateShow = 0;
}
void ResetExState(void (*PreSave)(void), void (*PostSave)(void)) {
void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
{
SPreSave = PreSave;
SPostSave = PostSave;
SFEXINDEX = 0;
}
void AddExState(void *v, uint32 s, int type, char *desc) {
void AddExState(void *v, uint32 s, int type, char *desc)
{
memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc));
if (desc)
strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc));
@@ -372,52 +359,7 @@ void AddExState(void *v, uint32 s, int type, char *desc) {
SFMDATA[SFEXINDEX].v = 0; // End marker.
}
void FCEUI_SelectState(int w) {
if (w == -1) {
StateShow = 0; return;
}
FCEUI_SelectMovie(-1);
CurrentState = w;
StateShow = 180;
FCEU_DispMessage("-select state-");
}
void FCEUI_SaveState(char *fname) {
StateShow = 0;
FCEUSS_Save(fname);
}
void FCEUI_LoadState(char *fname) {
StateShow = 0;
FCEUMOV_Stop();
/* For network play, be load the state locally, and then save the state to a temporary file,
and send that. This insures that if an older state is loaded that is missing some
information expected in newer save states, desynchronization won't occur(at least not
from this ;)).
*/
if (FCEUSS_Load(fname))
if (FCEUnetplay) {
char *fn = FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0);
MEM_TYPE *fp;
if ((fp = fopen(fn, "wb"))) {
if (FCEUSS_SaveFP(fp)) {
fclose(fp);
FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn);
} else fclose(fp);
unlink(fn);
}
free(fn);
}
}
void FCEU_DrawSaveStates(uint8 *XBuf) {
if (!StateShow) return;
FCEU_DrawNumberRow(XBuf, SaveStateStatus, CurrentState);
StateShow--;
void FCEU_DrawSaveStates(uint8 *XBuf)
{
}