scummvm/engines/lab/engine.cpp

1419 lines
40 KiB
C++
Raw Normal View History

2014-10-06 12:50:05 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/*
* This code is based on Labyrinth of Time code with assistance of
*
* Copyright (c) 1993 Terra Nova Development
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
*
*/
2014-12-25 18:13:52 +00:00
#include "lab/lab.h"
2014-10-06 12:50:05 +00:00
#include "lab/labfun.h"
2015-12-01 19:10:42 +00:00
#include "lab/anim.h"
#include "lab/image.h"
2014-10-06 12:50:05 +00:00
#include "lab/text.h"
2015-11-20 19:17:30 +00:00
#include "lab/intro.h"
2014-10-06 12:50:05 +00:00
#include "lab/parsefun.h"
#include "lab/interface.h"
#include "lab/resource.h"
2014-10-06 12:50:05 +00:00
namespace Lab {
2015-12-01 19:10:42 +00:00
extern bool stopsound, DoNotDrawMessage;
2014-10-06 12:50:05 +00:00
/* Global parser data */
2015-11-28 01:27:02 +00:00
extern RoomData *_rooms;
2014-10-06 12:50:05 +00:00
extern InventoryData *Inventory;
2015-11-30 00:42:12 +00:00
extern uint16 NumInv, ManyRooms, HighestCondition, Direction;
2014-10-06 12:50:05 +00:00
bool ispal = false, noupdatediff = false, MainDisplay = true, QuitLab = false;
2014-10-06 12:50:05 +00:00
#define BUFFERSIZE 850000L
2014-10-06 12:50:05 +00:00
/* LAB: Labyrinth specific code for the special puzzles */
#define SPECIALLOCK 100
#define SPECIALBRICK 101
#define SPECIALBRICKNOMOUSE 102
#define MAPNUM 28
#define JOURNALNUM 9
#define WESTPAPERNUM 18
#define NOTESNUM 12
#define WHISKEYNUM 25
#define PITHHELMETNUM 7
#define HELMETNUM 1
#define LAMPNUM 27
#define LAMPON 151
#define BELTNUM 3
#define BELTGLOW 70
#define USEDHELMET 184
#define QUARTERNUM 30
#define MUSEUMMONITOR 71
#define GRAMAPHONEMONITOR 72
#define UNICYCLEMONITOR 73
#define STATUEMONITOR 74
#define TALISMANMONITOR 75
#define LUTEMONITOR 76
#define CLOCKMONITOR 77
#define WINDOWMONITOR 78
#define BELTMONITOR 79
#define LIBRARYMONITOR 80
#define TERMINALMONITOR 81
#define LEVERSMONITOR 82
static char initcolors[] = { '\x00', '\x00', '\x00', '\x30',
'\x30', '\x30', '\x10', '\x10',
'\x10', '\x14', '\x14', '\x14',
'\x20', '\x20', '\x20', '\x24',
'\x24', '\x24', '\x2c', '\x2c',
'\x2c', '\x08', '\x08', '\x08'};
/******************************************************************************/
/* Draws the control panel display. */
/******************************************************************************/
2015-11-24 22:59:30 +00:00
void LabEngine::drawPanel() {
_event->mouseHide();
2014-10-06 12:50:05 +00:00
setAPen(3); /* Clear Area */
rectFill(0, VGAScaleY(149) + SVGACord(2), VGAScaleX(319), VGAScaleY(199));
setAPen(0); /* First Line */
drawHLine(0, VGAScaleY(149) + SVGACord(2), VGAScaleX(319));
setAPen(5); /* Second Line */
drawHLine(0, VGAScaleY(149) + 1 + SVGACord(2), VGAScaleX(319));
/* Gadget Separators */
2014-10-06 12:50:05 +00:00
setAPen(0);
drawHLine(0, VGAScaleY(170), VGAScaleX(319)); /* First black line to separate buttons */
2014-10-06 12:50:05 +00:00
if (!_alternate) {
2014-10-06 12:50:05 +00:00
setAPen(4);
drawHLine(0, VGAScaleY(170) + 1, VGAScaleX(319)); /* The horizontal lines under the black one */
drawGadgetList(_moveGadgetList);
2014-10-06 12:50:05 +00:00
} else {
2015-11-29 22:34:35 +00:00
if (getPlatform() != Common::kPlatformWindows) {
2014-12-27 13:18:40 +00:00
drawVLine(VGAScaleX(124), VGAScaleY(170) + 1, VGAScaleY(199)); /* Vertical Black lines */
drawVLine(VGAScaleX(194), VGAScaleY(170) + 1, VGAScaleY(199));
} else {
drawVLine(VGAScaleX(90), VGAScaleY(170) + 1, VGAScaleY(199)); /* Vertical Black lines */
drawVLine(VGAScaleX(160), VGAScaleY(170) + 1, VGAScaleY(199));
drawVLine(VGAScaleX(230), VGAScaleY(170) + 1, VGAScaleY(199));
}
2014-10-06 12:50:05 +00:00
setAPen(4);
drawHLine(0, VGAScaleY(170) + 1, VGAScaleX(122)); /* The horizontal lines under the black one */
drawHLine(VGAScaleX(126), VGAScaleY(170) + 1, VGAScaleX(192));
drawHLine(VGAScaleX(196), VGAScaleY(170) + 1, VGAScaleX(319));
drawVLine(VGAScaleX(1), VGAScaleY(170) + 2, VGAScaleY(198)); /* The vertical high light lines */
2015-11-29 22:34:35 +00:00
if (getPlatform() != Common::kPlatformWindows) {
2014-12-27 13:18:40 +00:00
drawVLine(VGAScaleX(126), VGAScaleY(170) + 2, VGAScaleY(198));
drawVLine(VGAScaleX(196), VGAScaleY(170) + 2, VGAScaleY(198));
} else {
drawVLine(VGAScaleX(92), VGAScaleY(170) + 2, VGAScaleY(198));
drawVLine(VGAScaleX(162), VGAScaleY(170) + 2, VGAScaleY(198));
drawVLine(VGAScaleX(232), VGAScaleY(170) + 2, VGAScaleY(198));
}
2014-10-06 12:50:05 +00:00
drawGadgetList(_invGadgetList);
2014-10-06 12:50:05 +00:00
}
_event->mouseShow();
2014-10-06 12:50:05 +00:00
}
/******************************************************************************/
/* Draws the message for the room. */
/******************************************************************************/
void LabEngine::drawRoomMessage(uint16 curInv, CloseDataPtr closePtr) {
2015-12-01 09:35:31 +00:00
if (_lastTooLong) {
_lastTooLong = false;
2014-10-06 12:50:05 +00:00
return;
}
if (_alternate) {
if ((curInv <= NumInv) && _conditions->in(curInv) && Inventory[curInv].BInvName) {
if ((curInv == LAMPNUM) && _conditions->in(LAMPON)) /* LAB: Labyrinth specific */
drawStaticMessage(kTextLampOn);
else if (Inventory[curInv].Many > 1) {
Common::String roomMessage = Common::String(Inventory[curInv].name) + " (" + Common::String::format("%d", Inventory[curInv].Many) + ")";
drawMessage(roomMessage.c_str());
2014-10-06 12:50:05 +00:00
} else
drawMessage(Inventory[curInv].name);
2014-10-06 12:50:05 +00:00
}
} else
drawDirection(closePtr);
2014-10-06 12:50:05 +00:00
2015-12-01 09:35:31 +00:00
_lastTooLong = _lastMessageLong;
2014-10-06 12:50:05 +00:00
}
/******************************************************************************/
/* Sets up the Labyrinth screens, and opens up the initial windows. */
/******************************************************************************/
2015-11-24 22:59:30 +00:00
bool LabEngine::setUpScreens() {
2015-11-29 23:12:01 +00:00
if (!createScreen(_isHiRes))
2014-10-06 12:50:05 +00:00
return false;
2015-12-03 13:06:45 +00:00
Common::File *controlFile = g_lab->_resource->openDataFile("P:Control");
for (uint16 i = 0; i < 20; i++)
2015-12-03 13:06:45 +00:00
_moveImages[i] = new Image(controlFile);
delete controlFile;
2014-10-06 12:50:05 +00:00
/* Creates the gadgets for the movement control panel */
uint16 y = VGAScaleY(173) - SVGACord(2);
2014-12-27 13:18:40 +00:00
2015-11-29 22:34:35 +00:00
if (getPlatform() == Common::kPlatformWindows) {
_moveGadgetList = createButton(1, y, 0, 't', _moveImages[0], _moveImages[1]);
Gadget *curGadget = _moveGadgetList;
curGadget->NextGadget = createButton(33, y, 1, 'm', _moveImages[2], _moveImages[3]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(65, y, 2, 'o', _moveImages[4], _moveImages[5]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(97, y, 3, 'c', _moveImages[6], _moveImages[7]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(129, y, 4, 'l', _moveImages[8], _moveImages[9]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(161, y, 5, 'i', _moveImages[12], _moveImages[13]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(193, y, 6, VKEY_LTARROW, _moveImages[14], _moveImages[15]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(225, y, 7, VKEY_UPARROW, _moveImages[16], _moveImages[17]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(257, y, 8, VKEY_RTARROW, _moveImages[18], _moveImages[19]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(289, y, 9, 'p', _moveImages[10], _moveImages[11]);
2014-12-27 13:18:40 +00:00
} else {
_moveGadgetList = createButton(1, y, 0, 0, _moveImages[0], _moveImages[1]);
Gadget *curGadget = _moveGadgetList;
curGadget->NextGadget = createButton(33, y, 1, 0, _moveImages[2], _moveImages[3]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(65, y, 2, 0, _moveImages[4], _moveImages[5]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(97, y, 3, 0, _moveImages[6], _moveImages[7]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(129, y, 4, 0, _moveImages[8], _moveImages[9]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(161, y, 5, 0, _moveImages[12], _moveImages[13]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(193, y, 6, 0, _moveImages[14], _moveImages[15]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(225, y, 7, 0, _moveImages[16], _moveImages[17]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(257, y, 8, 0, _moveImages[18], _moveImages[19]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(289, y, 9, 0, _moveImages[10], _moveImages[11]);
2014-12-27 13:18:40 +00:00
}
2014-10-06 12:50:05 +00:00
2015-12-03 13:06:45 +00:00
Common::File *invFile = g_lab->_resource->openDataFile("P:Inv");
2014-12-27 13:18:40 +00:00
2015-11-29 22:34:35 +00:00
if (getPlatform() == Common::kPlatformWindows) {
for (uint16 imgIdx = 0; imgIdx < 10; imgIdx++)
2015-12-03 13:06:45 +00:00
_invImages[imgIdx] = new Image(invFile);
_invGadgetList = createButton(24, y, 0, 'm', _invImages[0], _invImages[1]);
Gadget *curGadget = _invGadgetList;
curGadget->NextGadget = createButton(56, y, 1, 'g', _invImages[2], _invImages[3]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(94, y, 2, 'u', _invImages[4], _invImages[5]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(126, y, 3, 'l', _moveImages[8], _moveImages[9]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(164, y, 4, VKEY_LTARROW, _moveImages[14], _moveImages[15]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(196, y, 5, VKEY_RTARROW, _moveImages[18], _moveImages[19]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(234, y, 6, 'b', _invImages[6], _invImages[7]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(266, y, 7, 'f', _invImages[8], _invImages[9]);
curGadget = curGadget->NextGadget;
2014-12-27 13:18:40 +00:00
} else {
for (uint16 imgIdx = 0; imgIdx < 6; imgIdx++)
2015-12-03 13:06:45 +00:00
_invImages[imgIdx] = new Image(invFile);
_invGadgetList = createButton(58, y, 0, 0, _invImages[0], _invImages[1]);
Gadget *curGadget = _invGadgetList;
curGadget->NextGadget = createButton(90, y, 1, 0, _invImages[2], _invImages[3]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(128, y, 2, 0, _invImages[4], _invImages[5]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(160, y, 3, 0, _moveImages[8], _moveImages[9]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(198, y, 4, 0, _moveImages[14], _moveImages[15]);
curGadget = curGadget->NextGadget;
curGadget->NextGadget = createButton(230, y, 5, 0, _moveImages[18], _moveImages[19]);
curGadget = curGadget->NextGadget;
2014-12-27 13:18:40 +00:00
}
2014-10-06 12:50:05 +00:00
2015-12-03 13:06:45 +00:00
delete invFile;
2014-10-06 12:50:05 +00:00
return true;
}
2015-12-02 19:32:06 +00:00
void LabEngine::freeScreens() {
for (uint16 i = 0; i < 20; i++)
delete _moveImages[i];
if (getPlatform() == Common::kPlatformWindows) {
for (uint16 imgIdx = 0; imgIdx < 10; imgIdx++)
delete _invImages[imgIdx];
} else {
for (uint16 imgIdx = 0; imgIdx < 6; imgIdx++)
delete _invImages[imgIdx];
}
}
2014-10-06 12:50:05 +00:00
/******************************************************************************/
/* Permanently flips the imagery of a gadget. */
2014-10-06 12:50:05 +00:00
/******************************************************************************/
void LabEngine::perFlipGadget(uint16 gadgetId) {
Gadget *topGadget = _moveGadgetList;
2014-10-06 12:50:05 +00:00
while (topGadget) {
if (topGadget->GadgetID == gadgetId) {
Image *tmpImage = topGadget->_image;
topGadget->_image = topGadget->_altImage;
topGadget->_altImage = tmpImage;
2014-10-06 12:50:05 +00:00
if (!_alternate) {
_event->mouseHide();
topGadget->_image->drawImage(topGadget->x, topGadget->y);
_event->mouseShow();
2014-10-06 12:50:05 +00:00
}
return;
} else
topGadget = topGadget->NextGadget;
2014-10-06 12:50:05 +00:00
}
}
/******************************************************************************/
/* Eats all the available messages. */
/******************************************************************************/
void LabEngine::eatMessages() {
IntuiMessage *msg;
2014-10-06 12:50:05 +00:00
do {
msg = getMsg();
} while (msg);
2014-10-06 12:50:05 +00:00
return;
}
/******************************************************************************/
/* Checks whether the close up is one of the special case closeups. */
/******************************************************************************/
bool LabEngine::doCloseUp(CloseDataPtr closePtr) {
if (closePtr == NULL)
2014-10-06 12:50:05 +00:00
return false;
2014-12-27 13:18:40 +00:00
int monltmargin, monrtmargin, montopmargin, lutertmargin;
2015-11-29 22:34:35 +00:00
if (getPlatform() != Common::kPlatformWindows) {
2014-12-27 13:18:40 +00:00
monltmargin = 0;
monrtmargin = 319;
montopmargin = 0;
lutertmargin = 124;
} else {
monltmargin = 2;
monrtmargin = 317;
montopmargin = 2;
lutertmargin = 128;
}
switch (closePtr->CloseUpType) {
case MUSEUMMONITOR:
case LIBRARYMONITOR:
case WINDOWMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, false, monltmargin, montopmargin, monrtmargin, 165);
break;
case GRAMAPHONEMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, false, monltmargin, montopmargin, 171, 165);
break;
case UNICYCLEMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, false, 100, montopmargin, monrtmargin, 165);
break;
case STATUEMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, false, 117, montopmargin, monrtmargin, 165);
break;
case TALISMANMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, false, monltmargin, montopmargin, 184, 165);
break;
case LUTEMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, false, monltmargin, montopmargin, lutertmargin, 165);
break;
case CLOCKMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, false, monltmargin, montopmargin, 206, 165);
break;
case TERMINALMONITOR:
doMonitor(closePtr->GraphicName, closePtr->Message, true, monltmargin, montopmargin, monrtmargin, 165);
break;
default:
2014-10-06 12:50:05 +00:00
return false;
}
2014-10-06 12:50:05 +00:00
_curFileName = " ";
2014-10-06 12:50:05 +00:00
drawPanel();
return true;
}
/******************************************************************************/
/* Gets the current inventory name. */
/******************************************************************************/
2015-12-02 19:45:22 +00:00
const char *LabEngine::getInvName(uint16 CurInv) {
2014-10-06 12:50:05 +00:00
if (MainDisplay)
return Inventory[CurInv].BInvName;
2015-12-02 19:45:22 +00:00
if ((CurInv == LAMPNUM) && _conditions->in(LAMPON))
2014-10-06 12:50:05 +00:00
return "P:Mines/120";
if ((CurInv == BELTNUM) && g_lab->_conditions->in(BELTGLOW))
2014-10-06 12:50:05 +00:00
return "P:Future/BeltGlow";
if (CurInv == WESTPAPERNUM) {
g_lab->_curFileName = Inventory[CurInv].BInvName;
2015-12-01 23:34:51 +00:00
g_lab->_anim->_noPalChange = true;
readPict(g_lab->_curFileName, false);
2015-12-01 23:34:51 +00:00
g_lab->_anim->_noPalChange = false;
2014-10-06 12:50:05 +00:00
doWestPaper();
} else if (CurInv == NOTESNUM) {
g_lab->_curFileName = Inventory[CurInv].BInvName;
2015-12-01 23:34:51 +00:00
g_lab->_anim->_noPalChange = true;
readPict(g_lab->_curFileName, false);
2015-12-01 23:34:51 +00:00
g_lab->_anim->_noPalChange = false;
2014-10-06 12:50:05 +00:00
doNotes();
}
return Inventory[CurInv].BInvName;
}
/******************************************************************************/
/* Turns the interface off. */
/******************************************************************************/
void LabEngine::interfaceOff() {
if (!_interfaceOff) {
_event->attachGadgetList(NULL);
_event->mouseHide();
_interfaceOff = true;
2014-10-06 12:50:05 +00:00
}
}
/******************************************************************************/
/* Turns the interface on. */
/******************************************************************************/
void LabEngine::interfaceOn() {
if (_interfaceOff) {
_interfaceOff = false;
_event->mouseShow();
2014-10-06 12:50:05 +00:00
}
2015-12-03 10:01:50 +00:00
if (_longWinInFront)
_event->attachGadgetList(NULL);
else if (_alternate)
_event->attachGadgetList(_invGadgetList);
2014-10-06 12:50:05 +00:00
else
_event->attachGadgetList(_moveGadgetList);
2014-10-06 12:50:05 +00:00
}
/******************************************************************************/
/* If the user hits the "Use" gadget; things that can get used on themselves. */
/******************************************************************************/
2015-11-24 22:59:30 +00:00
bool LabEngine::doUse(uint16 CurInv) {
2014-10-06 12:50:05 +00:00
if (CurInv == MAPNUM) { /* LAB: Labyrinth specific */
drawStaticMessage(kTextUseMap);
2014-10-06 12:50:05 +00:00
interfaceOff();
2015-12-01 19:10:42 +00:00
_anim->stopDiff();
_curFileName = " ";
2015-12-03 10:10:58 +00:00
_cptr = NULL;
2015-11-30 00:42:12 +00:00
doMap(_roomNum);
2015-11-30 19:07:23 +00:00
setPalette(initcolors, 8);
2014-10-06 12:50:05 +00:00
drawMessage(NULL);
drawPanel();
2015-11-24 22:59:30 +00:00
} else if (CurInv == JOURNALNUM) { /* LAB: Labyrinth specific */
drawStaticMessage(kTextUseJournal);
2014-10-06 12:50:05 +00:00
interfaceOff();
2015-12-01 19:10:42 +00:00
_anim->stopDiff();
_curFileName = " ";
2015-12-03 10:10:58 +00:00
_cptr = NULL;
2014-12-25 18:13:52 +00:00
doJournal();
2014-10-06 12:50:05 +00:00
drawPanel();
drawMessage(NULL);
2015-11-24 22:59:30 +00:00
} else if (CurInv == LAMPNUM) { /* LAB: Labyrinth specific */
2014-10-06 12:50:05 +00:00
interfaceOff();
2015-11-24 22:59:30 +00:00
if (_conditions->in(LAMPON)) {
drawStaticMessage(kTextTurnLampOff);
2015-11-24 22:59:30 +00:00
_conditions->exclElement(LAMPON);
2014-10-06 12:50:05 +00:00
} else {
drawStaticMessage(kTextTurnLampOn);
2015-11-24 22:59:30 +00:00
_conditions->inclElement(LAMPON);
2014-10-06 12:50:05 +00:00
}
2015-12-01 23:34:51 +00:00
_anim->_doBlack = false;
_anim->_waitForEffect = true;
2014-10-06 12:50:05 +00:00
readPict("Music:Click", true);
2015-12-01 23:34:51 +00:00
_anim->_waitForEffect = false;
2014-10-06 12:50:05 +00:00
2015-12-01 23:34:51 +00:00
_anim->_doBlack = false;
_nextFileName = getInvName(CurInv);
2015-11-24 22:59:30 +00:00
} else if (CurInv == BELTNUM) { /* LAB: Labyrinth specific */
if (!_conditions->in(BELTGLOW))
_conditions->inclElement(BELTGLOW);
2014-10-06 12:50:05 +00:00
2015-12-01 23:34:51 +00:00
_anim->_doBlack = false;
_nextFileName = getInvName(CurInv);
2015-11-24 22:59:30 +00:00
} else if (CurInv == WHISKEYNUM) { /* LAB: Labyrinth specific */
_conditions->inclElement(USEDHELMET);
drawStaticMessage(kTextUseWhiskey);
2015-11-24 22:59:30 +00:00
} else if (CurInv == PITHHELMETNUM) { /* LAB: Labyrinth specific */
_conditions->inclElement(USEDHELMET);
drawStaticMessage(kTextUsePith);
2015-11-24 22:59:30 +00:00
} else if (CurInv == HELMETNUM) { /* LAB: Labyrinth specific */
_conditions->inclElement(USEDHELMET);
drawStaticMessage(kTextUseHelmet);
2015-11-24 22:59:30 +00:00
} else
2014-10-06 12:50:05 +00:00
return false;
return true;
}
/******************************************************************************/
/* Decrements the current inventory number. */
/******************************************************************************/
void LabEngine::decIncInv(uint16 *CurInv, bool dec) {
2014-10-06 12:50:05 +00:00
interfaceOff();
if (dec)
(*CurInv)--;
else
(*CurInv)++;
while (*CurInv && (*CurInv <= NumInv)) {
2015-11-29 22:34:35 +00:00
if (_conditions->in(*CurInv) && Inventory[*CurInv].BInvName) {
_nextFileName = getInvName(*CurInv);
2014-10-06 12:50:05 +00:00
break;
}
if (dec)
(*CurInv)--;
else
(*CurInv)++;
}
if ((*CurInv == 0) || (*CurInv > NumInv)) {
if (dec)
*CurInv = NumInv;
else
*CurInv = 1;
while (*CurInv && (*CurInv <= NumInv)) {
2015-11-29 22:34:35 +00:00
if (_conditions->in(*CurInv) && Inventory[*CurInv].BInvName) {
_nextFileName = getInvName(*CurInv);
2014-10-06 12:50:05 +00:00
break;
}
if (dec)
(*CurInv)--;
else
(*CurInv)++;
}
}
}
/******************************************************************************/
/* The main game loop */
2014-10-06 12:50:05 +00:00
/******************************************************************************/
2015-11-24 22:59:30 +00:00
void LabEngine::mainGameLoop() {
2015-11-30 12:09:36 +00:00
uint16 actionMode = 4;
uint16 curInv = MAPNUM;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
bool forceDraw = false, GotMessage = true;
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
setPalette(initcolors, 8);
2014-10-06 12:50:05 +00:00
2015-12-03 10:10:58 +00:00
_cptr = NULL;
2015-11-30 00:42:12 +00:00
_roomNum = 1;
2014-10-06 12:50:05 +00:00
Direction = NORTH;
_resource->readRoomData("LAB:Doors");
_resource->readInventory("LAB:Inventor");
2014-10-06 12:50:05 +00:00
if (!(_conditions = new LargeSet(HighestCondition + 1, this)))
2014-10-06 12:50:05 +00:00
return;
if (!(_roomsFound = new LargeSet(ManyRooms + 1, this)))
2014-10-06 12:50:05 +00:00
return;
2015-11-29 22:34:35 +00:00
_conditions->readInitialConditions("LAB:Conditio");
2014-10-06 12:50:05 +00:00
2015-12-03 10:01:50 +00:00
_longWinInFront = false;
2014-10-06 12:50:05 +00:00
drawPanel();
2015-11-30 12:09:36 +00:00
perFlipGadget(actionMode);
2014-10-06 12:50:05 +00:00
/* Set up initial picture. */
while (1) {
_event->processInput(true);
2014-10-06 12:50:05 +00:00
if (GotMessage) {
2015-02-25 23:15:54 +00:00
if (QuitLab || g_engine->shouldQuit()) {
2015-12-01 19:10:42 +00:00
_anim->stopDiff();
2014-10-06 12:50:05 +00:00
break;
}
_music->resumeBackMusic();
2014-10-06 12:50:05 +00:00
/* Sees what kind of close up we're in and does the appropriate stuff, if any. */
2015-12-03 10:10:58 +00:00
if (doCloseUp(_cptr)) {
_cptr = NULL;
2014-12-27 13:18:40 +00:00
2014-10-06 12:50:05 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-10-06 12:50:05 +00:00
}
/* Sets the current picture properly on the screen */
if (MainDisplay)
2015-12-03 10:10:58 +00:00
_nextFileName = getPictName(&_cptr);
2014-10-06 12:50:05 +00:00
if (noupdatediff) {
2015-11-30 00:42:12 +00:00
_roomsFound->inclElement(_roomNum); /* Potentially entered another room */
forceDraw |= (strcmp(_nextFileName, _curFileName) != 0);
2014-10-06 12:50:05 +00:00
noupdatediff = false;
_curFileName = _nextFileName;
} else if (strcmp(_nextFileName, _curFileName) != 0) {
2014-10-06 12:50:05 +00:00
interfaceOff();
2015-11-30 00:42:12 +00:00
_roomsFound->inclElement(_roomNum); /* Potentially entered another room */
_curFileName = _nextFileName;
2014-10-06 12:50:05 +00:00
2015-12-03 10:10:58 +00:00
if (_cptr) {
if ((_cptr->CloseUpType == SPECIALLOCK) && MainDisplay) /* LAB: Labyrinth specific code */
showCombination(_curFileName);
2015-12-03 10:10:58 +00:00
else if (((_cptr->CloseUpType == SPECIALBRICK) ||
(_cptr->CloseUpType == SPECIALBRICKNOMOUSE)) &&
2014-10-06 12:50:05 +00:00
MainDisplay) /* LAB: Labyrinth specific code */
2015-12-03 10:10:58 +00:00
showTile(_curFileName, (bool)(_cptr->CloseUpType == SPECIALBRICKNOMOUSE));
2014-10-06 12:50:05 +00:00
else
readPict(_curFileName, false);
2014-10-06 12:50:05 +00:00
} else
readPict(_curFileName, false);
2014-10-06 12:50:05 +00:00
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2015-11-30 12:09:36 +00:00
forceDraw = false;
2014-10-06 12:50:05 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-10-06 12:50:05 +00:00
if (!_followingCrumbs)
2014-10-06 12:50:05 +00:00
eatMessages();
}
2015-11-30 12:09:36 +00:00
if (forceDraw) {
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2015-11-30 12:09:36 +00:00
forceDraw = false;
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-10-06 12:50:05 +00:00
}
}
_music->updateMusic(); /* Make sure we check the music at least after every message */
2014-10-06 12:50:05 +00:00
interfaceOn();
IntuiMessage *curMsg = getMsg();
2014-10-06 12:50:05 +00:00
if (curMsg == NULL) { /* Does music load and next animation frame when you've run out of messages */
2014-10-06 12:50:05 +00:00
GotMessage = false;
_music->checkRoomMusic();
_music->updateMusic();
2015-12-01 19:10:42 +00:00
_anim->diffNextFrame();
2014-10-06 12:50:05 +00:00
if (_followingCrumbs) {
2014-10-06 12:50:05 +00:00
int result = followCrumbs();
if (result != 0) {
2015-11-30 12:09:36 +00:00
uint16 code = 0;
if (result == VKEY_UPARROW)
2015-11-30 12:09:36 +00:00
code = 7;
else if (result == VKEY_LTARROW)
2015-11-30 12:09:36 +00:00
code = 6;
else if (result == VKEY_RTARROW)
2015-11-30 12:09:36 +00:00
code = 8;
2014-10-06 12:50:05 +00:00
GotMessage = true;
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
if (!from_crumbs(GADGETUP, code, 0, _event->updateAndGetMousePos(), curInv, curMsg, forceDraw, code, actionMode))
2015-11-30 12:09:36 +00:00
break;
2014-10-06 12:50:05 +00:00
}
}
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-10-06 12:50:05 +00:00
} else {
GotMessage = true;
2015-11-30 12:09:36 +00:00
Common::Point curPos;
curPos.x = curMsg->mouseX;
curPos.y = curMsg->mouseY;
2014-10-06 12:50:05 +00:00
_followingCrumbs = false;
2015-11-30 12:09:36 +00:00
if (!from_crumbs(curMsg->msgClass, curMsg->code, curMsg->qualifier, curPos, curInv, curMsg, forceDraw, curMsg->gadgetID, actionMode))
break;
}
}
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
delete _conditions;
delete _roomsFound;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (_rooms) {
free(_rooms);
_rooms = nullptr;
}
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (Inventory) {
for (int i = 1; i <= NumInv; i++) {
if (Inventory[i].name)
free(Inventory[i].name);
if (Inventory[i].BInvName)
free(Inventory[i].BInvName);
}
free(Inventory);
}
}
bool LabEngine::from_crumbs(uint32 tmpClass, uint16 code, uint16 Qualifier, Common::Point tmpPos, uint16 &curInv, IntuiMessage *curMsg, bool &forceDraw, uint16 gadgetId, uint16 &actionMode) {
uint32 msgClass = tmpClass;
Common::Point curPos = tmpPos;
uint16 OldRoomNum, OldDirection = 0;
uint16 LastInv = MAPNUM, Old;
2015-12-03 10:02:58 +00:00
CloseDataPtr oldcptr, tempcptr, hcptr = NULL;
2015-11-30 12:09:36 +00:00
ViewData *VPtr;
bool doit;
uint16 NewDir;
2015-12-01 23:34:51 +00:00
_anim->_doBlack = false;
2015-11-30 12:09:36 +00:00
2015-12-03 10:01:50 +00:00
if ((msgClass == RAWKEY) && (!_longWinInFront)) {
2015-11-30 12:09:36 +00:00
if (code == 13) { /* The return key */
msgClass = MOUSEBUTTONS;
Qualifier = IEQUALIFIER_LEFTBUTTON;
curPos = _event->getMousePos();
} else if (getPlatform() == Common::kPlatformWindows &&
(code == 'b' || code == 'B')) { /* Start bread crumbs */
_breadCrumbs[0]._roomNum = 0;
_numCrumbs = 0;
_droppingCrumbs = true;
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (code == 'f' || code == 'F' ||
code == 'r' || code == 'R') { /* Follow bread crumbs */
if (_droppingCrumbs) {
if (_numCrumbs > 0) {
_followingCrumbs = true;
_followCrumbsFast = (code == 'r' || code == 'R');
_isCrumbTurning = false;
_isCrumbWaiting = false;
getTime(&_crumbSecs, &_crumbMicros);
if (_alternate) {
2015-11-30 12:09:36 +00:00
eatMessages();
_alternate = false;
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
DoNotDrawMessage = false;
MainDisplay = true;
interfaceOn(); /* Sets the correct gadget list */
drawPanel();
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-10-06 12:50:05 +00:00
}
2015-11-30 12:09:36 +00:00
} else {
_breadCrumbs[0]._roomNum = 0;
_droppingCrumbs = false;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
// Need to hide indicator!!!!
mayShowCrumbIndicatorOff();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
}
}
} else if ((code == 315) || (code == 'x') || (code == 'X')
|| (code == 'q') || (code == 'Q')) { /* Quit? */
DoNotDrawMessage = false;
drawMessage("Do you want to quit? (Y/N)");
doit = false;
eatMessages();
interfaceOff();
while (1) {
_music->updateMusic(); /* Make sure we check the music at least after every message */
curMsg = getMsg();
if (curMsg == NULL) { /* Does music load and next animation frame when you've run out of messages */
_music->updateMusic();
2015-12-01 19:10:42 +00:00
_anim->diffNextFrame();
2015-11-30 12:09:36 +00:00
} else {
if (curMsg->msgClass == RAWKEY) {
if ((curMsg->code == 'Y') || (curMsg->code == 'y') || (curMsg->code == 'Q') || (curMsg->code == 'q')) {
doit = true;
break;
} else if (curMsg->code < 128) {
break;
}
} else if (curMsg->msgClass == MOUSEBUTTONS) {
2014-10-06 12:50:05 +00:00
break;
}
}
2015-11-30 12:09:36 +00:00
}
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (doit) {
2015-12-01 19:10:42 +00:00
_anim->stopDiff();
2015-11-30 12:09:36 +00:00
return false;
} else {
forceDraw = true;
interfaceOn();
2014-10-06 12:50:05 +00:00
}
2015-11-30 12:09:36 +00:00
} else if (code == 9) { /* TAB key */
msgClass = DELTAMOVE;
} else if (code == 27) { /* ESC key */
2015-12-03 10:10:58 +00:00
_cptr = NULL;
2015-11-30 12:09:36 +00:00
}
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
eatMessages();
}
2014-10-06 12:50:05 +00:00
2015-12-03 10:01:50 +00:00
if (_longWinInFront) {
2015-11-30 12:09:36 +00:00
if ((msgClass == RAWKEY) ||
((msgClass == MOUSEBUTTONS) &&
((IEQUALIFIER_LEFTBUTTON & Qualifier) ||
(IEQUALIFIER_RBUTTON & Qualifier)))) {
2015-12-03 10:01:50 +00:00
_longWinInFront = false;
2015-11-30 12:09:36 +00:00
DoNotDrawMessage = false;
drawPanel();
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
}
} else if ((msgClass == GADGETUP) && !_alternate) {
2015-11-30 12:09:36 +00:00
if (gadgetId <= 5) {
2015-12-03 10:10:58 +00:00
if ((actionMode == 4) && (gadgetId == 4) && (_cptr != NULL)) {
doMainView(&_cptr);
2014-10-06 12:50:05 +00:00
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-12-03 10:02:58 +00:00
hcptr = NULL;
2015-12-03 10:10:58 +00:00
_cptr = NULL;
2015-11-30 12:09:36 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (gadgetId == 5) {
eatMessages();
_alternate = true;
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
DoNotDrawMessage = false;
interfaceOn(); /* Sets the correct gadget list */
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
MainDisplay = false;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (LastInv && _conditions->in(LastInv)) {
curInv = LastInv;
_nextFileName = getInvName(curInv);
2015-11-30 12:09:36 +00:00
} else
decIncInv(&curInv, false);
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
drawPanel();
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2014-12-27 13:18:40 +00:00
2015-11-30 12:09:36 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else {
Old = actionMode;
actionMode = gadgetId;
if (Old < 5)
perFlipGadget(Old);
perFlipGadget(actionMode);
if (gadgetId == 0)
drawStaticMessage(kTextTakeWhat);
else if (gadgetId == 1)
drawStaticMessage(kTextMoveWhat);
else if (gadgetId == 2)
drawStaticMessage(kTextOpenWhat);
else if (gadgetId == 3)
drawStaticMessage(kTextCloseWhat);
else if (gadgetId == 4)
drawStaticMessage(kTextLookWhat);
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
}
} else if (gadgetId == 9) {
doUse(MAPNUM);
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (gadgetId >= 6) { /* Arrow Gadgets */
2015-12-03 10:10:58 +00:00
_cptr = NULL;
2015-12-03 10:02:58 +00:00
hcptr = NULL;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if ((gadgetId == 6) || (gadgetId == 8)) {
if (gadgetId == 6)
drawStaticMessage(kTextTurnLeft);
else
drawStaticMessage(kTextTurnRight);
2014-10-06 12:50:05 +00:00
_curFileName = " ";
2014-12-27 13:18:40 +00:00
2015-11-30 12:09:36 +00:00
OldDirection = Direction;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
NewDir = Direction;
processArrow(&NewDir, gadgetId - 6);
2015-12-03 10:10:58 +00:00
doTurn(Direction, NewDir, &_cptr);
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
Direction = NewDir;
forceDraw = true;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (gadgetId == 7) {
OldRoomNum = _roomNum;
2014-12-27 13:18:40 +00:00
2015-12-03 10:10:58 +00:00
if (doGoForward(&_cptr)) {
2015-11-30 12:09:36 +00:00
if (OldRoomNum == _roomNum)
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
} else {
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
processArrow(&Direction, gadgetId - 6);
2014-12-27 13:18:40 +00:00
2015-11-30 12:09:36 +00:00
if (OldRoomNum != _roomNum) {
drawStaticMessage(kTextGoForward);
_roomsFound->inclElement(_roomNum); /* Potentially entered a new room */
_curFileName = " ";
2015-11-30 12:09:36 +00:00
forceDraw = true;
} else {
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
drawStaticMessage(kTextNoPath);
}
}
2014-12-27 13:18:40 +00:00
2015-11-30 12:09:36 +00:00
if (_followingCrumbs) {
if (_isCrumbTurning) {
if (Direction == OldDirection) {
_followingCrumbs = false;
}
} else {
if (_roomNum == OldRoomNum) { // didn't get there?
_followingCrumbs = false;
}
}
} else if (_droppingCrumbs && OldRoomNum != _roomNum) {
// If in surreal maze, turn off DroppingCrumbs.
// Note: These numbers were generated by parsing the
// "Maps" file, which is why they are hard-coded. Bleh!
if (_roomNum >= 245 && _roomNum <= 280) {
_followingCrumbs = false;
_droppingCrumbs = false;
_numCrumbs = 0;
_breadCrumbs[0]._roomNum = 0;
} else {
bool intersect = false;
for (int idx = 0; idx < _numCrumbs; idx++) {
if (_breadCrumbs[idx]._roomNum == _roomNum) {
_numCrumbs = idx + 1;
_breadCrumbs[_numCrumbs]._roomNum = 0;
intersect = true;
2014-10-06 12:50:05 +00:00
}
}
2015-11-30 12:09:36 +00:00
if (!intersect) {
if (_numCrumbs == MAX_CRUMBS) {
_numCrumbs = MAX_CRUMBS - 1;
memcpy(&_breadCrumbs[0], &_breadCrumbs[1], _numCrumbs * sizeof _breadCrumbs[0]);
2014-10-06 12:50:05 +00:00
}
2015-11-30 12:09:36 +00:00
_breadCrumbs[_numCrumbs]._roomNum = _roomNum;
_breadCrumbs[_numCrumbs++]._direction = Direction;
}
2014-10-06 12:50:05 +00:00
}
}
2015-11-30 12:09:36 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
}
}
} else if ((msgClass == GADGETUP) && _alternate) {
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (gadgetId == 0) {
eatMessages();
_alternate = false;
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
DoNotDrawMessage = false;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
MainDisplay = true;
interfaceOn(); /* Sets the correct gadget list */
drawPanel();
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
}
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
gadgetId--;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (gadgetId == 0) {
interfaceOff();
2015-12-01 19:10:42 +00:00
_anim->stopDiff();
_curFileName = " ";
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
doit = !saveRestoreGame();
2015-12-03 10:10:58 +00:00
_cptr = NULL;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
MainDisplay = true;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
curInv = MAPNUM;
LastInv = MAPNUM;
2014-12-27 13:18:40 +00:00
_nextFileName = getInvName(curInv);
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
drawPanel();
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (doit) {
drawMessage("Disk operation failed.");
2015-11-30 19:07:23 +00:00
setPalette(initcolors, 8);
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-12-27 13:18:40 +00:00
2015-11-30 12:09:36 +00:00
g_system->delayMillis(1000);
} else {
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
}
} else if (gadgetId == 1) {
if (!doUse(curInv)) {
Old = actionMode;
actionMode = 5; /* Use button */
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if (Old < 5)
perFlipGadget(Old);
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
drawStaticMessage(kTextUseOnWhat);
MainDisplay = true;
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
}
} else if (gadgetId == 2) {
MainDisplay = !MainDisplay;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if ((curInv == 0) || (curInv > NumInv)) {
curInv = 1;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
while ((curInv <= NumInv) && (!_conditions->in(curInv)))
curInv++;
}
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
if ((curInv <= NumInv) && _conditions->in(curInv) &&
Inventory[curInv].BInvName)
_nextFileName = getInvName(curInv);
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (gadgetId == 3) { /* Left gadget */
decIncInv(&curInv, true);
LastInv = curInv;
DoNotDrawMessage = false;
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (gadgetId == 4) { /* Right gadget */
decIncInv(&curInv, false);
LastInv = curInv;
DoNotDrawMessage = false;
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2014-10-06 12:50:05 +00:00
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (gadgetId == 5) { /* bread crumbs */
_breadCrumbs[0]._roomNum = 0;
_numCrumbs = 0;
_droppingCrumbs = true;
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (gadgetId == 6) { /* follow crumbs */
if (_droppingCrumbs) {
if (_numCrumbs > 0) {
_followingCrumbs = true;
_followCrumbsFast = false;
_isCrumbTurning = false;
_isCrumbWaiting = false;
getTime(&_crumbSecs, &_crumbMicros);
2014-10-06 12:50:05 +00:00
eatMessages();
_alternate = false;
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
DoNotDrawMessage = false;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
MainDisplay = true;
interfaceOn(); /* Sets the correct gadget list */
drawPanel();
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else {
_breadCrumbs[0]._roomNum = 0;
_droppingCrumbs = false;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
// Need to hide indicator!!!!
mayShowCrumbIndicatorOff();
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-10-06 12:50:05 +00:00
}
2015-11-30 12:09:36 +00:00
}
}
} else if ((msgClass == MOUSEBUTTONS) && (IEQUALIFIER_LEFTBUTTON & Qualifier) && MainDisplay) {
interfaceOff();
MainDisplay = true;
2014-10-06 12:50:05 +00:00
2015-11-30 12:09:36 +00:00
doit = false;
2014-10-06 12:50:05 +00:00
2015-12-03 10:10:58 +00:00
if (_cptr) {
if ((_cptr->CloseUpType == SPECIALLOCK) && MainDisplay) /* LAB: Labyrinth specific code */
2015-11-30 12:09:36 +00:00
mouseCombination(curPos);
2015-12-03 10:10:58 +00:00
else if ((_cptr->CloseUpType == SPECIALBRICK) && MainDisplay)
2015-11-30 12:09:36 +00:00
mouseTile(curPos);
else
doit = true;
} else
doit = true;
if (doit) {
2015-12-03 10:02:58 +00:00
hcptr = NULL;
2015-11-30 12:09:36 +00:00
eatMessages();
if (actionMode == 0) { /* Take something. */
2015-12-03 10:10:58 +00:00
if (doActionRule(Common::Point(curPos.x, curPos.y), actionMode, _roomNum, &_cptr))
_curFileName = _newFileName;
2015-12-03 10:10:58 +00:00
else if (takeItem(curPos.x, curPos.y, &_cptr))
2015-11-30 12:09:36 +00:00
drawStaticMessage(kTextTakeItem);
2015-12-03 10:10:58 +00:00
else if (doActionRule(curPos, TAKEDEF - 1, _roomNum, &_cptr))
_curFileName = _newFileName;
2015-12-03 10:10:58 +00:00
else if (doActionRule(curPos, TAKE - 1, 0, &_cptr))
_curFileName = _newFileName;
2015-11-30 12:09:36 +00:00
else if (curPos.y < (VGAScaleY(149) + SVGACord(2)))
drawStaticMessage(kTextNothing);
} else if ((actionMode == 1) /* Manipulate an object */ ||
(actionMode == 2) /* Open up a "door" */ ||
(actionMode == 3)) { /* Close a "door" */
2015-12-03 10:10:58 +00:00
if (doActionRule(curPos, actionMode, _roomNum, &_cptr))
_curFileName = _newFileName;
2015-12-03 10:10:58 +00:00
else if (!doActionRule(curPos, actionMode, 0, &_cptr)) {
2015-11-30 12:09:36 +00:00
if (curPos.y < (VGAScaleY(149) + SVGACord(2)))
drawStaticMessage(kTextNothing);
2014-10-06 12:50:05 +00:00
}
2015-11-30 12:09:36 +00:00
} else if (actionMode == 4) { /* Look at closeups */
2015-12-03 10:10:58 +00:00
tempcptr = _cptr;
2015-12-03 10:02:58 +00:00
setCurClose(curPos, &tempcptr);
2015-11-30 12:09:36 +00:00
2015-12-03 10:10:58 +00:00
if (_cptr == tempcptr) {
2015-11-30 12:09:36 +00:00
if (curPos.y < (VGAScaleY(149) + SVGACord(2)))
drawStaticMessage(kTextNothing);
2015-12-03 10:02:58 +00:00
} else if (tempcptr->GraphicName) {
if (*(tempcptr->GraphicName)) {
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-12-03 10:10:58 +00:00
_cptr = tempcptr;
2015-11-30 12:09:36 +00:00
} else if (curPos.y < (VGAScaleY(149) + SVGACord(2)))
drawStaticMessage(kTextNothing);
} else if (curPos.y < (VGAScaleY(149) + SVGACord(2)))
drawStaticMessage(kTextNothing);
} else if ((actionMode == 5) &&
_conditions->in(curInv)) { /* Use an item on something else */
2015-12-03 10:10:58 +00:00
if (doOperateRule(curPos.x, curPos.y, curInv, &_cptr)) {
_curFileName = _newFileName;
2015-11-30 12:09:36 +00:00
if (!_conditions->in(curInv))
decIncInv(&curInv, false);
} else if (curPos.y < (VGAScaleY(149) + SVGACord(2)))
drawStaticMessage(kTextNothing);
2014-10-06 12:50:05 +00:00
}
}
2015-11-30 12:09:36 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2015-11-30 12:09:36 +00:00
} else if (msgClass == DELTAMOVE) {
VPtr = getViewData(_roomNum, Direction);
2015-12-03 10:02:58 +00:00
oldcptr = VPtr->closeUps;
2015-11-30 12:09:36 +00:00
2015-12-03 10:02:58 +00:00
if (hcptr == NULL) {
2015-12-03 10:10:58 +00:00
tempcptr = _cptr;
2015-12-03 10:02:58 +00:00
setCurClose(curPos, &tempcptr);
2015-11-30 12:09:36 +00:00
2015-12-03 10:10:58 +00:00
if ((tempcptr == NULL) || (tempcptr == _cptr)) {
if (_cptr == NULL)
2015-12-03 10:02:58 +00:00
hcptr = oldcptr;
2015-11-30 12:09:36 +00:00
else
2015-12-03 10:10:58 +00:00
hcptr = _cptr->SubCloseUps;
2015-11-30 12:09:36 +00:00
} else
2015-12-03 10:02:58 +00:00
hcptr = tempcptr->NextCloseUp;
2015-11-30 12:09:36 +00:00
} else
2015-12-03 10:02:58 +00:00
hcptr = hcptr->NextCloseUp;
2014-10-06 12:50:05 +00:00
2015-12-03 10:02:58 +00:00
if (hcptr == NULL) {
2015-12-03 10:10:58 +00:00
if (_cptr == NULL)
2015-12-03 10:02:58 +00:00
hcptr = oldcptr;
2015-11-30 12:09:36 +00:00
else
2015-12-03 10:10:58 +00:00
hcptr = _cptr->SubCloseUps;
2015-11-30 12:09:36 +00:00
}
2014-10-06 12:50:05 +00:00
2015-12-03 10:02:58 +00:00
if (hcptr)
_event->setMousePos(Common::Point(scaleX((hcptr->x1 + hcptr->x2) / 2), scaleY((hcptr->y1 + hcptr->y2) / 2)));
2015-11-30 12:09:36 +00:00
} else if ((msgClass == MOUSEBUTTONS) && (IEQUALIFIER_RBUTTON & Qualifier)) {
eatMessages();
_alternate = !_alternate;
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2015-11-30 12:09:36 +00:00
DoNotDrawMessage = false;
MainDisplay = true;
interfaceOn(); /* Sets the correct gadget list */
if (_alternate) {
2015-11-30 12:09:36 +00:00
if (LastInv && _conditions->in(LastInv))
curInv = LastInv;
else
decIncInv(&curInv, false);
2014-10-06 12:50:05 +00:00
}
2015-11-30 12:09:36 +00:00
drawPanel();
2015-12-03 10:10:58 +00:00
drawRoomMessage(curInv, _cptr);
2015-11-30 12:09:36 +00:00
mayShowCrumbIndicator();
2015-11-30 19:07:23 +00:00
screenUpdate();
2014-10-06 12:50:05 +00:00
}
2015-11-30 12:09:36 +00:00
return true;
2014-10-06 12:50:05 +00:00
}
2014-12-27 13:18:40 +00:00
void LabEngine::go() {
bool doIntro = true;
2014-10-06 12:50:05 +00:00
2015-11-29 23:12:01 +00:00
_isHiRes = ((getFeatures() & GF_LOWRES) == 0);
2014-12-27 13:18:40 +00:00
2015-11-27 20:52:31 +00:00
bool mem = false;
2014-10-06 12:50:05 +00:00
if (initBuffer(BUFFERSIZE, true)) {
mem = true;
} else {
warning("initBuffer() failed");
return;
}
if (!setUpScreens()) {
2015-11-29 23:12:01 +00:00
_isHiRes = false;
2014-10-06 12:50:05 +00:00
mem = mem && setUpScreens();
}
_event->initMouse();
2014-10-06 12:50:05 +00:00
mem = mem && initRoomBuffer();
2014-10-06 12:50:05 +00:00
if (!doIntro)
_music->initMusic();
2014-10-06 12:50:05 +00:00
2015-12-03 10:01:50 +00:00
_msgFont = _resource->getFont("P:AvanteG.12");
2014-10-06 12:50:05 +00:00
_event->mouseHide();
if (doIntro && mem) {
2015-12-02 22:10:41 +00:00
Intro *intro = new Intro(this);
intro->introSequence();
delete intro;
2014-10-06 12:50:05 +00:00
} else
2015-12-01 23:34:51 +00:00
_anim->_doBlack = true;
2014-10-06 12:50:05 +00:00
if (mem) {
_event->mouseShow();
mainGameLoop();
2014-10-06 12:50:05 +00:00
} else
debug("\n\nNot enough memory to start game.\n\n");
if (QuitLab) { /* Won the game */
blackAllScreen();
readPict("P:End/L2In.1", true);
for (uint16 i = 0; i < 120; i++) {
_music->updateMusic();
2014-10-06 12:50:05 +00:00
waitTOF();
}
readPict("P:End/L2In.9", true);
readPict("P:End/Lost", true);
warning("STUB: waitForPress");
while (!1) { // 1 means ignore SDL_ProcessInput calls
_music->updateMusic();
2015-12-01 19:10:42 +00:00
_anim->diffNextFrame();
2014-10-06 12:50:05 +00:00
waitTOF();
}
}
2015-12-03 10:01:50 +00:00
closeFont(_msgFont);
2014-10-06 12:50:05 +00:00
freeRoomBuffer();
freeBuffer();
2015-12-02 19:32:06 +00:00
freeScreens();
_music->freeMusic();
2014-10-06 12:50:05 +00:00
}
/*****************************************************************************/
/* New code to allow quick(er) return navigation in game. */
/*****************************************************************************/
int LabEngine::followCrumbs() {
2014-10-06 12:50:05 +00:00
// NORTH, SOUTH, EAST, WEST
static int movement[4][4] = {
2014-12-27 13:18:40 +00:00
{ VKEY_UPARROW, VKEY_RTARROW, VKEY_RTARROW, VKEY_LTARROW },
{ VKEY_RTARROW, VKEY_UPARROW, VKEY_LTARROW, VKEY_RTARROW },
{ VKEY_LTARROW, VKEY_RTARROW, VKEY_UPARROW, VKEY_RTARROW },
{ VKEY_RTARROW, VKEY_LTARROW, VKEY_RTARROW, VKEY_UPARROW }
2014-10-06 12:50:05 +00:00
};
if (_isCrumbWaiting) {
2014-10-06 12:50:05 +00:00
uint32 Secs;
uint32 Micros;
g_lab->timeDiff(_crumbSecs, _crumbMicros, &Secs, &Micros);
2014-10-06 12:50:05 +00:00
if (Secs != 0 || Micros != 0)
return 0;
_isCrumbWaiting = false;
2014-10-06 12:50:05 +00:00
}
if (!_isCrumbTurning)
_breadCrumbs[_numCrumbs--]._roomNum = 0;
2014-10-06 12:50:05 +00:00
// Is the current crumb this room? If not, logic error.
if (g_lab->_roomNum != _breadCrumbs[_numCrumbs]._roomNum) {
_numCrumbs = 0;
_breadCrumbs[0]._roomNum = 0;
_droppingCrumbs = false;
_followingCrumbs = false;
2014-10-06 12:50:05 +00:00
return 0;
}
int exitDir;
2014-10-06 12:50:05 +00:00
// which direction is last crumb
if (_breadCrumbs[_numCrumbs]._direction == EAST)
exitDir = WEST;
else if (_breadCrumbs[_numCrumbs]._direction == WEST)
exitDir = EAST;
else if (_breadCrumbs[_numCrumbs]._direction == NORTH)
exitDir = SOUTH;
2014-10-06 12:50:05 +00:00
else
exitDir = NORTH;
2014-10-06 12:50:05 +00:00
int moveDir = movement[Direction][exitDir];
2014-10-06 12:50:05 +00:00
if (_numCrumbs == 0) {
_isCrumbTurning = false;
_breadCrumbs[0]._roomNum = 0;
_droppingCrumbs = false;
_followingCrumbs = false;
2014-10-06 12:50:05 +00:00
} else {
int theDelay = (_followCrumbsFast ? ONESECOND / 4 : ONESECOND);
2014-10-06 12:50:05 +00:00
_isCrumbTurning = (moveDir != VKEY_UPARROW);
_isCrumbWaiting = true;
2014-10-06 12:50:05 +00:00
g_lab->addCurTime(theDelay / ONESECOND, theDelay % ONESECOND, &_crumbSecs, &_crumbMicros);
2014-10-06 12:50:05 +00:00
}
return moveDir;
2014-10-06 12:50:05 +00:00
}
byte dropCrumbs[] = { 0x00 };
Image dropCrumbsImage(24, 24, dropCrumbs);
2015-11-24 22:59:30 +00:00
void LabEngine::mayShowCrumbIndicator() {
if (getPlatform() != Common::kPlatformWindows)
2014-12-27 13:18:40 +00:00
return;
if (_droppingCrumbs && MainDisplay) {
_event->mouseHide();
dropCrumbsImage.drawMaskImage(612, 4);
_event->mouseShow();
2014-10-06 12:50:05 +00:00
}
}
byte dropCrumbsOff[] = { 0x00 };
Image dropCrumbsOffImage(24, 24, dropCrumbsOff);
2015-11-24 22:59:30 +00:00
void LabEngine::mayShowCrumbIndicatorOff() {
if (getPlatform() != Common::kPlatformWindows)
2014-12-27 13:18:40 +00:00
return;
2014-10-06 12:50:05 +00:00
if (MainDisplay) {
_event->mouseHide();
dropCrumbsOffImage.drawMaskImage(612, 4);
_event->mouseShow();
2014-10-06 12:50:05 +00:00
}
}
2015-12-02 19:50:12 +00:00
/* Have to make sure that ROOMBUFFERSIZE is bigger than the biggest piece of memory
that we need */
#define ROOMBUFFERSIZE (2 * 20480L)
static void *_roomBuffer = nullptr;
static uint16 _curMarker = 0;
static void *_memPlace = nullptr;
/*****************************************************************************/
/* Allocates the memory for the room buffers. */
/*****************************************************************************/
bool initRoomBuffer() {
_curMarker = 0;
if ((_roomBuffer = calloc(ROOMBUFFERSIZE, 1))) {
_memPlace = _roomBuffer;
return true;
} else
return false;
}
/*****************************************************************************/
/* Frees the memory for the room buffers. */
/*****************************************************************************/
void freeRoomBuffer() {
if (_roomBuffer) {
free(_roomBuffer);
_roomBuffer = nullptr;
}
}
2014-10-06 12:50:05 +00:00
} // End of namespace Lab