1 #include "../ui-base.hpp"
2 State state;
3 
save(unsigned slot)4 bool State::save(unsigned slot) {
5   if(!allowed()) return false;
6 
7   SNES::system.runtosave();
8   serializer state = SNES::system.serialize();
9 
10   file fp;
11   bool result = false;
12   if(fp.open(name(slot), file::mode_write)) {
13     fp.write(state.data(), state.size());
14     fp.close();
15     result = true;
16   }
17 
18   if(result) {
19     utility.showMessage(string() << "State " << (slot + 1) << " saved.");
20   } else {
21     utility.showMessage(string() << "Failed to save state " << (slot + 1) << ".");
22   }
23   return result;
24 }
25 
load(unsigned slot)26 bool State::load(unsigned slot) {
27   if(!allowed()) return false;
28 
29   file fp;
30   bool result = false;
31   if(fp.open(name(slot), file::mode_read)) {
32     unsigned size = fp.size();
33     uint8_t *data = new uint8_t[size];
34     fp.read(data, size);
35     fp.close();
36     serializer state(data, size);
37     delete[] data;
38     result = SNES::system.unserialize(state);
39   }
40 
41   if(result) {
42     utility.showMessage(string() << "State " << (slot + 1) << " loaded.");
43     resetHistory();
44   } else {
45     utility.showMessage(string() << "Failed to load state " << (slot + 1) << ".");
46   }
47   return result;
48 }
49 
frame()50 void State::frame() {
51   if(!allowed()) return;
52   if(!config().system.rewindEnabled) return;
53 
54   //if a full second has passed, automatically capture state
55   if(++frameCounter >= (SNES::system.region() == SNES::System::NTSC ? 60 : 50)) {
56     frameCounter = 0;
57     historyIndex = (historyIndex + 1) % historySize;
58     historyCount = min(historyCount + 1, historySize);
59     SNES::system.runtosave();
60     history[historyIndex] = SNES::system.serialize();
61   }
62 }
63 
resetHistory()64 void State::resetHistory() {
65   historyIndex = 0;
66   historyCount = 0;
67   frameCounter = 0;
68 }
69 
rewind()70 bool State::rewind() {
71   if(!allowed()) return false;
72   if(!config().system.rewindEnabled) return false;
73 
74   if(historyCount == 0) return false;
75   serializer state(history[historyIndex].data(), history[historyIndex].size());
76   bool result = SNES::system.unserialize(state);
77   historyIndex = (historyIndex + historySize - 1) % historySize;  //add historySize to prevent underflow
78   historyCount--;
79   return true;
80 }
81 
State()82 State::State() {
83   historySize = 120;
84   history = new serializer[historySize];
85   for(unsigned i = 0; i < historySize; i++) history[i] = 0;
86 }
87 
~State()88 State::~State() {
89   delete[] history;
90 }
91 
92 //
93 
allowed() const94 bool State::allowed() const {
95   if(!SNES::cartridge.loaded() || !application.power) return false;
96   if(movie.state != Movie::Inactive) return false;
97   return cartridge.saveStatesSupported();
98 }
99 
name(unsigned slot) const100 string State::name(unsigned slot) const {
101   string name = filepath(nall::basename(cartridge.fileName), config().path.state);
102   name << "-" << (slot + 1) << ".bst";
103   return name;
104 }
105