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
24 #include "common/endian.h"
25 #include "common/config-manager.h"
26 #include "common/events.h"
27 #include "common/system.h"
28 #include "common/savefile.h"
29 #include "common/textconsole.h"
30
31 #include "gui/message.h"
32 #include "sky/compact.h"
33 #include "sky/control.h"
34 #include "sky/disk.h"
35 #include "sky/logic.h"
36 #include "sky/music/musicbase.h"
37 #include "sky/mouse.h"
38 #include "sky/screen.h"
39 #include "sky/sky.h"
40 #include "sky/skydefs.h"
41 #include "sky/sound.h"
42 #include "sky/struc.h"
43 #include "sky/text.h"
44 #include "sky/compact.h"
45
46 #define ANIM_DELAY 20
47 #define CLICK_DELAY 150
48
49 namespace Sky {
50
ConResource(void * pSpData,uint32 pNSprites,uint32 pCurSprite,uint16 pX,uint16 pY,uint32 pText,uint8 pOnClick,OSystem * system,uint8 * screen)51 ConResource::ConResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, uint16 pX, uint16 pY, uint32 pText, uint8 pOnClick, OSystem *system, uint8 *screen) {
52 _spriteData = (DataFileHeader *)pSpData;
53 _numSprites = pNSprites;
54 _curSprite = pCurSprite;
55 _x = pX;
56 _y = pY;
57 _text = pText;
58 _onClick = pOnClick;
59 _system = system;
60 _screen = screen;
61 }
62
isMouseOver(uint32 mouseX,uint32 mouseY)63 bool ConResource::isMouseOver(uint32 mouseX, uint32 mouseY) {
64 if ((mouseX >= _x) && (mouseY >= _y) && ((uint16)mouseX <= _x + _spriteData->s_width) && ((uint16)mouseY <= _y + _spriteData->s_height))
65 return true;
66 else
67 return false;
68 }
69
drawToScreen(bool doMask)70 void ConResource::drawToScreen(bool doMask) {
71 uint8 *screenPos = _y * GAME_SCREEN_WIDTH + _x + _screen;
72 uint8 *updatePos = screenPos;
73
74 if (!_spriteData)
75 return;
76 uint8 *spriteData = ((uint8 *)_spriteData) + sizeof(DataFileHeader);
77 spriteData += _spriteData->s_sp_size * _curSprite;
78 if (doMask) {
79 for (uint16 cnty = 0; cnty < _spriteData->s_height; cnty++) {
80 for (uint16 cntx = 0; cntx < _spriteData->s_width; cntx++) {
81 if (spriteData[cntx]) screenPos[cntx] = spriteData[cntx];
82 }
83 screenPos += GAME_SCREEN_WIDTH;
84 spriteData += _spriteData->s_width;
85 }
86 } else {
87 for (uint16 cnty = 0; cnty < _spriteData->s_height; cnty++) {
88 memcpy(screenPos, spriteData, _spriteData->s_width);
89 screenPos += GAME_SCREEN_WIDTH;
90 spriteData += _spriteData->s_width;
91 }
92 }
93 _system->copyRectToScreen(updatePos, GAME_SCREEN_WIDTH, _x, _y, _spriteData->s_width, _spriteData->s_height);
94 }
95
TextResource(void * pSpData,uint32 pNSprites,uint32 pCurSprite,uint16 pX,uint16 pY,uint32 pText,uint8 pOnClick,OSystem * system,uint8 * screen)96 TextResource::TextResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, uint16 pX, uint16 pY, uint32 pText, uint8 pOnClick, OSystem *system, uint8 *screen) :
97 ConResource(pSpData, pNSprites, pCurSprite, pX, pY, pText, pOnClick, system, screen) {
98 _oldScreen = (uint8 *)malloc(PAN_CHAR_HEIGHT * 3 * PAN_LINE_WIDTH);
99 _oldY = 0;
100 _oldX = GAME_SCREEN_WIDTH;
101 }
102
~TextResource()103 TextResource::~TextResource() {
104 free(_oldScreen);
105 }
106
flushForRedraw()107 void TextResource::flushForRedraw() {
108 if (_oldX < GAME_SCREEN_WIDTH) {
109 uint16 cpWidth = (PAN_LINE_WIDTH > (GAME_SCREEN_WIDTH - _oldX))?(GAME_SCREEN_WIDTH - _oldX):(PAN_LINE_WIDTH);
110 for (uint8 cnty = 0; cnty < PAN_CHAR_HEIGHT; cnty++)
111 memcpy(_screen + (cnty + _oldY) * GAME_SCREEN_WIDTH + _oldX, _oldScreen + cnty * PAN_LINE_WIDTH, cpWidth);
112 }
113 _oldX = GAME_SCREEN_WIDTH;
114 }
115
drawToScreen(bool doMask)116 void TextResource::drawToScreen(bool doMask) {
117 (void)doMask;
118 uint16 cnty, cntx, cpWidth, cpHeight;
119 if ((_oldX == _x) && (_oldY == _y) && (_spriteData))
120 return;
121 if (_oldX < GAME_SCREEN_WIDTH) {
122 cpWidth = (PAN_LINE_WIDTH > (GAME_SCREEN_WIDTH - _oldX))?(GAME_SCREEN_WIDTH - _oldX):(PAN_LINE_WIDTH);
123 if (_spriteData && (cpWidth > _spriteData->s_width))
124 cpWidth = _spriteData->s_width;
125 if (_spriteData)
126 cpHeight = (_spriteData->s_height > (GAME_SCREEN_HEIGHT - _oldY))?(GAME_SCREEN_HEIGHT - _oldY):(_spriteData->s_height);
127 else
128 cpHeight = PAN_CHAR_HEIGHT;
129 for (cnty = 0; cnty < cpHeight; cnty++)
130 memcpy(_screen + (cnty + _oldY) * GAME_SCREEN_WIDTH + _oldX, _oldScreen + cnty * PAN_LINE_WIDTH, cpWidth);
131 _system->copyRectToScreen(_screen + _oldY * GAME_SCREEN_WIDTH + _oldX, GAME_SCREEN_WIDTH, _oldX, _oldY, cpWidth, PAN_CHAR_HEIGHT);
132 }
133 if (!_spriteData) {
134 _oldX = GAME_SCREEN_WIDTH;
135 return;
136 }
137 _oldX = _x;
138 _oldY = _y;
139 cpWidth = (PAN_LINE_WIDTH > (GAME_SCREEN_WIDTH - _x))?(GAME_SCREEN_WIDTH - _x):(PAN_LINE_WIDTH);
140 if (cpWidth > _spriteData->s_width)
141 cpWidth = _spriteData->s_width;
142 cpHeight = (_spriteData->s_height > (GAME_SCREEN_HEIGHT - _y))?(GAME_SCREEN_HEIGHT - _y):(_spriteData->s_height);
143
144 uint8 *screenPos = _screen + _y * GAME_SCREEN_WIDTH + _x;
145 uint8 *copyDest = _oldScreen;
146 uint8 *copySrc = ((uint8 *)_spriteData) + sizeof(DataFileHeader);
147 for (cnty = 0; cnty < cpHeight; cnty++) {
148 memcpy(copyDest, screenPos, cpWidth);
149 for (cntx = 0; cntx < cpWidth; cntx++)
150 if (copySrc[cntx]) screenPos[cntx] = copySrc[cntx];
151 copySrc += _spriteData->s_width;
152 copyDest += PAN_LINE_WIDTH;
153 screenPos += GAME_SCREEN_WIDTH;
154 }
155 _system->copyRectToScreen(_screen + _y * GAME_SCREEN_WIDTH + _x, GAME_SCREEN_WIDTH, _x, _y, cpWidth, cpHeight);
156 }
157
ControlStatus(Text * skyText,OSystem * system,uint8 * scrBuf)158 ControlStatus::ControlStatus(Text *skyText, OSystem *system, uint8 *scrBuf) {
159 _skyText = skyText;
160 _system = system;
161 _screenBuf = scrBuf;
162 _textData = NULL;
163 _statusText = new TextResource(NULL, 2, 1, 64, 163, 0, DO_NOTHING, _system, _screenBuf);
164 }
165
~ControlStatus()166 ControlStatus::~ControlStatus() {
167 free(_textData);
168 delete _statusText;
169 }
170
setToText(const char * newText)171 void ControlStatus::setToText(const char *newText) {
172 char tmpLine[256];
173 Common::strlcpy(tmpLine, newText, 256);
174 if (_textData) {
175 _statusText->flushForRedraw();
176 free(_textData);
177 }
178 DisplayedText disText = _skyText->displayText(tmpLine, NULL, true, STATUS_WIDTH, 255);
179 _textData = (DataFileHeader *)disText.textData;
180 _statusText->setSprite(_textData);
181 _statusText->drawToScreen(WITH_MASK);
182 }
183
setToText(uint16 textNum)184 void ControlStatus::setToText(uint16 textNum) {
185 free(_textData);
186 DisplayedText disText = _skyText->displayText(textNum, NULL, true, STATUS_WIDTH, 255);
187 _textData = (DataFileHeader *)disText.textData;
188 _statusText->setSprite(_textData);
189 _statusText->drawToScreen(WITH_MASK);
190 }
191
drawToScreen()192 void ControlStatus::drawToScreen() {
193 _statusText->flushForRedraw();
194 _statusText->drawToScreen(WITH_MASK);
195 }
196
Control(Common::SaveFileManager * saveFileMan,Screen * screen,Disk * disk,Mouse * mouse,Text * text,MusicBase * music,Logic * logic,Sound * sound,SkyCompact * skyCompact,OSystem * system)197 Control::Control(Common::SaveFileManager *saveFileMan, Screen *screen, Disk *disk, Mouse *mouse, Text *text, MusicBase *music, Logic *logic, Sound *sound, SkyCompact *skyCompact, OSystem *system) {
198 _saveFileMan = saveFileMan;
199
200 _skyScreen = screen;
201 _skyDisk = disk;
202 _skyMouse = mouse;
203 _skyText = text;
204 _skyMusic = music;
205 _skyLogic = logic;
206 _skySound = sound;
207 _skyCompact = skyCompact;
208 _system = system;
209 _controlPanel = NULL;
210 }
211
createResource(void * pSpData,uint32 pNSprites,uint32 pCurSprite,int16 pX,int16 pY,uint32 pText,uint8 pOnClick,uint8 panelType)212 ConResource *Control::createResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, int16 pX, int16 pY, uint32 pText, uint8 pOnClick, uint8 panelType) {
213 if (pText) pText += 0x7000;
214 if (panelType == MAINPANEL) {
215 pX += MPNL_X;
216 pY += MPNL_Y;
217 } else {
218 pX += SPNL_X;
219 pY += SPNL_Y;
220 }
221 return new ConResource(pSpData, pNSprites, pCurSprite, pX, pY, pText, pOnClick, _system, _screenBuf);
222 }
223
removePanel()224 void Control::removePanel() {
225 free(_screenBuf);
226 free(_sprites.controlPanel); free(_sprites.button);
227 free(_sprites.buttonDown); free(_sprites.savePanel);
228 free(_sprites.yesNo); free(_sprites.slide);
229 free(_sprites.slide2); free(_sprites.slode);
230 free(_sprites.slode2); free(_sprites.musicBodge);
231 delete _controlPanel; delete _exitButton;
232 _controlPanel = NULL;
233 delete _slide; delete _slide2;
234 delete _slode; delete _restorePanButton;
235 delete _savePanel; delete _saveButton;
236 delete _downFastButton; delete _downSlowButton;
237 delete _upFastButton; delete _upSlowButton;
238 delete _quitButton; delete _autoSaveButton;
239 delete _savePanButton; delete _dosPanButton;
240 delete _restartPanButton; delete _fxPanButton;
241 delete _musicPanButton; delete _bodge;
242 delete _yesNo; delete _text;
243 delete _statusBar; delete _restoreButton;
244
245 if (_textSprite) {
246 free(_textSprite);
247 _textSprite = NULL;
248 }
249 }
250
initPanel()251 void Control::initPanel() {
252 _screenBuf = (uint8 *)malloc(GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
253 memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
254
255 uint16 volY = (127 - _skyMusic->giveVolume()) / 4 + 59 - MPNL_Y; // volume slider's Y coordinate
256 uint16 spdY = (SkyEngine::_systemVars.gameSpeed - 2) / SPEED_MULTIPLY;
257 spdY += MPNL_Y + 83; // speed slider's initial position
258
259 _sprites.controlPanel = _skyDisk->loadFile(60500);
260 _sprites.button = _skyDisk->loadFile(60501);
261 _sprites.buttonDown = _skyDisk->loadFile(60502);
262 _sprites.savePanel = _skyDisk->loadFile(60503);
263 _sprites.yesNo = _skyDisk->loadFile(60504);
264 _sprites.slide = _skyDisk->loadFile(60505);
265 _sprites.slode = _skyDisk->loadFile(60506);
266 _sprites.slode2 = _skyDisk->loadFile(60507);
267 _sprites.slide2 = _skyDisk->loadFile(60508);
268 if (SkyEngine::_systemVars.gameVersion < 368)
269 _sprites.musicBodge = NULL;
270 else
271 _sprites.musicBodge = _skyDisk->loadFile(60509);
272
273 //Main control panel: X Y Text OnClick
274 _controlPanel = createResource(_sprites.controlPanel, 1, 0, 0, 0, 0, DO_NOTHING, MAINPANEL);
275 _exitButton = createResource( _sprites.button, 3, 0, 16, 125, 50, EXIT, MAINPANEL);
276 _slide = createResource( _sprites.slide2, 1, 0, 19,spdY, 95, SPEED_SLIDE, MAINPANEL);
277 _slide2 = createResource( _sprites.slide2, 1, 0, 19,volY, 14, MUSIC_SLIDE, MAINPANEL);
278 _slode = createResource( _sprites.slode2, 1, 0, 9, 49, 0, DO_NOTHING, MAINPANEL);
279 _restorePanButton = createResource( _sprites.button, 3, 0, 58, 19, 51, REST_GAME_PANEL, MAINPANEL);
280 _savePanButton = createResource( _sprites.button, 3, 0, 58, 39, 48, SAVE_GAME_PANEL, MAINPANEL);
281 _dosPanButton = createResource( _sprites.button, 3, 0, 58, 59, 93, QUIT_TO_DOS, MAINPANEL);
282 _restartPanButton = createResource( _sprites.button, 3, 0, 58, 79, 94, RESTART, MAINPANEL);
283 _fxPanButton = createResource( _sprites.button, 3, 0, 58, 99, 90, TOGGLE_FX, MAINPANEL);
284
285 if (SkyEngine::isCDVersion()) { // CD Version: Toggle text/speech
286 _musicPanButton = createResource( _sprites.button, 3, 0, 58, 119, 52, TOGGLE_TEXT, MAINPANEL);
287 } else { // disk version: toggle music on/off
288 _musicPanButton = createResource( _sprites.button, 3, 0, 58, 119, 91, TOGGLE_MS, MAINPANEL);
289 }
290 _bodge = createResource( _sprites.musicBodge, 2, 1, 98, 115, 0, DO_NOTHING, MAINPANEL);
291 _yesNo = createResource( _sprites.yesNo, 1, 0, -2, 40, 0, DO_NOTHING, MAINPANEL);
292
293 _text = new TextResource(NULL, 1, 0, 15, 137, 0, DO_NOTHING, _system, _screenBuf);
294 _controlPanLookList[0] = _exitButton;
295 _controlPanLookList[1] = _restorePanButton;
296 _controlPanLookList[2] = _savePanButton;
297 _controlPanLookList[3] = _dosPanButton;
298 _controlPanLookList[4] = _restartPanButton;
299 _controlPanLookList[5] = _fxPanButton;
300 _controlPanLookList[6] = _musicPanButton;
301 _controlPanLookList[7] = _slide;
302 _controlPanLookList[8] = _slide2;
303
304 // save/restore panel
305 _savePanel = createResource( _sprites.savePanel, 1, 0, 0, 0, 0, DO_NOTHING, SAVEPANEL);
306 _saveButton = createResource( _sprites.button, 3, 0, 29, 129, 48, SAVE_A_GAME, SAVEPANEL);
307 _downFastButton = createResource(_sprites.buttonDown, 1, 0, 212, 114, 0, SHIFT_DOWN_FAST, SAVEPANEL);
308 _downSlowButton = createResource(_sprites.buttonDown, 1, 0, 212, 104, 0, SHIFT_DOWN_SLOW, SAVEPANEL);
309 _upFastButton = createResource(_sprites.buttonDown, 1, 0, 212, 10, 0, SHIFT_UP_FAST, SAVEPANEL);
310 _upSlowButton = createResource(_sprites.buttonDown, 1, 0, 212, 21, 0, SHIFT_UP_SLOW, SAVEPANEL);
311 _quitButton = createResource( _sprites.button, 3, 0, 72, 129, 49, SP_CANCEL, SAVEPANEL);
312 _restoreButton = createResource( _sprites.button, 3, 0, 29, 129, 51, RESTORE_A_GAME, SAVEPANEL);
313 _autoSaveButton = createResource( _sprites.button, 3, 0, 115, 129, 0x8FFF, RESTORE_AUTO, SAVEPANEL);
314
315 _savePanLookList[0] = _saveButton;
316 _restorePanLookList[0] = _restoreButton;
317 _restorePanLookList[1] = _savePanLookList[1] = _downSlowButton;
318 _restorePanLookList[2] = _savePanLookList[2] = _downFastButton;
319 _restorePanLookList[3] = _savePanLookList[3] = _upFastButton;
320 _restorePanLookList[4] = _savePanLookList[4] = _upSlowButton;
321 _restorePanLookList[5] = _savePanLookList[5] = _quitButton;
322 _restorePanLookList[6] = _autoSaveButton;
323
324 _statusBar = new ControlStatus(_skyText, _system, _screenBuf);
325
326 _textSprite = NULL;
327 }
328
buttonControl(ConResource * pButton)329 void Control::buttonControl(ConResource *pButton) {
330 char autoSave[50] = "Restore Autosave";
331
332 if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS)
333 strncpy(autoSave, "Zarpyzit/ abtocoxpahehie", 50);
334
335 if (pButton == NULL) {
336 free(_textSprite);
337 _textSprite = NULL;
338 _curButtonText = 0;
339 _text->setSprite(NULL);
340 return;
341 }
342 if (_curButtonText != pButton->_text) {
343 free(_textSprite);
344 _textSprite = NULL;
345 _curButtonText = pButton->_text;
346 if (pButton->_text) {
347 DisplayedText textRes;
348 if (pButton->_text == 0xFFFF) // text for autosave button
349 textRes = _skyText->displayText(autoSave, NULL, false, PAN_LINE_WIDTH, 255);
350 else
351 textRes = _skyText->displayText(pButton->_text, NULL, false, PAN_LINE_WIDTH, 255);
352 _textSprite = (DataFileHeader *)textRes.textData;
353 _text->setSprite(_textSprite);
354 } else
355 _text->setSprite(NULL);
356 }
357 Common::Point mouse = _system->getEventManager()->getMousePos();
358 int destY = (mouse.y - 16 >= 0) ? mouse.y - 16 : 0;
359 _text->setXY(mouse.x + 12, destY);
360 }
361
drawTextCross(uint32 flags)362 void Control::drawTextCross(uint32 flags) {
363 _bodge->drawToScreen(NO_MASK);
364 if (!(flags & SF_ALLOW_SPEECH))
365 drawCross(151, 124);
366 if (!(flags & SF_ALLOW_TEXT))
367 drawCross(173, 124);
368 }
369
drawCross(uint16 x,uint16 y)370 void Control::drawCross(uint16 x, uint16 y) {
371 _text->flushForRedraw();
372 uint8 *bufPos, *crossPos;
373 bufPos = _screenBuf + y * GAME_SCREEN_WIDTH + x;
374 crossPos = _crossImg;
375 for (uint16 cnty = 0; cnty < CROSS_SZ_Y; cnty++) {
376 for (uint16 cntx = 0; cntx < CROSS_SZ_X; cntx++)
377 if (crossPos[cntx] != 0xFF)
378 bufPos[cntx] = crossPos[cntx];
379 bufPos += GAME_SCREEN_WIDTH;
380 crossPos += CROSS_SZ_X;
381 }
382 bufPos = _screenBuf + y * GAME_SCREEN_WIDTH + x;
383 _system->copyRectToScreen(bufPos, GAME_SCREEN_WIDTH, x, y, CROSS_SZ_X, CROSS_SZ_Y);
384 _text->drawToScreen(WITH_MASK);
385 }
386
animClick(ConResource * pButton)387 void Control::animClick(ConResource *pButton) {
388 if (pButton->_curSprite != pButton->_numSprites -1) {
389 pButton->_curSprite++;
390 _text->flushForRedraw();
391 pButton->drawToScreen(NO_MASK);
392 _text->drawToScreen(WITH_MASK);
393 _system->updateScreen();
394 delay(CLICK_DELAY);
395 if (!_controlPanel)
396 return;
397 pButton->_curSprite--;
398 _text->flushForRedraw();
399 pButton->drawToScreen(NO_MASK);
400 _text->drawToScreen(WITH_MASK);
401 _system->updateScreen();
402 }
403 }
404
drawMainPanel()405 void Control::drawMainPanel() {
406 memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
407 _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
408 if (_controlPanel)
409 _controlPanel->drawToScreen(NO_MASK);
410 _exitButton->drawToScreen(NO_MASK);
411 _savePanButton->drawToScreen(NO_MASK);
412 _restorePanButton->drawToScreen(NO_MASK);
413 _dosPanButton->drawToScreen(NO_MASK);
414 _restartPanButton->drawToScreen(NO_MASK);
415 _fxPanButton->drawToScreen(NO_MASK);
416 _musicPanButton->drawToScreen(NO_MASK);
417 _slode->drawToScreen(WITH_MASK);
418 _slide->drawToScreen(WITH_MASK);
419 _slide2->drawToScreen(WITH_MASK);
420 _bodge->drawToScreen(WITH_MASK);
421 if (SkyEngine::isCDVersion())
422 drawTextCross(SkyEngine::_systemVars.systemFlags & TEXT_FLAG_MASK);
423 _statusBar->drawToScreen();
424 }
425
doLoadSavePanel()426 void Control::doLoadSavePanel() {
427 if (SkyEngine::isDemo())
428 return; // I don't think this can even happen
429 initPanel();
430 _skyScreen->clearScreen();
431 if (SkyEngine::_systemVars.gameVersion < 331)
432 _skyScreen->setPalette(60509);
433 else
434 _skyScreen->setPalette(60510);
435
436 _savedMouse = _skyMouse->giveCurrentMouseType();
437 _savedCharSet = _skyText->giveCurrentCharSet();
438 _skyText->fnSetFont(2);
439 _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
440 _lastButton = -1;
441 _curButtonText = 0;
442
443 saveRestorePanel(false);
444
445 memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
446 _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
447 _system->updateScreen();
448 _skyScreen->forceRefresh();
449 _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
450 removePanel();
451 _skyMouse->spriteMouse(_savedMouse, 0, 0);
452 _skyText->fnSetFont(_savedCharSet);
453 }
454
doControlPanel()455 void Control::doControlPanel() {
456 if (SkyEngine::isDemo()) {
457 return;
458 }
459
460 initPanel();
461
462 _savedCharSet = _skyText->giveCurrentCharSet();
463 _skyText->fnSetFont(2);
464
465 _skyScreen->clearScreen();
466 if (SkyEngine::_systemVars.gameVersion < 331)
467 _skyScreen->setPalette(60509);
468 else
469 _skyScreen->setPalette(60510);
470
471 // Set initial button lights
472 _fxPanButton->_curSprite =
473 (SkyEngine::_systemVars.systemFlags & SF_FX_OFF ? 0 : 2);
474
475 // music button only available in floppy version
476 if (!SkyEngine::isCDVersion())
477 _musicPanButton->_curSprite =
478 (SkyEngine::_systemVars.systemFlags & SF_MUS_OFF ? 0 : 2);
479
480 drawMainPanel();
481
482 _savedMouse = _skyMouse->giveCurrentMouseType();
483
484 _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
485 bool quitPanel = false;
486 _lastButton = -1;
487 _curButtonText = 0;
488 uint16 clickRes = 0;
489
490 while (!quitPanel && !Engine::shouldQuit()) {
491 _text->drawToScreen(WITH_MASK);
492 _system->updateScreen();
493 _mouseClicked = false;
494 delay(ANIM_DELAY);
495 if (!_controlPanel)
496 return;
497 if (_keyPressed.keycode == Common::KEYCODE_ESCAPE) { // escape pressed
498 _mouseClicked = false;
499 quitPanel = true;
500 }
501 bool haveButton = false;
502 Common::Point mouse = _system->getEventManager()->getMousePos();
503 for (uint8 lookCnt = 0; lookCnt < 9; lookCnt++) {
504 if (_controlPanLookList[lookCnt]->isMouseOver(mouse.x, mouse.y)) {
505 haveButton = true;
506 buttonControl(_controlPanLookList[lookCnt]);
507 if (_mouseClicked && _controlPanLookList[lookCnt]->_onClick) {
508 clickRes = handleClick(_controlPanLookList[lookCnt]);
509 if (!_controlPanel) //game state was destroyed
510 return;
511 _text->flushForRedraw();
512 drawMainPanel();
513 _text->drawToScreen(WITH_MASK);
514 if ((clickRes == QUIT_PANEL) || (clickRes == GAME_SAVED) ||
515 (clickRes == GAME_RESTORED))
516 quitPanel = true;
517 }
518 _mouseClicked = false;
519 }
520 }
521 if (!haveButton)
522 buttonControl(NULL);
523 }
524 memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
525 _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
526 if (!Engine::shouldQuit())
527 _system->updateScreen();
528 _skyScreen->forceRefresh();
529 _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
530 removePanel();
531 _skyMouse->spriteMouse(_savedMouse, 0, 0);
532 _skyText->fnSetFont(_savedCharSet);
533 }
534
handleClick(ConResource * pButton)535 uint16 Control::handleClick(ConResource *pButton) {
536 char quitDos[50] = "Quit to DOS?";
537 char restart[50] = "Restart?";
538
539 if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
540 strncpy(quitDos, "B[uti b DOC?", 50);
541 strncpy(restart, "Hobaq irpa?", 50);
542 }
543
544 switch (pButton->_onClick) {
545 case DO_NOTHING:
546 return 0;
547 case REST_GAME_PANEL:
548 if (!loadSaveAllowed())
549 return CANCEL_PRESSED; // can't save/restore while choosing
550 animClick(pButton);
551 return saveRestorePanel(false); // texts can't be edited
552 case SAVE_GAME_PANEL:
553 if (!loadSaveAllowed())
554 return CANCEL_PRESSED; // can't save/restore while choosing
555 animClick(pButton);
556 return saveRestorePanel(true); // texts can be edited
557 case SAVE_A_GAME:
558 animClick(pButton);
559 return saveGameToFile(true);
560 case RESTORE_A_GAME:
561 animClick(pButton);
562 return restoreGameFromFile(false);
563 case RESTORE_AUTO:
564 animClick(pButton);
565 return restoreGameFromFile(true);
566 case SP_CANCEL:
567 animClick(pButton);
568 return CANCEL_PRESSED;
569 case SHIFT_DOWN_FAST:
570 animClick(pButton);
571 return shiftDown(FAST);
572 case SHIFT_DOWN_SLOW:
573 animClick(pButton);
574 return shiftDown(SLOW);
575 case SHIFT_UP_FAST:
576 animClick(pButton);
577 return shiftUp(FAST);
578 case SHIFT_UP_SLOW:
579 animClick(pButton);
580 return shiftUp(SLOW);
581 case SPEED_SLIDE:
582 _mouseClicked = true;
583 return doSpeedSlide();
584 case MUSIC_SLIDE:
585 _mouseClicked = true;
586 return doMusicSlide();
587 case TOGGLE_FX:
588 toggleFx(pButton);
589 return TOGGLED;
590 case TOGGLE_MS:
591 toggleMusic(pButton);
592 return TOGGLED;
593 case TOGGLE_TEXT:
594 animClick(pButton);
595 return toggleText();
596 case EXIT:
597 animClick(pButton);
598 return QUIT_PANEL;
599 case RESTART:
600 animClick(pButton);
601 if (getYesNo(restart)) {
602 restartGame();
603 return GAME_RESTORED;
604 } else
605 return 0;
606 case QUIT_TO_DOS:
607 animClick(pButton);
608 if (getYesNo(quitDos))
609 Engine::quitGame();
610 return 0;
611 default:
612 error("Control::handleClick: unknown routine: %X",pButton->_onClick);
613 }
614 }
615
getYesNo(char * text)616 bool Control::getYesNo(char *text) {
617 bool retVal = false;
618 bool quitPanel = false;
619 uint8 mouseType = MOUSE_NORMAL;
620 uint8 wantMouse = MOUSE_NORMAL;
621 DataFileHeader *dlgTextDat;
622 uint16 textY = MPNL_Y;
623
624 _yesNo->drawToScreen(WITH_MASK);
625 if (text) {
626 DisplayedText dlgLtm = _skyText->displayText(text, NULL, true, _yesNo->_spriteData->s_width - 8, 37);
627 dlgTextDat = (DataFileHeader *)dlgLtm.textData;
628 textY = MPNL_Y + 44 + (28 - dlgTextDat->s_height) / 2;
629 } else
630 dlgTextDat = NULL;
631
632 TextResource *dlgText = new TextResource(dlgTextDat, 1, 0, MPNL_X+2, textY, 0, DO_NOTHING, _system, _screenBuf);
633 dlgText->drawToScreen(WITH_MASK);
634
635 while (!quitPanel) {
636 if (mouseType != wantMouse) {
637 mouseType = wantMouse;
638 _skyMouse->spriteMouse(mouseType, 0, 0);
639 }
640 _system->updateScreen();
641 delay(ANIM_DELAY);
642 if (!_controlPanel) {
643 free(dlgTextDat);
644 delete dlgText;
645 return retVal;
646 }
647 Common::Point mouse = _system->getEventManager()->getMousePos();
648 if ((mouse.y >= 83) && (mouse.y <= 110)) {
649 if ((mouse.x >= 77) && (mouse.x <= 114)) { // over 'yes'
650 wantMouse = MOUSE_CROSS;
651 if (_mouseClicked) {
652 quitPanel = true;
653 retVal = true;
654 }
655 } else if ((mouse.x >= 156) && (mouse.x <= 193)) { // over 'no'
656 wantMouse = MOUSE_CROSS;
657 if (_mouseClicked) {
658 quitPanel = true;
659 retVal = false;
660 }
661 } else
662 wantMouse = MOUSE_NORMAL;
663 } else
664 wantMouse = MOUSE_NORMAL;
665 }
666 _mouseClicked = false;
667 _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
668 free(dlgTextDat);
669 delete dlgText;
670 return retVal;
671 }
672
doMusicSlide()673 uint16 Control::doMusicSlide() {
674 Common::Point mouse = _system->getEventManager()->getMousePos();
675 int ofsY = _slide2->_y - mouse.y;
676 uint8 volume;
677 while (_mouseClicked) {
678 delay(ANIM_DELAY);
679 if (!_controlPanel)
680 return 0;
681 mouse = _system->getEventManager()->getMousePos();
682 int newY = ofsY + mouse.y;
683 if (newY < 59) newY = 59;
684 if (newY > 91) newY = 91;
685 if (newY != _slide2->_y) {
686 _slode->drawToScreen(NO_MASK);
687 _slide2->setXY(_slide2->_x, (uint16)newY);
688 _slide2->drawToScreen(WITH_MASK);
689 _slide->drawToScreen(WITH_MASK);
690 volume = (newY - 59) * 4;
691 if (volume >= 128) volume = 0;
692 else volume = 127 - volume;
693 _skyMusic->setVolume(volume);
694 }
695 buttonControl(_slide2);
696 _text->drawToScreen(WITH_MASK);
697 _system->updateScreen();
698 }
699 return 0;
700 }
701
doSpeedSlide()702 uint16 Control::doSpeedSlide() {
703 Common::Point mouse = _system->getEventManager()->getMousePos();
704 int ofsY = _slide->_y - mouse.y;
705 uint16 speedDelay = _slide->_y - (MPNL_Y + 93);
706 speedDelay *= SPEED_MULTIPLY;
707 speedDelay += 2;
708 while (_mouseClicked) {
709 delay(ANIM_DELAY);
710 if (!_controlPanel)
711 return SPEED_CHANGED;
712 mouse = _system->getEventManager()->getMousePos();
713 int newY = ofsY + mouse.y;
714 if (newY < MPNL_Y + 93) newY = MPNL_Y + 93;
715 if (newY > MPNL_Y + 104) newY = MPNL_Y + 104;
716 if ((newY == 110) || (newY == 108)) newY = 109;
717 if (newY != _slide->_y) {
718 _slode->drawToScreen(NO_MASK);
719 _slide->setXY(_slide->_x, (uint16)newY);
720 _slide->drawToScreen(WITH_MASK);
721 _slide2->drawToScreen(WITH_MASK);
722 speedDelay = newY - (MPNL_Y + 93);
723 speedDelay *= SPEED_MULTIPLY;
724 speedDelay += 2;
725 }
726 buttonControl(_slide);
727 _text->drawToScreen(WITH_MASK);
728 _system->updateScreen();
729 }
730 SkyEngine::_systemVars.gameSpeed = speedDelay;
731 return SPEED_CHANGED;
732 }
733
toggleFx(ConResource * pButton)734 void Control::toggleFx(ConResource *pButton) {
735 SkyEngine::_systemVars.systemFlags ^= SF_FX_OFF;
736 if (SkyEngine::_systemVars.systemFlags & SF_FX_OFF) {
737 pButton->_curSprite = 0;
738 _statusBar->setToText(0x7000 + 87);
739 } else {
740 pButton->_curSprite = 2;
741 _statusBar->setToText(0x7000 + 86);
742 }
743
744 ConfMan.setBool("sfx_mute", (SkyEngine::_systemVars.systemFlags & SF_FX_OFF) != 0);
745
746 pButton->drawToScreen(WITH_MASK);
747 _system->updateScreen();
748 }
749
toggleText()750 uint16 Control::toggleText() {
751 uint32 flags = SkyEngine::_systemVars.systemFlags & TEXT_FLAG_MASK;
752 SkyEngine::_systemVars.systemFlags &= ~TEXT_FLAG_MASK;
753
754 if (flags == SF_ALLOW_TEXT) {
755 flags = SF_ALLOW_SPEECH;
756 _statusBar->setToText(0x7000 + 21); // speech only
757 } else if (flags == SF_ALLOW_SPEECH) {
758 flags = SF_ALLOW_SPEECH | SF_ALLOW_TEXT;
759 _statusBar->setToText(0x7000 + 52); // text and speech
760 } else {
761 flags = SF_ALLOW_TEXT;
762 _statusBar->setToText(0x7000 + 35); // text only
763 }
764
765 ConfMan.setBool("subtitles", (flags & SF_ALLOW_TEXT) != 0);
766 ConfMan.setBool("speech_mute", (flags & SF_ALLOW_SPEECH) == 0);
767
768 SkyEngine::_systemVars.systemFlags |= flags;
769
770 drawTextCross(flags);
771
772 _system->updateScreen();
773 return TOGGLED;
774 }
775
toggleMusic(ConResource * pButton)776 void Control::toggleMusic(ConResource *pButton) {
777 SkyEngine::_systemVars.systemFlags ^= SF_MUS_OFF;
778 if (SkyEngine::_systemVars.systemFlags & SF_MUS_OFF) {
779 _skyMusic->startMusic(0);
780 pButton->_curSprite = 0;
781 _statusBar->setToText(0x7000 + 89);
782 } else {
783 _skyMusic->startMusic(SkyEngine::_systemVars.currentMusic);
784 pButton->_curSprite = 2;
785 _statusBar->setToText(0x7000 + 88);
786 }
787
788 ConfMan.setBool("music_mute", (SkyEngine::_systemVars.systemFlags & SF_MUS_OFF) != 0);
789
790 pButton->drawToScreen(WITH_MASK);
791 _system->updateScreen();
792 }
793
shiftDown(uint8 speed)794 uint16 Control::shiftDown(uint8 speed) {
795 if (speed == SLOW) {
796 if (_firstText >= MAX_SAVE_GAMES - MAX_ON_SCREEN)
797 return 0;
798 _firstText++;
799 } else {
800 if (_firstText <= MAX_SAVE_GAMES - 2 * MAX_ON_SCREEN)
801 _firstText += MAX_ON_SCREEN;
802 else if (_firstText < MAX_SAVE_GAMES - MAX_ON_SCREEN)
803 _firstText = MAX_SAVE_GAMES - MAX_ON_SCREEN;
804 else
805 return 0;
806 }
807
808 return SHIFTED;
809 }
810
shiftUp(uint8 speed)811 uint16 Control::shiftUp(uint8 speed) {
812 if (speed == SLOW) {
813 if (_firstText > 0)
814 _firstText--;
815 else
816 return 0;
817 } else {
818 if (_firstText >= MAX_ON_SCREEN)
819 _firstText -= MAX_ON_SCREEN;
820 else if (_firstText > 0)
821 _firstText = 0;
822 else
823 return 0;
824 }
825 return SHIFTED;
826 }
827
autoSaveExists()828 bool Control::autoSaveExists() {
829 bool test = false;
830 Common::InSaveFile *f;
831 char fName[20];
832 if (SkyEngine::isCDVersion())
833 strcpy(fName, "SKY-VM-CD.ASD");
834 else
835 sprintf(fName, "SKY-VM%03d.ASD", SkyEngine::_systemVars.gameVersion);
836
837 f = _saveFileMan->openForLoading(fName);
838 if (f != NULL) {
839 test = true;
840 delete f;
841 }
842 return test;
843 }
844
saveRestorePanel(bool allowSave)845 uint16 Control::saveRestorePanel(bool allowSave) {
846 _keyPressed.reset();
847 _mouseWheel = 0;
848 buttonControl(NULL);
849 _text->drawToScreen(WITH_MASK); // flush text restore buffer
850
851 ConResource **lookList;
852 uint16 cnt;
853 uint8 lookListLen;
854 if (allowSave) {
855 lookList = _savePanLookList;
856 lookListLen = 6;
857 _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
858 } else {
859 lookList = _restorePanLookList;
860 if (autoSaveExists())
861 lookListLen = 7;
862 else
863 lookListLen = 6;
864 }
865 bool withAutoSave = (lookListLen == 7);
866
867 Common::StringArray saveGameTexts;
868 DataFileHeader *textSprites[MAX_ON_SCREEN + 1];
869 for (cnt = 0; cnt < MAX_ON_SCREEN + 1; cnt++)
870 textSprites[cnt] = NULL;
871 _firstText = 0;
872
873 loadDescriptions(saveGameTexts);
874 _selectedGame = 0;
875
876 bool quitPanel = false;
877 bool refreshNames = true;
878 bool refreshAll = true;
879 uint16 clickRes = 0;
880 while (!quitPanel && !Engine::shouldQuit()) {
881 clickRes = 0;
882 if (refreshNames || refreshAll) {
883 if (refreshAll) {
884 _text->flushForRedraw();
885 _savePanel->drawToScreen(NO_MASK);
886 _quitButton->drawToScreen(NO_MASK);
887 if (withAutoSave)
888 _autoSaveButton->drawToScreen(NO_MASK);
889 refreshAll = false;
890 }
891 for (cnt = 0; cnt < MAX_ON_SCREEN; cnt++)
892 if (textSprites[cnt])
893 free(textSprites[cnt]);
894 setUpGameSprites(saveGameTexts, textSprites, _firstText, _selectedGame);
895 showSprites(textSprites, allowSave);
896 refreshNames = false;
897 }
898
899 _text->drawToScreen(WITH_MASK);
900 _system->updateScreen();
901 _mouseClicked = false;
902 delay(ANIM_DELAY);
903 if (!_controlPanel)
904 return clickRes;
905 if (_keyPressed.keycode == Common::KEYCODE_ESCAPE) { // escape pressed
906 _mouseClicked = false;
907 clickRes = CANCEL_PRESSED;
908 quitPanel = true;
909 } else if ((_keyPressed.keycode == Common::KEYCODE_RETURN) || (_keyPressed.keycode == Common::KEYCODE_KP_ENTER)) {
910 clickRes = handleClick(lookList[0]);
911 if (!_controlPanel) //game state was destroyed
912 return clickRes;
913 if (clickRes == GAME_SAVED)
914 saveDescriptions(saveGameTexts);
915 else if (clickRes == NO_DISK_SPACE)
916 displayMessage(0, "Could not save the game. (%s)", _saveFileMan->popErrorDesc().c_str());
917 quitPanel = true;
918 _mouseClicked = false;
919 _keyPressed.reset();
920 } if (allowSave && _keyPressed.keycode) {
921 handleKeyPress(_keyPressed, saveGameTexts[_selectedGame]);
922 refreshNames = true;
923 _keyPressed.reset();
924 }
925
926 if (_mouseWheel) {
927 if (_mouseWheel < 0)
928 clickRes = shiftUp(SLOW);
929 else if (_mouseWheel > 0)
930 clickRes = shiftDown(SLOW);
931 _mouseWheel = 0;
932 if (clickRes == SHIFTED) {
933 _selectedGame = _firstText;
934 refreshNames = true;
935 }
936 }
937
938 bool haveButton = false;
939 Common::Point mouse = _system->getEventManager()->getMousePos();
940 for (cnt = 0; cnt < lookListLen; cnt++)
941 if (lookList[cnt]->isMouseOver(mouse.x, mouse.y)) {
942 buttonControl(lookList[cnt]);
943 haveButton = true;
944
945 if (_mouseClicked && lookList[cnt]->_onClick) {
946 _mouseClicked = false;
947
948 clickRes = handleClick(lookList[cnt]);
949 if (!_controlPanel) //game state was destroyed
950 return clickRes;
951
952 if (clickRes == SHIFTED) {
953 _selectedGame = _firstText;
954 refreshNames = true;
955 }
956 if (clickRes == NO_DISK_SPACE) {
957 displayMessage(0, "Could not save the game. (%s)", _saveFileMan->popErrorDesc().c_str());
958 quitPanel = true;
959 }
960 if ((clickRes == CANCEL_PRESSED) || (clickRes == GAME_RESTORED))
961 quitPanel = true;
962
963 if (clickRes == GAME_SAVED) {
964 saveDescriptions(saveGameTexts);
965 quitPanel = true;
966 }
967 if (clickRes == RESTORE_FAILED)
968 refreshAll = true;
969 }
970 }
971
972 if (_mouseClicked) {
973 if ((mouse.x >= GAME_NAME_X) && (mouse.x <= GAME_NAME_X + PAN_LINE_WIDTH) &&
974 (mouse.y >= GAME_NAME_Y) && (mouse.y <= GAME_NAME_Y + PAN_CHAR_HEIGHT * MAX_ON_SCREEN)) {
975
976 _selectedGame = (mouse.y - GAME_NAME_Y) / PAN_CHAR_HEIGHT + _firstText;
977 refreshNames = true;
978 }
979 }
980 if (!haveButton)
981 buttonControl(NULL);
982 }
983
984 for (cnt = 0; cnt < MAX_ON_SCREEN + 1; cnt++)
985 free(textSprites[cnt]);
986
987 if (allowSave) {
988 _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
989 }
990
991 return clickRes;
992 }
993
handleKeyPress(Common::KeyState kbd,Common::String & textBuf)994 void Control::handleKeyPress(Common::KeyState kbd, Common::String &textBuf) {
995 if (kbd.keycode == Common::KEYCODE_BACKSPACE) { // backspace
996 if (textBuf.size() > 0)
997 textBuf.deleteLastChar();
998 } else if (kbd.ascii) {
999 // Cannot enter text wider than the save/load panel
1000 if (_enteredTextWidth >= PAN_LINE_WIDTH - 10)
1001 return;
1002
1003 // Cannot enter text longer than MAX_TEXT_LEN-1 chars, since
1004 // the storage is only so big. Note: The code used to incorrectly
1005 // allow up to MAX_TEXT_LEN, which caused an out of bounds access,
1006 // overwriting the next entry in the list of savegames partially.
1007 // This could be triggered by e.g. entering lots of periods ".".
1008 if (textBuf.size() >= MAX_TEXT_LEN - 1)
1009 return;
1010
1011 // Allow the key only if is a letter, a digit, or one of a selected
1012 // list of extra characters
1013 if (Common::isAlnum(kbd.ascii) || strchr(" ,().='-&+!?\"", kbd.ascii) != 0) {
1014 textBuf += kbd.ascii;
1015 }
1016 }
1017 }
1018
setUpGameSprites(const Common::StringArray & saveGameNames,DataFileHeader ** nameSprites,uint16 firstNum,uint16 selectedGame)1019 void Control::setUpGameSprites(const Common::StringArray &saveGameNames, DataFileHeader **nameSprites, uint16 firstNum, uint16 selectedGame) {
1020 char cursorChar[2] = "-";
1021 DisplayedText textSpr;
1022 if (!nameSprites[MAX_ON_SCREEN]) {
1023 textSpr = _skyText->displayText(cursorChar, NULL, false, 15, 0);
1024 nameSprites[MAX_ON_SCREEN] = (DataFileHeader *)textSpr.textData;
1025 }
1026 for (uint16 cnt = 0; cnt < MAX_ON_SCREEN; cnt++) {
1027 char nameBuf[MAX_TEXT_LEN + 10];
1028 sprintf(nameBuf, "%3d: %s", firstNum + cnt + 1, saveGameNames[firstNum + cnt].c_str());
1029
1030 if (firstNum + cnt == selectedGame)
1031 textSpr = _skyText->displayText(nameBuf, NULL, false, PAN_LINE_WIDTH, 0);
1032 else
1033 textSpr = _skyText->displayText(nameBuf, NULL, false, PAN_LINE_WIDTH, 37);
1034 nameSprites[cnt] = (DataFileHeader *)textSpr.textData;
1035 if (firstNum + cnt == selectedGame) {
1036 nameSprites[cnt]->flag = 1;
1037 _enteredTextWidth = (uint16)textSpr.textWidth;
1038 } else
1039 nameSprites[cnt]->flag = 0;
1040 }
1041 }
1042
showSprites(DataFileHeader ** nameSprites,bool allowSave)1043 void Control::showSprites(DataFileHeader **nameSprites, bool allowSave) {
1044 ConResource *drawResource = new ConResource(NULL, 1, 0, 0, 0, 0, 0, _system, _screenBuf);
1045 for (uint16 cnt = 0; cnt < MAX_ON_SCREEN; cnt++) {
1046 drawResource->setSprite(nameSprites[cnt]);
1047 drawResource->setXY(GAME_NAME_X, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT);
1048 if (nameSprites[cnt]->flag) { // name is highlighted
1049 for (uint16 cnty = GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT; cnty < GAME_NAME_Y + (cnt + 1) * PAN_CHAR_HEIGHT - 1; cnty++)
1050 memset(_screenBuf + cnty * GAME_SCREEN_WIDTH + GAME_NAME_X, 37, PAN_LINE_WIDTH);
1051 drawResource->drawToScreen(WITH_MASK);
1052 if (allowSave) {
1053 drawResource->setSprite(nameSprites[MAX_ON_SCREEN]);
1054 drawResource->setXY(GAME_NAME_X + _enteredTextWidth + 1, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT + 4);
1055 drawResource->drawToScreen(WITH_MASK);
1056 }
1057 _system->copyRectToScreen(_screenBuf + (GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT) * GAME_SCREEN_WIDTH + GAME_NAME_X, GAME_SCREEN_WIDTH, GAME_NAME_X, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT, PAN_LINE_WIDTH, PAN_CHAR_HEIGHT);
1058 } else
1059 drawResource->drawToScreen(NO_MASK);
1060 }
1061 delete drawResource;
1062 }
1063
loadDescriptions(Common::StringArray & savenames)1064 void Control::loadDescriptions(Common::StringArray &savenames) {
1065 savenames.resize(MAX_SAVE_GAMES);
1066
1067 Common::InSaveFile *inf;
1068 inf = _saveFileMan->openForLoading("SKY-VM.SAV");
1069 if (inf != NULL) {
1070 char *tmpBuf = new char[MAX_SAVE_GAMES * MAX_TEXT_LEN];
1071 char *tmpPtr = tmpBuf;
1072 inf->read(tmpBuf, MAX_SAVE_GAMES * MAX_TEXT_LEN);
1073 for (int i = 0; i < MAX_SAVE_GAMES; ++i) {
1074 savenames[i] = tmpPtr;
1075 tmpPtr += savenames[i].size() + 1;
1076 }
1077 delete inf;
1078 delete[] tmpBuf;
1079 }
1080 }
1081
loadSaveAllowed()1082 bool Control::loadSaveAllowed() {
1083 if (SkyEngine::_systemVars.systemFlags & SF_CHOOSING)
1084 return false; // texts get lost during load/save, so don't allow it during choosing
1085 if (Logic::_scriptVariables[SCREEN] >= 101)
1086 return false; // same problem with LINC terminals
1087 if ((Logic::_scriptVariables[SCREEN] >= 82) &&
1088 (Logic::_scriptVariables[SCREEN] != 85) &&
1089 (Logic::_scriptVariables[SCREEN] < 90))
1090 return false; // don't allow saving in final rooms
1091
1092 return true;
1093 }
1094
displayMessage(const char * altButton,const char * message,...)1095 int Control::displayMessage(const char *altButton, const char *message, ...) {
1096 char buf[STRINGBUFLEN];
1097 va_list va;
1098
1099 va_start(va, message);
1100 vsnprintf(buf, STRINGBUFLEN, message, va);
1101 va_end(va);
1102
1103 GUI::MessageDialog dialog(buf, "OK", altButton);
1104 int result = dialog.runModal();
1105 _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
1106 return result;
1107 }
1108
saveDescriptions(const Common::StringArray & list)1109 void Control::saveDescriptions(const Common::StringArray &list) {
1110 Common::OutSaveFile *outf;
1111
1112 outf = _saveFileMan->openForSaving("SKY-VM.SAV");
1113 bool ioFailed = true;
1114 if (outf) {
1115 for (uint16 cnt = 0; cnt < MAX_SAVE_GAMES; cnt++) {
1116 outf->write(list[cnt].c_str(), list[cnt].size() + 1);
1117 }
1118 outf->finalize();
1119 if (!outf->err())
1120 ioFailed = false;
1121 delete outf;
1122 }
1123 if (ioFailed)
1124 displayMessage(NULL, "Unable to store Savegame names to file SKY-VM.SAV. (%s)", _saveFileMan->popErrorDesc().c_str());
1125 }
1126
doAutoSave()1127 void Control::doAutoSave() {
1128 char fName[20];
1129 if (SkyEngine::isCDVersion())
1130 strcpy(fName, "SKY-VM-CD.ASD");
1131 else
1132 sprintf(fName, "SKY-VM%03d.ASD", SkyEngine::_systemVars.gameVersion);
1133
1134 uint16 res = saveGameToFile(false, fName);
1135
1136 if (res != GAME_SAVED)
1137 displayMessage(0, "Unable to perform autosave to '%s'. (%s)", fName, _saveFileMan->popErrorDesc().c_str());
1138
1139 }
1140
saveGameToFile(bool fromControlPanel,const char * filename)1141 uint16 Control::saveGameToFile(bool fromControlPanel, const char *filename) {
1142 char fName[20];
1143 if (!filename) {
1144 sprintf(fName,"SKY-VM.%03d", _selectedGame);
1145 filename = fName;
1146 }
1147
1148 Common::OutSaveFile *outf;
1149 outf = _saveFileMan->openForSaving(filename);
1150 if (outf == NULL)
1151 return NO_DISK_SPACE;
1152
1153 if (!fromControlPanel) {
1154 // These variables are usually set when entering the control panel,
1155 // but not when using the GMM.
1156 _savedCharSet = _skyText->giveCurrentCharSet();
1157 _savedMouse = _skyMouse->giveCurrentMouseType();
1158 }
1159
1160 uint8 *saveData = (uint8 *)malloc(0x20000);
1161 uint32 fSize = prepareSaveData(saveData);
1162
1163 uint32 writeRes = outf->write(saveData, fSize);
1164 outf->finalize();
1165 if (outf->err())
1166 writeRes = 0;
1167 free(saveData);
1168 delete outf;
1169
1170 return (writeRes == fSize) ? GAME_SAVED : NO_DISK_SPACE;
1171 }
1172
1173 #define STOSD(ptr, val) { *(uint32 *)(ptr) = TO_LE_32(val); (ptr) += 4; }
1174 #define STOSW(ptr, val) { *(uint16 *)(ptr) = TO_LE_16(val); (ptr) += 2; }
1175
prepareSaveData(uint8 * destBuf)1176 uint32 Control::prepareSaveData(uint8 *destBuf) {
1177 uint32 cnt;
1178 memset(destBuf, 0, 4); // space for data size
1179 uint8 *destPos = destBuf + 4;
1180 STOSD(destPos, SAVE_FILE_REVISION);
1181 STOSD(destPos, SkyEngine::_systemVars.gameVersion);
1182
1183 STOSW(destPos, _skySound->_saveSounds[0]);
1184 STOSW(destPos, _skySound->_saveSounds[1]);
1185
1186 STOSD(destPos, _skyMusic->giveCurrentMusic());
1187 STOSD(destPos, _savedCharSet);
1188 STOSD(destPos, _savedMouse);
1189 STOSD(destPos, SkyEngine::_systemVars.currentPalette);
1190 for (cnt = 0; cnt < 838; cnt++)
1191 STOSD(destPos, Logic::_scriptVariables[cnt]);
1192 uint32 *loadedFilesList = _skyDisk->giveLoadedFilesList();
1193
1194 for (cnt = 0; cnt < 60; cnt++)
1195 STOSD(destPos, loadedFilesList[cnt]);
1196
1197 for (cnt = 0; cnt < _skyCompact->_numSaveIds; cnt++) {
1198 uint16 numElems;
1199 uint16 *rawCpt = (uint16 *)_skyCompact->fetchCptInfo(_skyCompact->_saveIds[cnt], &numElems, NULL, NULL);
1200 for (uint16 elemCnt = 0; elemCnt < numElems; elemCnt++)
1201 STOSW(destPos, rawCpt[elemCnt]);
1202 }
1203
1204 *(uint32 *)destBuf = TO_LE_32(destPos - destBuf); // save size
1205 return destPos - destBuf;
1206 }
1207
1208 #undef STOSD
1209 #undef STOSW
1210
1211 #define LODSD(strPtr, val) { val = READ_LE_UINT32(strPtr); (strPtr) += 4; }
1212 #define LODSW(strPtr, val) { val = READ_LE_UINT16(strPtr); (strPtr) += 2; }
1213
importOldMegaSet(uint8 ** srcPos,MegaSet * mega)1214 void Control::importOldMegaSet(uint8 **srcPos, MegaSet *mega) {
1215 LODSW(*srcPos, mega->gridWidth);
1216 LODSW(*srcPos, mega->colOffset);
1217 LODSW(*srcPos, mega->colWidth);
1218 LODSW(*srcPos, mega->lastChr);
1219 }
1220
importOldCompact(Compact * destCpt,uint8 ** srcPos,uint16 numElems,uint16 type,char * name)1221 void Control::importOldCompact(Compact* destCpt, uint8 **srcPos, uint16 numElems, uint16 type, char *name) {
1222 uint16 saveType;
1223 LODSW(*srcPos, saveType);
1224 if ((saveType & (SAVE_EXT | SAVE_TURNP)) && (numElems < 54))
1225 error("Cpt %s: Savedata doesn't match cpt size (%d)", name, numElems);
1226 if ((saveType & SAVE_MEGA0) && (numElems < 54 + 13))
1227 error("Cpt %s: Savedata doesn't match cpt size (%d)", name, numElems);
1228 if ((saveType & SAVE_MEGA1) && (numElems < 54 + 13 + 13))
1229 error("Cpt %s: Savedata doesn't match cpt size (%d)", name, numElems);
1230 if ((saveType & SAVE_MEGA2) && (numElems < 54 + 13 + 13 + 13))
1231 error("Cpt %s: Savedata doesn't match cpt size (%d)", name, numElems);
1232 if ((saveType & SAVE_MEGA3) && (numElems < 54 + 13 + 13 + 13))
1233 error("Cpt %s: Savedata doesn't match cpt size (%d)", name, numElems);
1234 if (saveType & SAVE_GRAFX) {
1235 uint16 graphType, target, pos;
1236 LODSW(*srcPos, graphType);
1237 LODSW(*srcPos, target);
1238 LODSW(*srcPos, pos);
1239 // convert to new compact system..
1240 destCpt->grafixProgPos = pos;
1241 if (graphType == OG_PTR_NULL)
1242 destCpt->grafixProgId = 0;
1243 else if (graphType == OG_AUTOROUTE)
1244 destCpt->grafixProgId = destCpt->animScratchId;
1245 else if (graphType == OG_COMPACT)
1246 destCpt->grafixProgId = target;
1247 else if (graphType == OG_TALKTABLE)
1248 destCpt->grafixProgId = ((uint16 *)_skyCompact->fetchCpt(CPT_TALK_TABLE_LIST))[target];
1249 else if (graphType == OG_COMPACTELEM)
1250 destCpt->grafixProgId = *(uint16 *)_skyCompact->getCompactElem(destCpt, target);
1251 else
1252 error("Illegal GrafixProg type encountered for compact %s", name);
1253 }
1254 if (saveType & SAVE_TURNP) {
1255 // basically impossible to import these. simply set it to end-of-turn and hope the script
1256 // will take care of it.
1257 destCpt->turnProgId = 0x13B;
1258 destCpt->turnProgPos = 1;
1259 uint16 turnSkipLen;
1260 LODSW(*srcPos, turnSkipLen);
1261 *srcPos += 2 * turnSkipLen;
1262 } else if (numElems >= 49) {
1263 destCpt->turnProgId = 0;
1264 destCpt->turnProgPos = 0;
1265 }
1266 LODSW(*srcPos, destCpt->logic);
1267 LODSW(*srcPos, destCpt->status);
1268 LODSW(*srcPos, destCpt->sync);
1269 LODSW(*srcPos, destCpt->screen);
1270 LODSW(*srcPos, destCpt->place);
1271 // getToTable
1272 LODSW(*srcPos, destCpt->xcood);
1273 LODSW(*srcPos, destCpt->ycood);
1274 LODSW(*srcPos, destCpt->frame);
1275 LODSW(*srcPos, destCpt->cursorText);
1276 LODSW(*srcPos, destCpt->mouseOn);
1277 LODSW(*srcPos, destCpt->mouseOff);
1278 LODSW(*srcPos, destCpt->mouseClick);
1279 LODSW(*srcPos, destCpt->mouseRelX);
1280 LODSW(*srcPos, destCpt->mouseRelY);
1281 LODSW(*srcPos, destCpt->mouseSizeX);
1282 LODSW(*srcPos, destCpt->mouseSizeY);
1283 LODSW(*srcPos, destCpt->actionScript);
1284 LODSW(*srcPos, destCpt->upFlag);
1285 LODSW(*srcPos, destCpt->downFlag);
1286 LODSW(*srcPos, destCpt->getToFlag);
1287 LODSW(*srcPos, destCpt->flag);
1288 LODSW(*srcPos, destCpt->mood);
1289 // grafixProg
1290 LODSW(*srcPos, destCpt->offset);
1291 LODSW(*srcPos, destCpt->mode);
1292 LODSW(*srcPos, destCpt->baseSub);
1293 LODSW(*srcPos, destCpt->baseSub_off);
1294 if (saveType & SAVE_EXT) {
1295 LODSW(*srcPos, destCpt->actionSub);
1296 LODSW(*srcPos, destCpt->actionSub_off);
1297 LODSW(*srcPos, destCpt->getToSub);
1298 LODSW(*srcPos, destCpt->getToSub_off);
1299 LODSW(*srcPos, destCpt->extraSub);
1300 LODSW(*srcPos, destCpt->extraSub_off);
1301 LODSW(*srcPos, destCpt->dir);
1302 LODSW(*srcPos, destCpt->stopScript);
1303 LODSW(*srcPos, destCpt->miniBump);
1304 LODSW(*srcPos, destCpt->leaving);
1305 LODSW(*srcPos, destCpt->atWatch);
1306 LODSW(*srcPos, destCpt->atWas);
1307 LODSW(*srcPos, destCpt->alt);
1308 LODSW(*srcPos, destCpt->request);
1309 LODSW(*srcPos, destCpt->spWidth_xx);
1310 LODSW(*srcPos, destCpt->spColor);
1311 LODSW(*srcPos, destCpt->spTextId);
1312 LODSW(*srcPos, destCpt->spTime);
1313 LODSW(*srcPos, destCpt->arAnimIndex);
1314 // turnProg
1315 LODSW(*srcPos, destCpt->waitingFor);
1316 LODSW(*srcPos, destCpt->arTargetX);
1317 LODSW(*srcPos, destCpt->arTargetY);
1318 // animScratch
1319 LODSW(*srcPos, destCpt->megaSet);
1320 if (saveType & SAVE_MEGA0)
1321 importOldMegaSet(srcPos, &(destCpt->megaSet0));
1322 if (saveType & SAVE_MEGA1)
1323 importOldMegaSet(srcPos, &(destCpt->megaSet1));
1324 if (saveType & SAVE_MEGA2)
1325 importOldMegaSet(srcPos, &(destCpt->megaSet2));
1326 if (saveType & SAVE_MEGA3)
1327 importOldMegaSet(srcPos, &(destCpt->megaSet3));
1328 }
1329 }
1330
parseSaveData(uint8 * srcBuf)1331 uint16 Control::parseSaveData(uint8 *srcBuf) {
1332 uint32 reloadList[60];
1333 uint32 cnt;
1334 uint8 *srcPos = srcBuf;
1335 uint32 size;
1336 uint32 saveRev;
1337 uint32 gameVersion;
1338 LODSD(srcPos, size);
1339 LODSD(srcPos, saveRev);
1340 if (saveRev > SAVE_FILE_REVISION) {
1341 displayMessage(0, "Unknown save file revision (%d)", saveRev);
1342 return RESTORE_FAILED;
1343 } else if (saveRev < OLD_SAVEGAME_TYPE) {
1344 displayMessage(0, "This saved game version is unsupported.");
1345 return RESTORE_FAILED;
1346 }
1347 LODSD(srcPos, gameVersion);
1348 if (gameVersion != SkyEngine::_systemVars.gameVersion) {
1349 if ((!SkyEngine::isCDVersion()) || (gameVersion < 365)) { // cd versions are compatible
1350 displayMessage(NULL, "This saved game was created by\n"
1351 "Beneath a Steel Sky v0.0%03d\n"
1352 "It cannot be loaded by this version (v0.0%3d)",
1353 gameVersion, SkyEngine::_systemVars.gameVersion);
1354 return RESTORE_FAILED;
1355 }
1356 }
1357 SkyEngine::_systemVars.systemFlags |= SF_GAME_RESTORED;
1358
1359 LODSW(srcPos, _skySound->_saveSounds[0]);
1360 LODSW(srcPos, _skySound->_saveSounds[1]);
1361 _skySound->restoreSfx();
1362
1363 uint32 music, mouseType, palette;
1364 LODSD(srcPos, music);
1365 LODSD(srcPos, _savedCharSet);
1366 LODSD(srcPos, mouseType);
1367 LODSD(srcPos, palette);
1368
1369 _skyLogic->parseSaveData((uint32 *)srcPos);
1370 srcPos += NUM_SKY_SCRIPTVARS * sizeof(uint32);
1371
1372 for (cnt = 0; cnt < 60; cnt++)
1373 LODSD(srcPos, reloadList[cnt]);
1374
1375 if (saveRev == SAVE_FILE_REVISION) {
1376 for (cnt = 0; cnt < _skyCompact->_numSaveIds; cnt++) {
1377 uint16 numElems;
1378 uint16 *rawCpt = (uint16 *)_skyCompact->fetchCptInfo(_skyCompact->_saveIds[cnt], &numElems, NULL, NULL);
1379 for (uint16 elemCnt = 0; elemCnt < numElems; elemCnt++)
1380 LODSW(srcPos, rawCpt[elemCnt]);
1381 }
1382 } else { // import old savegame revision
1383 for (cnt = 0; cnt < (uint32)(_skyCompact->_numSaveIds - 2); cnt++) {
1384 uint16 numElems;
1385 uint16 type;
1386 char name[128];
1387 uint16 *rawCpt = (uint16 *)_skyCompact->fetchCptInfo(_skyCompact->_saveIds[cnt], &numElems, &type, name);
1388 if (type == COMPACT) {
1389 importOldCompact((Compact *)rawCpt, &srcPos, numElems, type, name);
1390 } else if (type == ROUTEBUF) {
1391 assert(numElems == 32);
1392 for (uint32 elemCnt = 0; elemCnt < numElems; elemCnt++)
1393 LODSW(srcPos, rawCpt[elemCnt]);
1394 }
1395 }
1396 uint16 *rawCpt = (uint16 *)_skyCompact->fetchCpt(0xBF);
1397 for (cnt = 0; cnt < 3; cnt++)
1398 LODSW(srcPos, rawCpt[cnt]);
1399 rawCpt = (uint16 *)_skyCompact->fetchCpt(0xC2);
1400 for (cnt = 0; cnt < 13; cnt++)
1401 LODSW(srcPos, rawCpt[cnt]);
1402 }
1403
1404 // make sure all text compacts are off
1405 for (cnt = CPT_TEXT_1; cnt <= CPT_TEXT_11; cnt++)
1406 _skyCompact->fetchCpt(cnt)->status = 0;
1407
1408 if (srcPos - srcBuf != (int32)size)
1409 error("Restore failed! Savegame data = %lu bytes. Expected size: %d", (long)(srcPos-srcBuf), size);
1410
1411 _skyDisk->refreshFilesList(reloadList);
1412 SkyEngine::_systemVars.currentMusic = (uint16)music;
1413 if (!(SkyEngine::_systemVars.systemFlags & SF_MUS_OFF))
1414 _skyMusic->startMusic((uint16)music);
1415 _savedMouse = (uint16)mouseType;
1416 SkyEngine::_systemVars.currentPalette = palette; // will be set when doControlPanel ends
1417
1418 return GAME_RESTORED;
1419 }
1420
1421
restoreGameFromFile(bool autoSave)1422 uint16 Control::restoreGameFromFile(bool autoSave) {
1423 char fName[20];
1424 if (autoSave) {
1425 if (SkyEngine::isCDVersion())
1426 strcpy(fName, "SKY-VM-CD.ASD");
1427 else
1428 sprintf(fName, "SKY-VM%03d.ASD", SkyEngine::_systemVars.gameVersion);
1429 } else
1430 sprintf(fName,"SKY-VM.%03d", _selectedGame);
1431
1432 Common::InSaveFile *inf;
1433 inf = _saveFileMan->openForLoading(fName);
1434 if (inf == NULL) {
1435 return RESTORE_FAILED;
1436 }
1437
1438 uint32 infSize = inf->readUint32LE();
1439 if (infSize < 4) infSize = 4;
1440 uint8 *saveData = (uint8 *)malloc(infSize);
1441 *(uint32 *)saveData = TO_LE_32(infSize);
1442
1443 if (inf->read(saveData+4, infSize-4) != infSize-4) {
1444 displayMessage(NULL, "Can't read from file '%s'", fName);
1445 free(saveData);
1446 delete inf;
1447 return RESTORE_FAILED;
1448 }
1449
1450 uint16 res = parseSaveData(saveData);
1451 SkyEngine::_systemVars.pastIntro = true;
1452 delete inf;
1453 free(saveData);
1454 return res;
1455 }
1456
quickXRestore(uint16 slot)1457 uint16 Control::quickXRestore(uint16 slot) {
1458 uint16 result;
1459 if (!_controlPanel)
1460 initPanel();
1461 _mouseClicked = false;
1462
1463 _savedCharSet = _skyText->giveCurrentCharSet();
1464 _skyText->fnSetFont(2);
1465
1466 _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
1467 _system->updateScreen();
1468
1469 if (SkyEngine::_systemVars.gameVersion < 331)
1470 _skyScreen->setPalette(60509);
1471 else
1472 _skyScreen->setPalette(60510);
1473
1474 _savedMouse = _skyMouse->giveCurrentMouseType();
1475 _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
1476
1477 if (slot == 0)
1478 result = restoreGameFromFile(true);
1479 else {
1480 _selectedGame = slot - 1;
1481 result = restoreGameFromFile(false);
1482 }
1483 if (result == GAME_RESTORED) {
1484 memset(_skyScreen->giveCurrent(), 0, GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT);
1485 _skyScreen->showScreen(_skyScreen->giveCurrent());
1486 _skyScreen->forceRefresh();
1487 _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
1488 } else {
1489 memset(_screenBuf, 0, FULL_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
1490 _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
1491 _system->updateScreen();
1492 _skyScreen->showScreen(_skyScreen->giveCurrent());
1493 _skyScreen->setPalette(60111);
1494 }
1495 _skyMouse->spriteMouse(_savedMouse, 0, 0);
1496 _skyText->fnSetFont(_savedCharSet);
1497
1498 removePanel();
1499 return result;
1500 }
1501
restartGame()1502 void Control::restartGame() {
1503 if (SkyEngine::_systemVars.gameVersion <= 267)
1504 return; // no restart for floppy demo
1505
1506 uint8 *resetData = _skyCompact->createResetData((uint16)SkyEngine::_systemVars.gameVersion);
1507 parseSaveData((uint8 *)resetData);
1508 free(resetData);
1509 _skyScreen->forceRefresh();
1510
1511 memset(_skyScreen->giveCurrent(), 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
1512 _skyScreen->showScreen(_skyScreen->giveCurrent());
1513 _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
1514 _skyMouse->spriteMouse(_savedMouse, 0, 0);
1515 SkyEngine::_systemVars.pastIntro = true;
1516 }
1517
delay(unsigned int amount)1518 void Control::delay(unsigned int amount) {
1519 Common::Event event;
1520
1521 uint32 start = _system->getMillis();
1522 uint32 cur = start;
1523 _keyPressed.reset();
1524
1525 do {
1526 Common::EventManager *eventMan = _system->getEventManager();
1527 while (eventMan->pollEvent(event)) {
1528 switch (event.type) {
1529 case Common::EVENT_KEYDOWN:
1530 _keyPressed = event.kbd;
1531 break;
1532 case Common::EVENT_MOUSEMOVE:
1533 if (!(SkyEngine::_systemVars.systemFlags & SF_MOUSE_LOCKED))
1534 _skyMouse->mouseMoved(event.mouse.x, event.mouse.y);
1535 break;
1536 case Common::EVENT_LBUTTONDOWN:
1537 _mouseClicked = true;
1538 break;
1539 case Common::EVENT_LBUTTONUP:
1540 _mouseClicked = false;
1541 break;
1542 case Common::EVENT_RBUTTONDOWN:
1543 break;
1544 case Common::EVENT_WHEELUP:
1545 _mouseWheel = -1;
1546 break;
1547 case Common::EVENT_WHEELDOWN:
1548 _mouseWheel = 1;
1549 break;
1550 default:
1551 break;
1552 }
1553 }
1554
1555 uint this_delay = 20; // 1?
1556 #ifdef _WIN32_WCE
1557 this_delay = 10;
1558 #endif
1559 if (this_delay > amount)
1560 this_delay = amount;
1561
1562 if (this_delay > 0) _system->delayMillis(this_delay);
1563
1564 cur = _system->getMillis();
1565 } while (cur < start + amount);
1566 }
1567
showGameQuitMsg()1568 void Control::showGameQuitMsg() {
1569 _skyText->fnSetFont(0);
1570 uint8 *textBuf1 = (uint8 *)malloc(GAME_SCREEN_WIDTH * 14 + sizeof(DataFileHeader));
1571 uint8 *textBuf2 = (uint8 *)malloc(GAME_SCREEN_WIDTH * 14 + sizeof(DataFileHeader));
1572 uint8 *screenData;
1573 if (_skyScreen->sequenceRunning())
1574 _skyScreen->stopSequence();
1575
1576 screenData = _skyScreen->giveCurrent();
1577
1578 if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
1579 _skyText->displayText(_quitTexts[8 * 2 + 0], textBuf1, true, 320, 255);
1580 _skyText->displayText(_quitTexts[8 * 2 + 1], textBuf2, true, 320, 255);
1581 } else {
1582 _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 0], textBuf1, true, 320, 255);
1583 _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 1], textBuf2, true, 320, 255);
1584 }
1585 uint8 *curLine1 = textBuf1 + sizeof(DataFileHeader);
1586 uint8 *curLine2 = textBuf2 + sizeof(DataFileHeader);
1587 uint8 *targetLine = screenData + GAME_SCREEN_WIDTH * 80;
1588 for (uint8 cnty = 0; cnty < PAN_CHAR_HEIGHT; cnty++) {
1589 for (uint16 cntx = 0; cntx < GAME_SCREEN_WIDTH; cntx++) {
1590 if (curLine1[cntx])
1591 targetLine[cntx] = curLine1[cntx];
1592 if (curLine2[cntx])
1593 (targetLine + 24 * GAME_SCREEN_WIDTH)[cntx] = curLine2[cntx];
1594 }
1595 curLine1 += GAME_SCREEN_WIDTH;
1596 curLine2 += GAME_SCREEN_WIDTH;
1597 targetLine += GAME_SCREEN_WIDTH;
1598 }
1599 _skyScreen->halvePalette();
1600 _skyScreen->showScreen(screenData);
1601 free(textBuf1);
1602 free(textBuf2);
1603 }
1604
1605 char Control::_quitTexts[18][35] = {
1606 "Game over player one",
1607 "BE VIGILANT",
1608 "Das Spiel ist aus.",
1609 "SEI WACHSAM",
1610 "Game over joueur 1",
1611 "SOYEZ VIGILANTS",
1612 "Game over player one",
1613 "BE VIGILANT",
1614 "SPELET \x2Ar SLUT, Agent 1.",
1615 "VAR VAKSAM",
1616 "Game over giocatore 1",
1617 "SIATE VIGILANTI",
1618 "Fim de jogo para o jogador um",
1619 "BE VIGILANT",
1620 "Game over player one",
1621 "BE VIGILANT",
1622 "Irpa okohseha, irpok 1",
1623 "JYD\x96 JDITELEH"
1624 };
1625
1626 uint8 Control::_crossImg[594] = {
1627 0xFF, 0xFF, 0xFF, 0xFF, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1628 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0B, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x4D, 0x61,
1629 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1630 0x08, 0x4E, 0x53, 0x50, 0x4F, 0x0C, 0x4D, 0x4E, 0x51, 0x58, 0x58, 0x54, 0x4E, 0x08, 0xFF, 0xFF,
1631 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x54, 0x58, 0x50, 0x4E, 0xFF,
1632 0xFF, 0xFF, 0xFF, 0x50, 0x4E, 0x54, 0x58, 0x58, 0x54, 0x4E, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1633 0xFF, 0xFF, 0xFF, 0x61, 0x53, 0x58, 0x54, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1634 0x50, 0x4E, 0x55, 0x58, 0x58, 0x53, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x51, 0x58, 0x58,
1635 0x51, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x51, 0x58,
1636 0x59, 0x58, 0x51, 0x61, 0xFF, 0xFF, 0x61, 0x54, 0x58, 0x58, 0x4F, 0x52, 0xFF, 0xFF, 0xFF, 0xFF,
1637 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x55, 0x58, 0x58, 0x57, 0x4E,
1638 0x4F, 0x56, 0x58, 0x57, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1639 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x51, 0x58, 0x58, 0x58, 0x58, 0x58, 0x54, 0x4E, 0xFF,
1640 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1641 0xFF, 0xFF, 0x6A, 0x4F, 0x58, 0x58, 0x58, 0x58, 0x52, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1642 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x54, 0x58,
1643 0x58, 0x58, 0x58, 0x57, 0x53, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1644 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x09, 0x58, 0x58, 0x58, 0x57, 0x56, 0x58, 0x58, 0x58,
1645 0x57, 0x4F, 0x0A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1646 0x61, 0x55, 0x58, 0x58, 0x58, 0x58, 0x4E, 0x64, 0x57, 0x58, 0x58, 0x58, 0x58, 0x53, 0x61, 0xFF,
1647 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x57, 0x58, 0x58, 0x58, 0x58,
1648 0x50, 0xFF, 0xFF, 0x4E, 0x57, 0x58, 0x58, 0x58, 0x58, 0x56, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1649 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x58, 0x58, 0x58, 0x58, 0x58, 0x53, 0x09, 0xFF, 0xFF, 0xFF, 0x4E,
1650 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x57,
1651 0x58, 0x58, 0x58, 0x58, 0x56, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x58, 0x58, 0x58, 0x58,
1652 0x58, 0x57, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x55, 0x58, 0x58, 0x58, 0x58, 0x58, 0x4E,
1653 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x58, 0x58, 0x58, 0x58, 0x4E, 0xFF, 0xFF, 0xFF,
1654 0xFF, 0xFF, 0xFF, 0x06, 0x58, 0x58, 0x58, 0x58, 0x58, 0x52, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1655 0xFF, 0xFF, 0x0C, 0x52, 0x58, 0x58, 0x51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x56, 0x58,
1656 0x58, 0x58, 0x58, 0x56, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x56,
1657 0x58, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x4D, 0x4D, 0x51, 0x56, 0x58, 0x58, 0x50, 0xFF,
1658 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x54, 0x09, 0xFF, 0xFF, 0xFF,
1659 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x50, 0x54, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1660 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1661 0xFF, 0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1662 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0xFF,
1663 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF,
1664 0xFF, 0xFF
1665 };
1666
1667 } // End of namespace Sky
1668