1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/alan2/alan2.h"
24 #include "glk/alan2/exe.h"
25 #include "glk/alan2/main.h"
26 #include "glk/alan2/glkio.h"
27 #include "common/system.h"
28 #include "common/config-manager.h"
29 #include "common/translation.h"
30 #include "common/error.h"
31 #include "common/scummsys.h"
32 #include "common/serializer.h"
33 #include "glk/glk.h"
34 #include "glk/streams.h"
35
36 namespace Glk {
37 namespace Alan2 {
38
39 Alan2 *g_vm = nullptr;
40
Alan2(OSystem * syst,const GlkGameDescription & gameDesc)41 Alan2::Alan2(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
42 vm_exited_cleanly(false), _restartFlag(false), _saveSlot(-1), _pendingLook(false) {
43 g_vm = this;
44 txtfil = nullptr;
45 logfil = nullptr;
46 memory = nullptr;
47 }
48
runGame()49 void Alan2::runGame() {
50 if (initialize())
51 Glk::Alan2::run();
52
53 deinitialize();
54 }
55
initialize()56 bool Alan2::initialize() {
57 // Set up adventure name
58 _advName = getFilename();
59 if (_advName.size() > 4 && _advName[_advName.size() - 4] == '.')
60 _advName = Common::String(_advName.c_str(), _advName.size() - 4);
61
62 // first, open a window for error output
63 glkMainWin = g_vm->glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
64 if (glkMainWin == nullptr)
65 ::error("FATAL ERROR: Cannot open initial window");
66
67 g_vm->glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1);
68 glkStatusWin = g_vm->glk_window_open(glkMainWin, winmethod_Above |
69 winmethod_Fixed, 1, wintype_TextGrid, 0);
70 g_vm->glk_set_window(glkMainWin);
71
72 // Set up the code file to point to the already opened game file
73 codfil = &_gameFile;
74
75 if (_gameFile.size() < 8) {
76 GUIErrorMessage(_("This is too short to be a valid Alan2 file."));
77 return false;
78 }
79
80 if (_gameFile.readUint32BE() != MKTAG(2, 8, 1, 0)) {
81 GUIErrorMessage(_("This is not a valid Alan2 file."));
82 return false;
83 }
84
85 // Open up the text file
86 txtfil = new Common::File();
87 if (!txtfil->open(Common::String::format("%s.dat", _advName.c_str()))) {
88 GUIErrorMessage("Could not open adventure text data file");
89 delete txtfil;
90 return false;
91 }
92
93 // Check for a save being loaded directly from the launcher
94 _saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
95
96 return true;
97 }
98
deinitialize()99 void Alan2::deinitialize() {
100 free(memory);
101
102 delete txtfil;
103 delete logfil;
104 }
105
readSaveData(Common::SeekableReadStream * rs)106 Common::Error Alan2::readSaveData(Common::SeekableReadStream *rs) {
107 Common::Serializer s(rs, nullptr);
108 synchronizeSave(s);
109
110 return Common::kNoError;
111 }
112
writeGameData(Common::WriteStream * ws)113 Common::Error Alan2::writeGameData(Common::WriteStream *ws) {
114 Common::Serializer s(nullptr, ws);
115 synchronizeSave(s);
116
117 ws->flush();
118 return Common::kNoError;
119 }
120
121 // This works around gcc errors for passing packed structure fields
syncVal(Common::Serializer & s,uint32 * fld)122 void syncVal(Common::Serializer &s, uint32 *fld) {
123 uint32 &v = *fld;
124 s.syncAsUint32LE(v);
125 }
126
syncActors(Common::Serializer & s)127 static void syncActors(Common::Serializer &s) {
128 for (uint i = ACTMIN; i <= ACTMAX; ++i) {
129 syncVal(s, &acts[i - ACTMIN].loc);
130 syncVal(s, &acts[i - ACTMIN].script);
131 syncVal(s, &acts[i - ACTMIN].step);
132 syncVal(s, &acts[i - ACTMIN].count);
133
134 if (acts[i - ACTMIN].atrs) {
135 for (AtrElem *atr = (AtrElem *)addrTo(acts[i - ACTMIN].atrs); !endOfTable(atr); ++atr)
136 syncVal(s, &atr->val);
137 }
138 }
139 }
140
syncLocations(Common::Serializer & s)141 static void syncLocations(Common::Serializer &s) {
142 for (uint i = LOCMIN; i <= LOCMAX; ++i) {
143 syncVal(s, &locs[i - LOCMIN].describe);
144 if (locs[i - LOCMIN].atrs)
145 for (AtrElem *atr = (AtrElem *)addrTo(locs[i - LOCMIN].atrs); !endOfTable(atr); atr++)
146 syncVal(s, &atr->val);
147 }
148 }
149
syncObjects(Common::Serializer & s)150 static void syncObjects(Common::Serializer &s) {
151 for (uint i = OBJMIN; i <= OBJMAX; ++i) {
152 syncVal(s, &objs[i - OBJMIN].loc);
153 if (objs[i - OBJMIN].atrs)
154 for (AtrElem *atr = (AtrElem *)addrTo(objs[i - OBJMIN].atrs); !endOfTable(atr); atr++)
155 syncVal(s, &atr->val);
156 }
157 }
158
syncEventQueue(Common::Serializer & s)159 static void syncEventQueue(Common::Serializer &s) {
160 int i;
161 EvtqElem *arr = eventq;
162
163 if (s.isLoading()) {
164 i = 0;
165 do {
166 arr[i].synchronize(s);
167 i++;
168 } while (arr[i - 1].time != 0);
169 etop = i - 1;
170 } else {
171 // Mark the top
172 arr[etop].time = 0;
173
174 for (i = 0; i <= etop; ++i)
175 arr[i].synchronize(s);
176 }
177 }
178
syncScores(Common::Serializer & s)179 static void syncScores(Common::Serializer &s) {
180 for (int i = 0; scores[i] != EOD; i++)
181 syncVal(s, &scores[i]);
182 }
183
synchronizeSave(Common::Serializer & s)184 void Alan2::synchronizeSave(Common::Serializer &s) {
185 // Sync various savegame data
186 cur.synchronize(s);
187 syncActors(s);
188 syncLocations(s);
189 syncObjects(s);
190 syncEventQueue(s);
191 syncScores(s);
192 }
193
194 } // End of namespace Alan2
195 } // End of namespace Glk
196