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 "access/resources.h"
24 #include "access/martian/martian_game.h"
25 #include "access/martian/martian_resources.h"
26 #include "access/martian/martian_room.h"
27 #include "access/martian/martian_scripts.h"
28 #include "access/amazon/amazon_resources.h"
29 
30 namespace Access {
31 
32 namespace Martian {
33 
MartianEngine(OSystem * syst,const AccessGameDescription * gameDesc)34 MartianEngine::MartianEngine(OSystem *syst, const AccessGameDescription *gameDesc) : AccessEngine(syst, gameDesc) {
35 }
36 
~MartianEngine()37 MartianEngine::~MartianEngine() {
38 	_introObjects = _spec7Objects = nullptr;
39 	_skipStart = false;
40 	_creditsStream = nullptr;
41 }
42 
initObjects()43 void MartianEngine::initObjects() {
44 	_room = new MartianRoom(this);
45 	_scripts = new MartianScripts(this);
46 }
47 
configSelect()48 void MartianEngine::configSelect() {
49 	// No implementation required in MM
50 }
51 
initVariables()52 void MartianEngine::initVariables() {
53 	warning("TODO: initVariables");
54 
55 	// Set player room and position
56 	_player->_roomNumber = 7;
57 
58 	_inventory->_startInvItem = 0;
59 	_inventory->_startInvBox = 0;
60 	Common::fill(&_objectsTable[0], &_objectsTable[100], (SpriteResource *)nullptr);
61 	_player->_playerOff = false;
62 
63 	// Setup timers
64 	const int TIMER_DEFAULTS[] = { 4, 10, 8, 1, 1, 1, 1, 2 };
65 	for (int i = 0; i < 32; ++i) {
66 		TimerEntry te;
67 		te._initTm = te._timer = (i < 8) ? TIMER_DEFAULTS[i] : 1;
68 		te._flag = 1;
69 
70 		_timers.push_back(te);
71 	}
72 
73 	_player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
74 	_player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
75 	_room->_selectCommand = -1;
76 	_events->setNormalCursor(CURSOR_CROSSHAIRS);
77 	_mouseMode = 0;
78 	_numAnimTimers = 0;
79 
80 	for (int i = 0; i < 60; i++)
81 		_travel[i] = 0;
82 	_travel[7] = 1;
83 
84 	for (int i = 0; i < 40; i++)
85 		_ask[i] = 0;
86 	_ask[33] = 1;
87 }
88 
setNoteParams()89 void MartianEngine::setNoteParams() {
90 	_events->hideCursor();
91 
92 	_screen->_orgX1 = 58;
93 	_screen->_orgY1 = 124;
94 	_screen->_orgX2 = 297;
95 	_screen->_orgY2 = 199;
96 	_screen->_lColor = 51;
97 	_screen->drawRect();
98 
99 	_events->showCursor();
100 }
101 
displayNote(const Common::String & msg)102 void MartianEngine::displayNote(const Common::String &msg) {
103 	_fonts._charSet._lo = 1;
104 	_fonts._charSet._hi = 8;
105 	_fonts._charFor._lo = 0;
106 	_fonts._charFor._hi = 255;
107 
108 	_screen->_maxChars = 40;
109 	_screen->_printOrg = _screen->_printStart = Common::Point(59, 124);
110 
111 	setNoteParams();
112 
113 	Common::String lines = msg;
114 	Common::String line;
115 	int width = 0;
116 	bool lastLine = false;
117 	do {
118 		lastLine = _fonts._font1->getLine(lines, _screen->_maxChars * 6, line, width);
119 		_bubbleBox->printString(line);
120 		_screen->_printOrg = Common::Point(_screen->_printStart.x, _screen->_printOrg.y + 6);
121 
122 		if (_screen->_printOrg.y == 196) {
123 			_events->waitKeyMouse();
124 			setNoteParams();
125 			_screen->_printOrg = _screen->_printStart;
126 		}
127 	} while (!lastLine);
128 	_events->waitKeyMouse();
129 }
130 
doSpecial5(int param1)131 void MartianEngine::doSpecial5(int param1) {
132 	warning("TODO: Push midi song");
133 	_midi->stopSong();
134 	_midi->_byte1F781 = false;
135 	_midi->loadMusic(47, 4);
136 	_midi->midiPlay();
137 	_screen->setDisplayScan();
138 	_events->clearEvents();
139 	_screen->forceFadeOut();
140 	_events->hideCursor();
141 	_files->loadScreen("DATA.SC");
142 	_events->showCursor();
143 	_screen->setIconPalette();
144 	_screen->forceFadeIn();
145 
146 	Resource *cellsRes = _files->loadFile("CELLS00.LZ");
147 	_objectsTable[0] = new SpriteResource(this, cellsRes);
148 	delete cellsRes;
149 
150 	_timers[20]._timer = _timers[20]._initTm = 30;
151 	Resource *notesRes = _files->loadFile("NOTES.DAT");
152 	notesRes->_stream->skip(param1 * 2);
153 	int pos = notesRes->_stream->readUint16LE();
154 	notesRes->_stream->seek(pos);
155 	Common::String msg = "";
156 	byte c;
157 	while ((c = (char)notesRes->_stream->readByte()) != '\0')
158 		msg += c;
159 
160 	displayNote(msg);
161 
162 	_midi->stopSong();
163 	_midi->freeMusic();
164 
165 	warning("TODO: Pop Midi");
166 	// _midi->_byte1F781 = true;
167 }
168 
playGame()169 void MartianEngine::playGame() {
170 	// Initialize Martian Memorandum game-specific objects
171 	initObjects();
172 
173 	// Setup the game
174 	setupGame();
175 	configSelect();
176 
177 	if (_loadSaveSlot == -1) {
178 		// Do introduction
179 		doCredits();
180 		if (shouldQuit())
181 			return;
182 
183 		// Display Notes screen
184 		doSpecial5(4);
185 		if (shouldQuit())
186 			return;
187 		_screen->forceFadeOut();
188 	}
189 
190 	do {
191 		_restartFl = false;
192 		_screen->clearScreen();
193 		_screen->setPanel(0);
194 		_screen->forceFadeOut();
195 		_events->showCursor();
196 
197 		initVariables();
198 
199 		// If there's a pending savegame to load, load it
200 		if (_loadSaveSlot != -1) {
201 			loadGameState(_loadSaveSlot);
202 			_loadSaveSlot = -1;
203 		}
204 
205 		// Execute the room
206 		_room->doRoom();
207 	} while (_restartFl);
208 }
209 
showCredits()210 bool MartianEngine::showCredits() {
211 	_events->hideCursor();
212 	_screen->clearScreen();
213 	_destIn = _screen;
214 
215 	int posX = _creditsStream->readSint16LE();
216 	int posY = 0;
217 
218 	while(posX != -1) {
219 		posY = _creditsStream->readSint16LE();
220 		int frameNum = _creditsStream->readSint16LE();
221 		_screen->plotImage(_introObjects, frameNum, Common::Point(posX, posY));
222 
223 		posX = _creditsStream->readSint16LE();
224 	}
225 
226 	posY = _creditsStream->readSint16LE();
227 	if (posY == -1) {
228 		_events->showCursor();
229 		_screen->forceFadeOut();
230 		return true;
231 	}
232 
233 	_screen->forceFadeIn();
234 	_timers[3]._timer = _timers[3]._initTm = posY;
235 
236 	while (!shouldQuit() && !_events->isKeyMousePressed() && _timers[3]._timer) {
237 		_events->pollEventsAndWait();
238 	}
239 
240 	_events->showCursor();
241 	_screen->forceFadeOut();
242 
243 	if (_events->_rightButton)
244 		return true;
245 	else
246 		return false;
247 }
248 
doCredits()249 void MartianEngine::doCredits() {
250 	_midi->_byte1F781 = false;
251 	_midi->loadMusic(47, 3);
252 	_midi->midiPlay();
253 	_screen->setDisplayScan();
254 	_events->hideCursor();
255 	_screen->forceFadeOut();
256 	Resource *data = _files->loadFile(41, 1);
257 	_introObjects = new SpriteResource(this, data);
258 	delete data;
259 
260 	_files->loadScreen(41, 0);
261 	_buffer2.copyFrom(*_screen);
262 	_buffer1.copyFrom(*_screen);
263 	_events->showCursor();
264 	_creditsStream = new Common::MemoryReadStream(CREDIT_DATA, 180);
265 
266 	if (!showCredits()) {
267 		_screen->copyFrom(_buffer2);
268 		_screen->forceFadeIn();
269 
270 		_events->_vbCount = 550;
271 		while (!shouldQuit() && !_events->isKeyMousePressed() && _events->_vbCount > 0)
272 			_events->pollEventsAndWait();
273 
274 		_screen->forceFadeOut();
275 		while (!shouldQuit() && !_events->isKeyMousePressed()&& !showCredits())
276 			_events->pollEventsAndWait();
277 
278 		warning("TODO: Free word_21E2B");
279 		_midi->freeMusic();
280 	}
281 }
282 
setupGame()283 void MartianEngine::setupGame() {
284 	// Load death list
285 	_deaths.resize(_res->DEATHS.size());
286 	for (uint idx = 0; idx < _deaths.size(); ++idx) {
287 		_deaths[idx]._screenId = _res->DEATHS[idx]._screenId;
288 		_deaths[idx]._msg = _res->DEATHS[idx]._msg;
289 	}
290 
291 	// Setup timers
292 	const int TIMER_DEFAULTS[] = { 4, 10, 8, 1, 1, 1, 1, 2 };
293 	for (int i = 0; i < 32; ++i) {
294 		TimerEntry te;
295 		te._initTm = te._timer = (i < 8) ? TIMER_DEFAULTS[i] : 1;
296 		te._flag = 1;
297 
298 		_timers.push_back(te);
299 	}
300 
301 	// Miscellaneous
302 	Martian::MartianResources &res = *((Martian::MartianResources *)_res);
303 	_fonts.load(res._font6x6, res._font3x5);
304 
305 	// Set player room and position
306 	_player->_roomNumber = 7;
307 	_player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
308 	_player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
309 }
310 
showDeathText(Common::String msg)311 void MartianEngine::showDeathText(Common::String msg) {
312 	Common::String line = "";
313 	int width = 0;
314 	bool lastLine;
315 	do {
316 		lastLine = _fonts._font2->getLine(msg, _screen->_maxChars * 6, line, width);
317 		// Draw the text
318 		_bubbleBox->printString(line);
319 
320 		_screen->_printOrg.y += 6;
321 		_screen->_printOrg.x = _screen->_printStart.x;
322 
323 		if (_screen->_printOrg.y == 180) {
324 			_events->waitKeyMouse();
325 			_screen->copyBuffer(&_buffer2);
326 			_screen->_printOrg.y = _screen->_printStart.y;
327 		}
328 	} while (!lastLine);
329 	_events->waitKeyMouse();
330 }
331 
dead(int deathId)332 void MartianEngine::dead(int deathId) {
333 	// Load and display death screen
334 	_events->hideCursor();
335 	_screen->forceFadeOut();
336 	_files->loadScreen(48, _deaths[deathId]._screenId);
337 	_screen->setIconPalette();
338 	_buffer2.copyBuffer(_screen);
339 	_screen->forceFadeIn();
340 	_events->showCursor();
341 
342 	// Setup fonts
343 	_fonts._charSet._hi = 10;
344 	_fonts._charSet._lo = 1;
345 	_fonts._charFor._lo = 247;
346 	_fonts._charFor._hi = 255;
347 	_screen->_maxChars = 50;
348 	_screen->_printOrg = Common::Point(24, 18);
349 	_screen->_printStart = Common::Point(24, 18);
350 
351 	// Display death message
352 	showDeathText(_deaths[deathId]._msg);
353 
354 	_screen->forceFadeOut();
355 	_room->clearRoom();
356 	freeChar();
357 
358 	// The original was jumping to the restart label in main
359 	_restartFl = true;
360 	_events->pollEvents();
361 }
362 
363 } // End of namespace Martian
364 
365 } // End of namespace Access
366