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