2015-01-03 03:19:14 -10: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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "xeen/interface.h"
|
2015-02-01 11:56:08 -05:00
|
|
|
#include "xeen/dialogs_char_info.h"
|
2015-01-05 08:11:16 -05:00
|
|
|
#include "xeen/dialogs_error.h"
|
2015-01-31 07:22:25 -05:00
|
|
|
#include "xeen/dialogs_automap.h"
|
2015-01-31 17:39:52 -05:00
|
|
|
#include "xeen/dialogs_info.h"
|
2015-02-07 21:17:31 -05:00
|
|
|
#include "xeen/dialogs_query.h"
|
2015-02-07 18:02:03 -05:00
|
|
|
#include "xeen/dialogs_quests.h"
|
2015-02-01 19:04:28 -05:00
|
|
|
#include "xeen/dialogs_quick_ref.h"
|
2015-01-03 03:19:14 -10:00
|
|
|
#include "xeen/resources.h"
|
|
|
|
#include "xeen/xeen.h"
|
|
|
|
|
2015-02-11 20:04:38 -05:00
|
|
|
#include "xeen/dialogs_party.h"
|
|
|
|
|
2015-01-03 03:19:14 -10:00
|
|
|
namespace Xeen {
|
|
|
|
|
2015-02-10 19:28:45 -05:00
|
|
|
PartyDrawer::PartyDrawer(XeenEngine *vm): _vm(vm) {
|
|
|
|
_restoreSprites.load("restorex.icn");
|
|
|
|
_hpSprites.load("hpbars.icn");
|
|
|
|
_dseFace.load("dse.fac");
|
2015-01-03 19:08:30 -05:00
|
|
|
_hiliteChar = -1;
|
2015-02-10 19:28:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void PartyDrawer::drawParty(bool updateFlag) {
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
Resources &res = *_vm->_resources;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
bool inCombat = _vm->_mode == MODE_COMBAT;
|
|
|
|
_restoreSprites.draw(screen, 0, Common::Point(8, 149));
|
|
|
|
|
|
|
|
// Handle drawing the party faces
|
|
|
|
uint partyCount = inCombat ? party._combatParty.size() : party._activeParty.size();
|
|
|
|
for (uint idx = 0; idx < partyCount; ++idx) {
|
|
|
|
Character &ps = inCombat ? *party._combatParty[idx] : party._activeParty[idx];
|
|
|
|
Condition charCondition = ps.worstCondition();
|
|
|
|
int charFrame = FACE_CONDITION_FRAMES[charCondition];
|
|
|
|
|
|
|
|
SpriteResource *sprites = (charFrame > 4) ? &_dseFace : ps._faceSprites;
|
|
|
|
if (charFrame > 4)
|
|
|
|
charFrame -= 5;
|
|
|
|
|
|
|
|
sprites->draw(screen, charFrame, Common::Point(CHAR_FACES_X[idx], 150));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint idx = 0; idx < partyCount; ++idx) {
|
|
|
|
Character &ps = inCombat ? *party._combatParty[idx] : party._activeParty[idx];
|
|
|
|
|
|
|
|
// Draw the Hp bar
|
|
|
|
int maxHp = ps.getMaxHP();
|
|
|
|
int frame;
|
|
|
|
if (ps._currentHp < 1)
|
|
|
|
frame = 4;
|
|
|
|
else if (ps._currentHp > maxHp)
|
|
|
|
frame = 3;
|
|
|
|
else if (ps._currentHp == maxHp)
|
|
|
|
frame = 0;
|
|
|
|
else if (ps._currentHp < (maxHp / 4))
|
|
|
|
frame = 2;
|
|
|
|
else
|
|
|
|
frame = 1;
|
|
|
|
|
|
|
|
_hpSprites.draw(screen, frame, Common::Point(HP_BARS_X[idx], 182));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_hiliteChar != -1)
|
|
|
|
res._globalSprites.draw(screen, 8, Common::Point(CHAR_FACES_X[_hiliteChar] - 1, 149));
|
|
|
|
|
|
|
|
if (updateFlag)
|
|
|
|
screen._windows[33].update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartyDrawer::highlightChar(int charId) {
|
|
|
|
Resources &res = *_vm->_resources;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
|
|
|
|
if (charId != _hiliteChar && _hiliteChar != HILIGHT_CHAR_DISABLED) {
|
|
|
|
// Handle deselecting any previusly selected char
|
|
|
|
if (_hiliteChar != -1) {
|
|
|
|
res._globalSprites.draw(screen, 9 + _hiliteChar,
|
|
|
|
Common::Point(CHAR_FACES_X[_hiliteChar] - 1, 149));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Highlight new character
|
|
|
|
res._globalSprites.draw(screen, 8, Common::Point(CHAR_FACES_X[charId] - 1, 149));
|
|
|
|
_hiliteChar = charId;
|
|
|
|
screen._windows[33].update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartyDrawer::unhighlightChar() {
|
|
|
|
Resources &res = *_vm->_resources;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
|
|
|
|
if (_hiliteChar != -1) {
|
|
|
|
res._globalSprites.draw(screen, _hiliteChar + 9,
|
|
|
|
Common::Point(CHAR_FACES_X[_hiliteChar] - 1, 149));
|
|
|
|
_hiliteChar = -1;
|
|
|
|
screen._windows[33].update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
Interface::Interface(XeenEngine *vm) : ButtonContainer(), InterfaceMap(vm),
|
|
|
|
PartyDrawer(vm), _vm(vm) {
|
|
|
|
_buttonsLoaded = false;
|
2015-01-05 08:11:16 -05:00
|
|
|
_intrIndex1 = 0;
|
2015-01-19 12:13:03 -05:00
|
|
|
_steppingFX = 0;
|
2015-01-11 17:09:48 -05:00
|
|
|
|
|
|
|
Common::fill(&_combatCharIds[0], &_combatCharIds[8], 0);
|
2015-01-05 15:10:42 -05:00
|
|
|
initDrawStructs();
|
|
|
|
}
|
|
|
|
|
2015-01-14 20:39:56 -05:00
|
|
|
|
2015-01-05 15:10:42 -05:00
|
|
|
void Interface::initDrawStructs() {
|
|
|
|
_mainList[0] = DrawStruct(7, 232, 74);
|
|
|
|
_mainList[1] = DrawStruct(0, 235, 75);
|
|
|
|
_mainList[2] = DrawStruct(2, 260, 75);
|
|
|
|
_mainList[3] = DrawStruct(4, 286, 75);
|
|
|
|
_mainList[4] = DrawStruct(6, 235, 96);
|
|
|
|
_mainList[5] = DrawStruct(8, 260, 96);
|
|
|
|
_mainList[6] = DrawStruct(10, 286, 96);
|
|
|
|
_mainList[7] = DrawStruct(12, 235, 117);
|
|
|
|
_mainList[8] = DrawStruct(14, 260, 117);
|
|
|
|
_mainList[9] = DrawStruct(16, 286, 117);
|
|
|
|
_mainList[10] = DrawStruct(20, 235, 148);
|
|
|
|
_mainList[11] = DrawStruct(22, 260, 148);
|
|
|
|
_mainList[12] = DrawStruct(24, 286, 148);
|
|
|
|
_mainList[13] = DrawStruct(26, 235, 169);
|
|
|
|
_mainList[14] = DrawStruct(28, 260, 169);
|
|
|
|
_mainList[15] = DrawStruct(30, 286, 169);
|
2015-01-03 03:19:14 -10:00
|
|
|
}
|
|
|
|
|
2015-01-05 21:17:44 -05:00
|
|
|
void Interface::setup() {
|
2015-01-22 07:53:33 -05:00
|
|
|
InterfaceMap::setup();
|
2015-01-05 08:11:16 -05:00
|
|
|
_uiSprites.load("inn.icn");
|
2015-02-09 21:34:03 -05:00
|
|
|
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
party.loadActiveParty();
|
|
|
|
party._newDay = party._minutes >= 300;
|
2015-01-03 03:19:14 -10:00
|
|
|
}
|
|
|
|
|
2015-01-05 15:10:42 -05:00
|
|
|
void Interface::startup() {
|
2015-02-10 19:28:45 -05:00
|
|
|
Resources &res = *_vm->_resources;
|
2015-01-05 15:10:42 -05:00
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
_iconSprites.load("main.icn");
|
|
|
|
|
|
|
|
animate3d();
|
|
|
|
if (_vm->_map->_isOutdoors) {
|
2015-01-16 22:19:36 -05:00
|
|
|
setIndoorsMonsters();
|
2015-01-16 21:26:06 -05:00
|
|
|
setIndoorsObjects();
|
2015-01-05 15:10:42 -05:00
|
|
|
} else {
|
|
|
|
setOutdoorsMonsters();
|
|
|
|
setOutdoorsObjects();
|
|
|
|
}
|
|
|
|
draw3d(false);
|
|
|
|
|
2015-02-10 19:28:45 -05:00
|
|
|
res._globalSprites.draw(screen._windows[1], 5, Common::Point(232, 9));
|
|
|
|
drawParty(false);
|
2015-01-05 15:10:42 -05:00
|
|
|
|
2015-02-10 19:28:45 -05:00
|
|
|
_mainList[0]._sprites = &res._globalSprites;
|
2015-01-05 15:10:42 -05:00
|
|
|
for (int i = 1; i < 16; ++i)
|
|
|
|
_mainList[i]._sprites = &_iconSprites;
|
2015-01-06 19:09:07 -05:00
|
|
|
|
2015-01-11 08:54:42 -05:00
|
|
|
setMainButtons();
|
2015-01-06 19:09:07 -05:00
|
|
|
|
|
|
|
_tillMove = false;
|
2015-01-05 15:10:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Interface::mainIconsPrint() {
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
screen._windows[38].close();
|
|
|
|
screen._windows[12].close();
|
|
|
|
screen._windows[0].drawList(_mainList, 16);
|
|
|
|
screen._windows[34].update();
|
|
|
|
}
|
|
|
|
|
2015-01-11 08:54:42 -05:00
|
|
|
void Interface::setMainButtons() {
|
2015-01-06 19:09:07 -05:00
|
|
|
clearButtons();
|
|
|
|
|
2015-01-19 18:51:29 -05:00
|
|
|
addButton(Common::Rect(235, 75, 259, 95), Common::KEYCODE_s, &_iconSprites);
|
|
|
|
addButton(Common::Rect(260, 75, 284, 95), Common::KEYCODE_c, &_iconSprites);
|
|
|
|
addButton(Common::Rect(286, 75, 310, 95), Common::KEYCODE_r, &_iconSprites);
|
|
|
|
addButton(Common::Rect(235, 96, 259, 116), Common::KEYCODE_b, &_iconSprites);
|
|
|
|
addButton(Common::Rect(260, 96, 284, 116), Common::KEYCODE_d, &_iconSprites);
|
|
|
|
addButton(Common::Rect(286, 96, 310, 116), Common::KEYCODE_v, &_iconSprites);
|
|
|
|
addButton(Common::Rect(235, 117, 259, 137), Common::KEYCODE_m, &_iconSprites);
|
|
|
|
addButton(Common::Rect(260, 117, 284, 137), Common::KEYCODE_i, &_iconSprites);
|
|
|
|
addButton(Common::Rect(286, 117, 310, 137), Common::KEYCODE_q, &_iconSprites);
|
2015-01-19 18:42:40 -05:00
|
|
|
addButton(Common::Rect(109, 137, 122, 147), Common::KEYCODE_TAB, &_iconSprites);
|
|
|
|
addButton(Common::Rect(235, 148, 259, 168), Common::KEYCODE_LEFT, &_iconSprites);
|
|
|
|
addButton(Common::Rect(260, 148, 284, 168), Common::KEYCODE_UP, &_iconSprites);
|
|
|
|
addButton(Common::Rect(286, 148, 310, 168), Common::KEYCODE_RIGHT, &_iconSprites);
|
|
|
|
addButton(Common::Rect(235, 169, 259, 189), (Common::KBD_CTRL << 16) |Common::KEYCODE_LEFT, &_iconSprites);
|
|
|
|
addButton(Common::Rect(260, 169, 284, 189), Common::KEYCODE_DOWN, &_iconSprites);
|
|
|
|
addButton(Common::Rect(286, 169, 310, 189), (Common::KBD_CTRL << 16) | Common::KEYCODE_RIGHT, &_iconSprites);
|
2015-01-19 15:29:57 -05:00
|
|
|
addButton(Common::Rect(236, 11, 308, 69), Common::KEYCODE_EQUALS, &_iconSprites, false);
|
2015-01-19 18:51:29 -05:00
|
|
|
addButton(Common::Rect(239, 27, 312, 37), Common::KEYCODE_1, &_iconSprites, false);
|
|
|
|
addButton(Common::Rect(239, 37, 312, 47), Common::KEYCODE_2, &_iconSprites, false);
|
|
|
|
addButton(Common::Rect(239, 47, 312, 57), Common::KEYCODE_3, &_iconSprites, false);
|
2015-02-11 21:09:07 -05:00
|
|
|
addPartyButtons(_vm);
|
2015-01-06 19:09:07 -05:00
|
|
|
}
|
|
|
|
|
2015-01-19 15:29:57 -05:00
|
|
|
/**
|
|
|
|
* Waits for a keypress or click, whilst still allowing the game scene to
|
|
|
|
* be animated.
|
|
|
|
*/
|
|
|
|
void Interface::perform() {
|
|
|
|
EventsManager &events = *_vm->_events;
|
|
|
|
Map &map = *_vm->_map;
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
Scripts &scripts = *_vm->_scripts;
|
|
|
|
const Common::Rect waitBounds(8, 8, 224, 140);
|
|
|
|
|
|
|
|
events.updateGameCounter();
|
|
|
|
draw3d(true);
|
|
|
|
|
|
|
|
// Wait for a frame
|
|
|
|
do {
|
|
|
|
events.pollEventsAndWait();
|
|
|
|
checkEvents(_vm);
|
|
|
|
} while (!_buttonValue && events.timeElapsed() < 1 && !_vm->_party->_partyDead);
|
2015-01-19 12:13:03 -05:00
|
|
|
|
2015-01-19 15:29:57 -05:00
|
|
|
if (!_buttonValue && !_vm->_party->_partyDead)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (_buttonValue == Common::KEYCODE_SPACE ||
|
|
|
|
(events._leftButton && waitBounds.contains(events._mousePos))) {
|
|
|
|
int lookupId = map.mazeLookup(party._mazePosition,
|
2015-01-23 20:44:02 -05:00
|
|
|
WALL_SHIFTS[party._mazeDirection][2]);
|
2015-01-19 15:29:57 -05:00
|
|
|
|
|
|
|
bool eventsFlag = true;
|
|
|
|
switch (lookupId) {
|
|
|
|
case 1:
|
|
|
|
if (!map._isOutdoors) {
|
|
|
|
scripts.openGrate(13, 1);
|
|
|
|
eventsFlag = _buttonValue != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 6:
|
|
|
|
if (!map._isOutdoors) {
|
|
|
|
scripts.openGrate(9, 0);
|
|
|
|
eventsFlag = _buttonValue != 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
if (!map._isOutdoors) {
|
|
|
|
scripts.openGrate(6, 0);
|
|
|
|
eventsFlag = _buttonValue != 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
if (!map._isOutdoors) {
|
|
|
|
scripts.openGrate(1, 1);
|
|
|
|
eventsFlag = _buttonValue != 0;
|
|
|
|
}
|
2015-01-19 11:32:57 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-01-19 15:29:57 -05:00
|
|
|
if (eventsFlag) {
|
|
|
|
scripts.checkEvents();
|
|
|
|
if (_vm->shouldQuit())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (_buttonValue) {
|
|
|
|
case Common::KEYCODE_TAB:
|
|
|
|
// Stop mosters doing any movement
|
|
|
|
_vm->_moveMonsters = false;
|
|
|
|
warning("TODO: showControlPanel");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Common::KEYCODE_SPACE:
|
|
|
|
case Common::KEYCODE_w:
|
|
|
|
// Wait one turn
|
|
|
|
chargeStep();
|
|
|
|
moveMonsters();
|
|
|
|
_upDoorText = false;
|
|
|
|
_flipDefaultGround = !_flipDefaultGround;
|
|
|
|
_flipGround = !_flipGround;
|
|
|
|
|
|
|
|
stepTime();
|
|
|
|
break;
|
2015-01-19 18:42:40 -05:00
|
|
|
|
|
|
|
case (Common::KBD_CTRL << 16) | Common::KEYCODE_LEFT:
|
|
|
|
case Common::KEYCODE_KP4:
|
|
|
|
if (checkMoveDirection((Common::KBD_CTRL << 16) | Common::KEYCODE_LEFT)) {
|
|
|
|
switch (party._mazeDirection) {
|
|
|
|
case DIR_NORTH:
|
|
|
|
--party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
case DIR_SOUTH:
|
|
|
|
++party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
case DIR_EAST:
|
|
|
|
++party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_WEST:
|
|
|
|
--party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
chargeStep();
|
|
|
|
_isAnimReset = true;
|
|
|
|
party._mazeDirection = (Direction)((int)party._mazeDirection & 3);
|
|
|
|
_flipSky = !_flipSky;
|
|
|
|
stepTime();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case (Common::KBD_CTRL << 16) | Common::KEYCODE_RIGHT:
|
|
|
|
case Common::KEYCODE_KP6:
|
|
|
|
if (checkMoveDirection((Common::KBD_CTRL << 16) | Common::KEYCODE_RIGHT)) {
|
|
|
|
switch (party._mazeDirection) {
|
|
|
|
case DIR_NORTH:
|
|
|
|
++party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
case DIR_SOUTH:
|
|
|
|
--party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
case DIR_EAST:
|
|
|
|
--party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_WEST:
|
|
|
|
++party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
chargeStep();
|
|
|
|
_isAnimReset = true;
|
|
|
|
party._mazeDirection = (Direction)((int)party._mazeDirection & 3);
|
|
|
|
_flipSky = !_flipSky;
|
|
|
|
stepTime();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Common::KEYCODE_LEFT:
|
|
|
|
case Common::KEYCODE_KP7:
|
|
|
|
party._mazeDirection = (Direction)((int)party._mazeDirection - 1);
|
|
|
|
_isAnimReset = true;
|
|
|
|
party._mazeDirection = (Direction)((int)party._mazeDirection & 3);
|
|
|
|
_flipSky = !_flipSky;
|
|
|
|
stepTime();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Common::KEYCODE_RIGHT:
|
|
|
|
case Common::KEYCODE_KP9:
|
|
|
|
party._mazeDirection = (Direction)((int)party._mazeDirection + 1);
|
|
|
|
_isAnimReset = true;
|
|
|
|
party._mazeDirection = (Direction)((int)party._mazeDirection & 3);
|
|
|
|
_flipSky = !_flipSky;
|
|
|
|
stepTime();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Common::KEYCODE_UP:
|
|
|
|
case Common::KEYCODE_KP8:
|
|
|
|
if (checkMoveDirection(Common::KEYCODE_UP)) {
|
|
|
|
switch (party._mazeDirection) {
|
|
|
|
case DIR_NORTH:
|
|
|
|
++party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_SOUTH:
|
|
|
|
--party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_EAST:
|
|
|
|
++party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
case DIR_WEST:
|
|
|
|
--party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
chargeStep();
|
|
|
|
stepTime();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Common::KEYCODE_DOWN:
|
|
|
|
case Common::KEYCODE_KP2:
|
|
|
|
if (checkMoveDirection(Common::KEYCODE_DOWN)) {
|
|
|
|
switch (party._mazeDirection) {
|
|
|
|
case DIR_NORTH:
|
|
|
|
--party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_SOUTH:
|
|
|
|
++party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_EAST:
|
|
|
|
--party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
case DIR_WEST:
|
|
|
|
++party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
chargeStep();
|
|
|
|
stepTime();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-02-01 11:56:08 -05:00
|
|
|
case Common::KEYCODE_F1:
|
|
|
|
case Common::KEYCODE_F2:
|
|
|
|
case Common::KEYCODE_F3:
|
|
|
|
case Common::KEYCODE_F4:
|
|
|
|
case Common::KEYCODE_F5:
|
|
|
|
case Common::KEYCODE_F6:
|
|
|
|
_buttonValue -= Common::KEYCODE_F1;
|
2015-02-10 23:40:45 -05:00
|
|
|
if (_buttonValue < (int)party._activeParty.size()) {
|
2015-02-01 11:56:08 -05:00
|
|
|
CharacterInfo::show(_vm, _buttonValue);
|
|
|
|
if (party._stepped)
|
|
|
|
moveMonsters();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-01-19 15:29:57 -05:00
|
|
|
case Common::KEYCODE_EQUALS:
|
|
|
|
case Common::KEYCODE_KP_EQUALS:
|
|
|
|
// Toggle minimap
|
2015-01-31 17:45:06 -05:00
|
|
|
_vm->_moveMonsters = false;
|
2015-01-19 15:29:57 -05:00
|
|
|
party._automapOn = !party._automapOn;
|
2015-01-31 17:45:06 -05:00
|
|
|
_vm->_moveMonsters = true;
|
2015-01-19 15:29:57 -05:00
|
|
|
break;
|
2015-01-31 07:22:25 -05:00
|
|
|
|
2015-02-07 22:47:28 -05:00
|
|
|
case Common::KEYCODE_b:
|
|
|
|
chargeStep();
|
|
|
|
|
|
|
|
if (map.getCell(2) < map.mazeData()._difficulties._wallNoPass
|
|
|
|
&& !map._isOutdoors) {
|
|
|
|
switch (party._mazeDirection) {
|
|
|
|
case DIR_NORTH:
|
|
|
|
++party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_EAST:
|
|
|
|
++party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
case DIR_SOUTH:
|
|
|
|
--party._mazePosition.y;
|
|
|
|
break;
|
|
|
|
case DIR_WEST:
|
|
|
|
--party._mazePosition.x;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
chargeStep();
|
|
|
|
stepTime();
|
|
|
|
} else {
|
|
|
|
bash(party._mazePosition, party._mazeDirection);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-01-31 17:39:52 -05:00
|
|
|
case Common::KEYCODE_i:
|
|
|
|
// Show Info dialog
|
2015-01-31 17:45:06 -05:00
|
|
|
_vm->_moveMonsters = false;
|
2015-01-31 17:39:52 -05:00
|
|
|
InfoDialog::show(_vm);
|
2015-01-31 17:45:06 -05:00
|
|
|
_vm->_moveMonsters = true;
|
2015-01-31 17:39:52 -05:00
|
|
|
break;
|
|
|
|
|
2015-01-31 07:22:25 -05:00
|
|
|
case Common::KEYCODE_m:
|
|
|
|
// Show map dialog
|
|
|
|
AutoMapDialog::show(_vm);
|
|
|
|
break;
|
|
|
|
|
2015-02-01 19:04:28 -05:00
|
|
|
case Common::KEYCODE_q:
|
|
|
|
// Show the quick reference dialog
|
|
|
|
QuickReferenceDialog::show(_vm);
|
|
|
|
break;
|
|
|
|
|
2015-02-07 21:17:31 -05:00
|
|
|
case Common::KEYCODE_r:
|
|
|
|
// Rest
|
|
|
|
rest();
|
|
|
|
break;
|
|
|
|
|
2015-02-07 18:02:03 -05:00
|
|
|
case Common::KEYCODE_v:
|
|
|
|
// Show the quests dialog
|
|
|
|
Quests::show(_vm);
|
|
|
|
break;
|
|
|
|
|
2015-02-11 20:04:38 -05:00
|
|
|
case Common::KEYCODE_x:
|
|
|
|
// ****DEBUG***
|
|
|
|
PartyDialog::show(_vm); //***DEBUG****
|
2015-01-19 15:29:57 -05:00
|
|
|
default:
|
|
|
|
break;
|
2015-01-19 11:32:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Interface::chargeStep() {
|
|
|
|
if (_vm->_party->_partyDead) {
|
|
|
|
_vm->_party->changeTime(_vm->_map->_isOutdoors ? 10 : 1);
|
|
|
|
if (!_tillMove) {
|
|
|
|
moveMonsters();
|
|
|
|
}
|
|
|
|
|
|
|
|
_tillMove = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-19 12:13:03 -05:00
|
|
|
/**
|
|
|
|
* Handles incrementing game time
|
|
|
|
*/
|
|
|
|
void Interface::stepTime() {
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
SoundManager &sound = *_vm->_sound;
|
|
|
|
doStepCode();
|
|
|
|
|
|
|
|
if (++party._ctr24 == 24)
|
|
|
|
party._ctr24 = 0;
|
|
|
|
|
|
|
|
if (_buttonValue != Common::KEYCODE_SPACE && _buttonValue != Common::KEYCODE_w) {
|
|
|
|
_steppingFX ^= 1;
|
|
|
|
sound.playFX(_steppingFX + 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
_upDoorText = false;
|
|
|
|
_flipDefaultGround = !_flipDefaultGround;
|
|
|
|
_flipGround = !_flipGround;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Interface::doStepCode() {
|
2015-01-20 08:46:27 -05:00
|
|
|
Map &map = *_vm->_map;
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
int damage = 0;
|
|
|
|
|
|
|
|
party._stepped = true;
|
|
|
|
_upDoorText = false;
|
|
|
|
|
|
|
|
map.getCell(2);
|
|
|
|
int surfaceId = map.mazeData()._surfaceTypes[map._currentSurfaceId];
|
|
|
|
|
|
|
|
switch (surfaceId) {
|
|
|
|
case SURFTYPE_SPACE:
|
|
|
|
// Wheeze.. can't breathe in space! Explosive decompression, here we come
|
|
|
|
party._partyDead = true;
|
|
|
|
break;
|
|
|
|
case SURFTYPE_LAVA:
|
|
|
|
// It burns, it burns!
|
|
|
|
damage = 100;
|
|
|
|
party._damageType = DT_FIRE;
|
|
|
|
break;
|
|
|
|
case SURFTYPE_SKY:
|
|
|
|
// We can fly, we can.. oh wait, we can't!
|
|
|
|
damage = 100;
|
|
|
|
party._damageType = DT_PHYSICAL;
|
|
|
|
party._falling = true;
|
|
|
|
break;
|
|
|
|
case SURFTYPE_DESERT:
|
|
|
|
// Without navigation skills, simulate getting lost by adding extra time
|
|
|
|
if (map._isOutdoors && !party.checkSkill(NAVIGATOR))
|
|
|
|
party.addTime(170);
|
|
|
|
break;
|
|
|
|
case SURFTYPE_CLOUD:
|
|
|
|
if (!party._levitateActive) {
|
|
|
|
party._damageType = DT_PHYSICAL;
|
|
|
|
party._falling = true;
|
|
|
|
damage = 100;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_vm->_files->_isDarkCc && party._gameFlags[374]) {
|
|
|
|
party._falling = false;
|
|
|
|
} else {
|
|
|
|
if (party._falling)
|
|
|
|
doFalling();
|
|
|
|
|
|
|
|
if ((party._mazePosition.x & 16) || (party._mazePosition.y & 16)) {
|
2015-01-20 21:05:15 -05:00
|
|
|
if (map._isOutdoors)
|
|
|
|
map.getNewMaze();
|
2015-01-20 08:46:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (damage) {
|
|
|
|
_flipGround = !_flipGround;
|
|
|
|
draw3d(true);
|
|
|
|
|
|
|
|
warning("TODO: apply damage");
|
|
|
|
|
|
|
|
_flipGround = !_flipGround;
|
|
|
|
} else if (party._partyDead) {
|
|
|
|
draw3d(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Interface::doFalling() {
|
2015-01-19 12:13:03 -05:00
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:42:40 -05:00
|
|
|
bool Interface::checkMoveDirection(int key) {
|
|
|
|
Map &map = *_vm->_map;
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
SoundManager &sound = *_vm->_sound;
|
|
|
|
Direction dir = party._mazeDirection;
|
|
|
|
|
|
|
|
switch (_buttonValue) {
|
|
|
|
case (Common::KBD_CTRL << 16) | Common::KEYCODE_LEFT:
|
|
|
|
party._mazeDirection = (party._mazeDirection == DIR_NORTH) ? DIR_WEST :
|
|
|
|
(Direction)(party._mazeDirection - 1);
|
|
|
|
break;
|
|
|
|
case (Common::KBD_CTRL << 16) | Common::KEYCODE_RIGHT:
|
|
|
|
party._mazeDirection = (party._mazeDirection == DIR_WEST) ? DIR_NORTH :
|
|
|
|
(Direction)(party._mazeDirection + 1);
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_DOWN:
|
|
|
|
party._mazeDirection = (party._mazeDirection == DIR_NORTH) ? DIR_SOUTH : DIR_NORTH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
map.getCell(7);
|
|
|
|
int startSurfaceId = map._currentSurfaceId;
|
|
|
|
int surfaceId;
|
|
|
|
|
|
|
|
if (map._isOutdoors) {
|
|
|
|
party._mazeDirection = dir;
|
|
|
|
|
2015-01-24 23:49:12 -05:00
|
|
|
switch (map._currentWall) {
|
2015-01-19 18:42:40 -05:00
|
|
|
case 5:
|
|
|
|
if (_vm->_files->_isDarkCc)
|
|
|
|
goto check;
|
|
|
|
|
|
|
|
// Deliberate FAll-through
|
|
|
|
case 0:
|
|
|
|
case 2:
|
|
|
|
case 4:
|
|
|
|
case 8:
|
|
|
|
case 11:
|
|
|
|
case 13:
|
|
|
|
case 14:
|
|
|
|
surfaceId = map.mazeData()._surfaceTypes[map._currentSurfaceId];
|
|
|
|
if (surfaceId == SURFTYPE_WATER) {
|
|
|
|
if (party.checkSkill(SWIMMING) || party._walkOnWaterActive)
|
|
|
|
return true;
|
|
|
|
} else if (surfaceId == SURFTYPE_DWATER) {
|
|
|
|
if (party._walkOnWaterActive)
|
|
|
|
return true;
|
2015-01-19 23:18:44 -05:00
|
|
|
} else if (surfaceId != SURFTYPE_SPACE) {
|
2015-01-19 18:42:40 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
sound.playFX(21);
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
case 7:
|
|
|
|
case 9:
|
|
|
|
case 10:
|
|
|
|
case 12:
|
|
|
|
check:
|
|
|
|
if (party.checkSkill(MOUNTAINEER))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
sound.playFX(21);
|
|
|
|
return false;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int surfaceId = map.getCell(2);
|
|
|
|
if (surfaceId >= map.mazeData()._difficulties._wallNoPass) {
|
|
|
|
party._mazeDirection = dir;
|
|
|
|
} else {
|
|
|
|
party._mazeDirection = dir;
|
|
|
|
|
2015-01-20 08:20:07 -05:00
|
|
|
if (startSurfaceId == SURFTYPE_SWAMP || party.checkSkill(SWIMMING) ||
|
2015-01-19 18:42:40 -05:00
|
|
|
party._walkOnWaterActive) {
|
|
|
|
sound.playFX(46);
|
|
|
|
return false;
|
|
|
|
} else {
|
2015-02-14 08:36:40 -05:00
|
|
|
if (_buttonValue == Common::KEYCODE_UP && _wo[107]) {
|
2015-01-19 18:42:40 -05:00
|
|
|
_vm->_openDoor = true;
|
|
|
|
sound.playFX(47);
|
|
|
|
draw3d(true);
|
|
|
|
_vm->_openDoor = false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-02-07 21:17:31 -05:00
|
|
|
void Interface::rest() {
|
|
|
|
EventsManager &events = *_vm->_events;
|
|
|
|
Map &map = *_vm->_map;
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
SoundManager &sound = *_vm->_sound;
|
|
|
|
|
|
|
|
map.cellFlagLookup(party._mazePosition);
|
|
|
|
|
|
|
|
if ((map._currentCantRest || (map.mazeData()._mazeFlags & RESTRICTION_REST))
|
|
|
|
&& _vm->_mode != MODE_12) {
|
|
|
|
ErrorScroll::show(_vm, TOO_DANGEROUS_TO_REST, WT_NONFREEZED_WAIT);
|
|
|
|
} else {
|
|
|
|
// Check whether any character is in danger of dying
|
|
|
|
bool dangerFlag = false;
|
|
|
|
for (uint charIdx = 0; charIdx < party._activeParty.size(); ++charIdx) {
|
|
|
|
for (int attrib = MIGHT; attrib <= LUCK; ++attrib) {
|
|
|
|
if (party._activeParty[charIdx].getStat((Attribute)attrib) < 1)
|
|
|
|
dangerFlag = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dangerFlag) {
|
|
|
|
if (!Confirm::show(_vm, SOME_CHARS_MAY_DIE))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark all the players as being asleep
|
|
|
|
for (uint charIdx = 0; charIdx < party._activeParty.size(); ++charIdx) {
|
|
|
|
party._activeParty[charIdx]._conditions[ASLEEP] = 1;
|
|
|
|
}
|
2015-02-10 19:28:45 -05:00
|
|
|
drawParty(true);
|
2015-02-07 21:17:31 -05:00
|
|
|
|
|
|
|
Mode oldMode = _vm->_mode;
|
|
|
|
_vm->_mode = MODE_SLEEPING;
|
|
|
|
|
|
|
|
if (oldMode == MODE_12) {
|
|
|
|
party.changeTime(8 * 60);
|
|
|
|
} else {
|
|
|
|
for (int idx = 0; idx < 10; ++idx) {
|
|
|
|
chargeStep();
|
|
|
|
draw3d(true);
|
|
|
|
|
|
|
|
if (_vm->_mode == MODE_1) {
|
|
|
|
_vm->_mode = oldMode;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
party.changeTime(map._isOutdoors ? 380 : 470);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_vm->getRandomNumber(1, 20) == 1) {
|
|
|
|
// Show dream
|
|
|
|
screen.saveBackground();
|
|
|
|
screen.fadeOut(4);
|
|
|
|
events.hideCursor();
|
|
|
|
|
|
|
|
screen.loadBackground("scene1.raw");
|
|
|
|
screen._windows[0].update();
|
|
|
|
screen.fadeIn(4);
|
|
|
|
|
|
|
|
events.updateGameCounter();
|
|
|
|
while (!_vm->shouldQuit() && events.timeElapsed() < 7)
|
|
|
|
events.pollEventsAndWait();
|
|
|
|
|
|
|
|
File f("dreams2.voc");
|
|
|
|
sound.playSample(&f, 1);
|
|
|
|
while (!_vm->shouldQuit() && sound.playSample(1, 0))
|
|
|
|
events.pollEventsAndWait();
|
|
|
|
f.close();
|
|
|
|
|
|
|
|
f.openFile("laff1.voc");
|
|
|
|
sound.playSample(&f, 1);
|
|
|
|
while (!_vm->shouldQuit() && sound.playSample(1, 0))
|
|
|
|
events.pollEventsAndWait();
|
|
|
|
f.close();
|
|
|
|
|
|
|
|
events.updateGameCounter();
|
|
|
|
while (!_vm->shouldQuit() && events.timeElapsed() < 7)
|
|
|
|
events.pollEventsAndWait();
|
|
|
|
|
|
|
|
screen.fadeOut(4);
|
|
|
|
events.setCursor(0);
|
|
|
|
screen.restoreBackground();
|
|
|
|
screen._windows[0].update();
|
|
|
|
|
|
|
|
screen.fadeIn(4);
|
|
|
|
}
|
|
|
|
|
|
|
|
party.resetTemps();
|
|
|
|
|
|
|
|
// Wake up the party
|
|
|
|
bool starving = false;
|
|
|
|
int foodConsumed = 0;
|
|
|
|
for (uint charIdx = 0; charIdx < party._activeParty.size(); ++charIdx) {
|
|
|
|
Character &c = party._activeParty[charIdx];
|
|
|
|
c._conditions[ASLEEP] = 0;
|
|
|
|
|
|
|
|
if (party._food == 0) {
|
|
|
|
starving = true;
|
|
|
|
} else {
|
|
|
|
party._rested = true;
|
|
|
|
Condition condition = c.worstCondition();
|
|
|
|
|
|
|
|
if (condition < DEAD || condition > ERADICATED) {
|
|
|
|
--party._food;
|
|
|
|
++foodConsumed;
|
|
|
|
party._heroism = 0;
|
|
|
|
party._holyBonus = 0;
|
|
|
|
party._powerShield = 0;
|
|
|
|
party._blessed = 0;
|
|
|
|
c._conditions[UNCONSCIOUS] = 0;
|
|
|
|
c._currentHp = c.getMaxHP();
|
|
|
|
c._currentSp = c.getMaxSP();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-10 19:28:45 -05:00
|
|
|
drawParty(true);
|
2015-02-07 21:17:31 -05:00
|
|
|
_vm->_mode = oldMode;
|
|
|
|
doStepCode();
|
|
|
|
draw3d(true);
|
|
|
|
|
|
|
|
ErrorScroll::show(_vm, Common::String::format(REST_COMPLETE,
|
|
|
|
starving ? PARTY_IS_STARVING : HIT_SPELL_POINTS_RESTORED,
|
|
|
|
foodConsumed));
|
|
|
|
party.checkPartyDead();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-07 22:47:28 -05:00
|
|
|
void Interface::bash(const Common::Point &pt, Direction direction) {
|
|
|
|
EventsManager &events = *_vm->_events;
|
|
|
|
Map &map = *_vm->_map;
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
SoundManager &sound = *_vm->_sound;
|
|
|
|
|
|
|
|
if (map._isOutdoors)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sound.playFX(31);
|
|
|
|
|
|
|
|
uint charNum1 = 0, charNum2 = 0;
|
|
|
|
for (uint charIdx = 0; charIdx < party._activeParty.size(); ++charIdx) {
|
|
|
|
Character &c = party._activeParty[charIdx];
|
|
|
|
Condition condition = c.worstCondition();
|
|
|
|
|
|
|
|
if (!(condition == ASLEEP || (condition >= PARALYZED &&
|
|
|
|
condition <= ERADICATED))) {
|
|
|
|
if (charNum1) {
|
|
|
|
charNum2 = charIdx + 1;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
charNum1 = charIdx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
party._activeParty[charNum1 - 1].subtractHitPoints(2);
|
|
|
|
_charPowSprites.draw(screen._windows[0], 0,
|
|
|
|
Common::Point(CHAR_FACES_X[charNum1 - 1], 150));
|
|
|
|
screen._windows[0].update();
|
|
|
|
|
|
|
|
if (charNum2) {
|
|
|
|
party._activeParty[charNum2 - 1].subtractHitPoints(2);
|
|
|
|
_charPowSprites.draw(screen._windows[0], 0,
|
|
|
|
Common::Point(CHAR_FACES_X[charNum2 - 1], 150));
|
|
|
|
screen._windows[0].update();
|
|
|
|
}
|
|
|
|
|
|
|
|
int cell = map.mazeLookup(Common::Point(pt.x + SCREEN_POSITIONING_X[direction][7],
|
|
|
|
pt.y + SCREEN_POSITIONING_Y[direction][7]), 0, 0xffff);
|
|
|
|
if (cell != INVALID_CELL) {
|
|
|
|
int v = map.getCell(2);
|
|
|
|
|
|
|
|
if (v == 7) {
|
|
|
|
++_wo[207];
|
|
|
|
++_wo[267];
|
|
|
|
++_wo[287];
|
|
|
|
} else if (v == 14) {
|
|
|
|
++_wo[267];
|
|
|
|
++_wo[287];
|
|
|
|
} else if (v == 15) {
|
|
|
|
++_wo[287];
|
|
|
|
} else {
|
|
|
|
int might = party._activeParty[charNum1 - 1].getStat(MIGHT) +
|
|
|
|
_vm->getRandomNumber(1, 30);
|
|
|
|
if (charNum2)
|
|
|
|
might += party._activeParty[charNum2 - 1].getStat(MIGHT);
|
|
|
|
|
|
|
|
int bashThreshold = (v == 9) ? map.mazeData()._difficulties._bashGrate :
|
|
|
|
map.mazeData()._difficulties._bashWall;
|
|
|
|
if (might >= bashThreshold) {
|
|
|
|
// Remove the wall on the current cell, and the reverse wall
|
|
|
|
// on the cell we're bashing through to
|
|
|
|
map.setWall(pt, direction, 3);
|
|
|
|
switch (direction) {
|
|
|
|
case DIR_NORTH:
|
|
|
|
map.setWall(Common::Point(pt.x, pt.y + 1), DIR_SOUTH, 3);
|
|
|
|
break;
|
|
|
|
case DIR_EAST:
|
|
|
|
map.setWall(Common::Point(pt.x + 1, pt.y), DIR_WEST, 3);
|
|
|
|
break;
|
|
|
|
case DIR_SOUTH:
|
|
|
|
map.setWall(Common::Point(pt.x, pt.y - 1), DIR_NORTH, 3);
|
|
|
|
break;
|
|
|
|
case DIR_WEST:
|
|
|
|
map.setWall(Common::Point(pt.x - 1, pt.y), DIR_EAST, 3);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
party.checkPartyDead();
|
|
|
|
events.ipause(2);
|
2015-02-10 19:28:45 -05:00
|
|
|
drawParty(true);
|
2015-02-07 22:47:28 -05:00
|
|
|
}
|
|
|
|
|
2015-02-15 12:01:04 -05:00
|
|
|
void Interface::draw3d(bool updateFlag) {
|
|
|
|
Combat &combat = *_vm->_combat;
|
|
|
|
EventsManager &events = *_vm->_events;
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
Screen &screen = *_vm->_screen;
|
2015-02-15 12:20:44 -05:00
|
|
|
Scripts &scripts = *_vm->_scripts;
|
2015-02-15 12:01:04 -05:00
|
|
|
|
|
|
|
if (screen._windows[11]._enabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Draw the map
|
2015-02-15 12:20:44 -05:00
|
|
|
drawMap();
|
2015-02-15 12:01:04 -05:00
|
|
|
|
|
|
|
// Draw the minimap
|
|
|
|
drawMiniMap();
|
|
|
|
|
|
|
|
if (party._falling == 1)
|
|
|
|
handleFalling();
|
|
|
|
|
|
|
|
if (party._falling == 2) {
|
|
|
|
screen.saveBackground(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
assembleBorder();
|
|
|
|
|
|
|
|
// Draw any on-screen text if flagged to do so
|
|
|
|
if (_upDoorText && combat._attackMonsters[0] == -1) {
|
|
|
|
screen._windows[3].writeString(_screenText);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (updateFlag) {
|
|
|
|
screen._windows[1].update();
|
|
|
|
screen._windows[3].update();
|
|
|
|
}
|
|
|
|
|
2015-02-15 12:20:44 -05:00
|
|
|
if (combat._attackMonsters[0] != -1 || combat._attackMonsters[1] != -1
|
|
|
|
|| combat._attackMonsters[2] != -1) {
|
|
|
|
if ((_vm->_mode == MODE_1 || _vm->_mode == MODE_SLEEPING) && !_flag1
|
|
|
|
&& !_charsShooting && _vm->_moveMonsters) {
|
|
|
|
combat.doCombat();
|
|
|
|
if (scripts._eventSkipped)
|
|
|
|
scripts.checkEvents();
|
|
|
|
}
|
|
|
|
}
|
2015-02-15 12:01:04 -05:00
|
|
|
|
2015-02-15 12:20:44 -05:00
|
|
|
party._stepped = false;
|
2015-02-15 12:01:04 -05:00
|
|
|
if (_vm->_mode == MODE_9) {
|
2015-02-15 12:20:44 -05:00
|
|
|
// TODO: Save current scripts data?
|
|
|
|
error("TODO: save scripts?");
|
2015-02-15 12:01:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Check use of updateFlag here. Original doesn't have it, but I
|
|
|
|
// wanted to ensure in places like the AutoMapDialog, that the draw3d
|
|
|
|
// doesn't result in the screen updating until the dialog has had
|
|
|
|
// a chance to full render itself
|
|
|
|
if (updateFlag)
|
|
|
|
events.wait(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Interface::handleFalling() {
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
SoundManager &sound = *_vm->_sound;
|
|
|
|
Window &w = screen._windows[3];
|
|
|
|
File voc1("scream.voc");
|
|
|
|
File voc2("unnh.voc");
|
|
|
|
saveFall();
|
|
|
|
|
|
|
|
for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
|
|
|
|
party._activeParty[idx]._faceSprites->draw(screen._windows[0], 4,
|
|
|
|
Common::Point(CHAR_FACES_X[idx], 150));
|
|
|
|
}
|
|
|
|
|
|
|
|
screen._windows[33].update();
|
|
|
|
sound.playFX(11);
|
|
|
|
sound.playSample(&voc1, 0);
|
|
|
|
|
|
|
|
for (int idx = 0, incr = 2; idx < 133; ++incr, idx += incr) {
|
|
|
|
fall(idx);
|
|
|
|
assembleBorder();
|
|
|
|
w.update();
|
|
|
|
}
|
|
|
|
|
|
|
|
fall(132);
|
|
|
|
assembleBorder();
|
|
|
|
w.update();
|
|
|
|
|
|
|
|
sound.playSample(nullptr, 0);
|
|
|
|
sound.playSample(&voc2, 0);
|
|
|
|
sound.playFX(31);
|
|
|
|
|
|
|
|
fall(127);
|
|
|
|
assembleBorder();
|
|
|
|
w.update();
|
|
|
|
|
|
|
|
fall(132);
|
|
|
|
assembleBorder();
|
|
|
|
w.update();
|
|
|
|
|
|
|
|
fall(129);
|
|
|
|
assembleBorder();
|
|
|
|
w.update();
|
|
|
|
|
|
|
|
fall(132);
|
|
|
|
assembleBorder();
|
|
|
|
w.update();
|
|
|
|
|
2015-02-15 12:20:44 -05:00
|
|
|
shake(10);
|
2015-02-15 12:01:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Interface::saveFall() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Interface::fall(int v) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-15 12:20:44 -05:00
|
|
|
void Interface::shake(int time) {
|
2015-02-15 12:01:04 -05:00
|
|
|
|
|
|
|
}
|
2015-02-07 22:47:28 -05:00
|
|
|
|
2015-02-15 12:26:23 -05:00
|
|
|
void Interface::drawMiniMap() {
|
|
|
|
Map &map = *_vm->_map;
|
|
|
|
Party &party = *_vm->_party;
|
|
|
|
Resources &res = *_vm->_resources;
|
|
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
Window &window1 = screen._windows[1];
|
|
|
|
|
|
|
|
if (screen._windows[2]._enabled || screen._windows[10]._enabled)
|
|
|
|
return;
|
|
|
|
if (!party._automapOn && !party._wizardEyeActive) {
|
|
|
|
// Draw the Might & Magic logo
|
|
|
|
res._globalSprites.draw(window1, 5, Common::Point(232, 9));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int v, frame;
|
|
|
|
int frame2 = _overallFrame * 2;
|
|
|
|
bool eyeActive = party._wizardEyeActive;
|
|
|
|
if (party._automapOn)
|
|
|
|
party._wizardEyeActive = false;
|
|
|
|
|
|
|
|
if (map._isOutdoors) {
|
|
|
|
res._globalSprites.draw(window1, 15, Common::Point(237, 12));
|
|
|
|
|
|
|
|
for (int rowNum = 0, yp = 12, yDiff = 3; rowNum < MINIMAP_SIZE; ++rowNum, yp += 8, --yDiff) {
|
|
|
|
for (int colNum = 0, xp = 237, xDiff = -3; colNum < MINIMAP_SIZE; ++colNum, xp += 10, ++xDiff) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x + xDiff, party._mazePosition.y + yDiff),
|
|
|
|
4);
|
|
|
|
frame = map.mazeDataCurrent()._surfaceTypes[v];
|
|
|
|
|
|
|
|
if (frame != -1 && (map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, frame, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int rowNum = 0, yp = 12, yDiff = 3; rowNum < MINIMAP_SIZE; ++rowNum, yp += 8, --yDiff) {
|
|
|
|
for (int colNum = 0, xp = 237, xDiff = -3; colNum < MINIMAP_SIZE; ++colNum, xp += 10, ++xDiff) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x + xDiff, party._mazePosition.y + yDiff),
|
|
|
|
4);
|
|
|
|
frame = map.mazeData()._wallTypes[v];
|
|
|
|
|
|
|
|
if (frame != -1 && (map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, frame + 16, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int rowNum = 0, yp = 12, yDiff = 3; rowNum < MINIMAP_SIZE; ++rowNum, yp += 8, --yDiff) {
|
|
|
|
for (int colNum = 0, xp = 237, xDiff = -3; colNum < MINIMAP_SIZE; ++colNum, xp += 10, ++xDiff) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x + xDiff, party._mazePosition.y + yDiff),
|
|
|
|
4);
|
|
|
|
|
|
|
|
if (v != -1 && (map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, v + 32, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the direction arrow
|
|
|
|
res._globalSprites.draw(window1, party._mazeDirection + 1,
|
|
|
|
Common::Point(267, 36));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
frame2 = (frame2 + 2) % 8;
|
|
|
|
|
|
|
|
// First draw the default surface bases for each cell to show
|
|
|
|
for (int rowNum = 0, yp = 12, yDiff = 3; rowNum < MINIMAP_SIZE; ++rowNum, yp += 8, --yDiff) {
|
|
|
|
for (int colNum = 0, xp = 237, xDiff = -3; colNum < MINIMAP_SIZE; ++colNum, xp += 10, ++xDiff) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x + xDiff, party._mazePosition.y + yDiff),
|
|
|
|
0, 0xffff);
|
|
|
|
|
|
|
|
if (v != INVALID_CELL && (map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, 0, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw correct surface bases for revealed tiles
|
|
|
|
for (int rowNum = 0, yp = 17, yDiff = 3; rowNum < MINIMAP_SIZE; ++rowNum, yp += 8, --yDiff) {
|
|
|
|
for (int colNum = 0, xp = 242, xDiff = -3; colNum < MINIMAP_SIZE; ++colNum, xp += 10, ++xDiff) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x + xDiff, party._mazePosition.y + yDiff),
|
|
|
|
0, 0xffff);
|
|
|
|
int surfaceId = map.mazeData()._surfaceTypes[map._currentSurfaceId];
|
|
|
|
|
|
|
|
if (v != INVALID_CELL && map._currentSurfaceId &&
|
|
|
|
(map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, surfaceId + 36, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v = map.mazeLookup(Common::Point(party._mazePosition.x - 4, party._mazePosition.y + 4), 0xffff, 0);
|
|
|
|
if (v != INVALID_CELL && map._currentSurfaceId &&
|
|
|
|
(map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1,
|
|
|
|
map.mazeData()._surfaceTypes[map._currentSurfaceId] + 36,
|
|
|
|
Common::Point(232, 9));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle drawing surface sprites partially clipped at the left edge
|
|
|
|
for (int rowNum = 0, yp = 17, yDiff = 3; rowNum < MINIMAP_SIZE; ++rowNum, --yDiff, yp += 8) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x - 4, party._mazePosition.y + yDiff),
|
|
|
|
0, 0xffff);
|
|
|
|
|
|
|
|
if (v != INVALID_CELL && map._currentSurfaceId &&
|
|
|
|
(map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1,
|
|
|
|
map.mazeData()._surfaceTypes[map._currentSurfaceId] + 36,
|
|
|
|
Common::Point(232, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle drawing surface sprites partially clipped at the top edge
|
|
|
|
for (int colNum = 0, xp = 242, xDiff = -3; colNum < MINIMAP_SIZE; ++colNum, ++xDiff, xp += 8) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x + xDiff, party._mazePosition.y + 4),
|
|
|
|
0, 0xffff);
|
|
|
|
|
|
|
|
if (v != INVALID_CELL && map._currentSurfaceId &&
|
|
|
|
(map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1,
|
|
|
|
map.mazeData()._surfaceTypes[map._currentSurfaceId] + 36,
|
|
|
|
Common::Point(xp, 9));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
for (int idx = 0, xp = 237, yp = 60, xDiff = -3; idx < MINIMAP_SIZE;
|
|
|
|
++idx, ++xDiff, xp += 10, yp -= 8) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x - 4, party._mazePosition.y - 3 + idx),
|
|
|
|
12, 0xffff);
|
|
|
|
|
|
|
|
switch (v) {
|
|
|
|
case 1:
|
|
|
|
frame = 18;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
frame = 22;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 13:
|
|
|
|
frame = 16;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
case 8:
|
|
|
|
frame = 2;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
frame = 30;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
frame = 32;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
frame = 24;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
frame = 28;
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
frame = 14;
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
frame = frame2 + 4;
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
frame = 24;
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
frame = 26;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
frame = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame != -1 && (map._currentSteppedOn || party._wizardEyeActive))
|
|
|
|
map._tileSprites.draw(window1, frame, Common::Point(222, yp));
|
|
|
|
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x - 3 + idx, party._mazePosition.y + 4),
|
|
|
|
0);
|
|
|
|
|
|
|
|
switch (v) {
|
|
|
|
case 1:
|
|
|
|
frame = 19;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
frame = 35;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
frame = 23;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 13:
|
|
|
|
frame = 17;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
case 8:
|
|
|
|
frame = 3;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
frame = 31;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
frame = 33;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
frame = 21;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
frame = 29;
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
frame = 15;
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
frame = frame2 + 5;
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
frame = 25;
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
frame = 27;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
frame = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame != -1 && (map._currentSteppedOn || party._wizardEyeActive))
|
|
|
|
map._tileSprites.draw(window1, frame, Common::Point(xp, 4));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the front/back walls of cells in the minimap
|
|
|
|
for (int rowNum = 0, yp = 12, yDiff = 3; rowNum < MINIMAP_SIZE;
|
|
|
|
++rowNum, --yDiff, yp += 8) {
|
|
|
|
for (int colNum = 0, xp = 237, xDiff = -3; colNum < MINIMAP_SIZE;
|
|
|
|
++colNum, ++xDiff, xp += 10) {
|
|
|
|
if (colNum == 4 && rowNum == 4) {
|
|
|
|
// Center of the minimap. Draw the direction arrow
|
|
|
|
res._globalSprites.draw(window1, party._mazeDirection + 1,
|
|
|
|
Common::Point(272, 40));
|
|
|
|
}
|
|
|
|
|
|
|
|
v = map.mazeLookup(Common::Point(party._mazePosition.x + xDiff,
|
|
|
|
party._mazePosition.y + yDiff), 12, 0xffff);
|
|
|
|
switch (v) {
|
|
|
|
case 1:
|
|
|
|
frame = 18;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
frame = 22;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 13:
|
|
|
|
frame = 16;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
case 8:
|
|
|
|
frame = 2;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
frame = 30;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
frame = 32;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
frame = 20;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
frame = 28;
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
frame = 14;
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
frame = frame2 + 4;
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
frame = 24;
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
frame = 26;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
frame = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame != -1 && (map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, frame, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
|
|
|
|
v = map.mazeLookup(Common::Point(party._mazePosition.x + xDiff,
|
|
|
|
party._mazePosition.y + yDiff), 12, 0xffff);
|
|
|
|
switch (v) {
|
|
|
|
case 1:
|
|
|
|
frame = 19;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
frame = 35;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
frame = 23;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 13:
|
|
|
|
frame = 17;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
case 8:
|
|
|
|
frame = 3;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
frame = 31;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
frame = 33;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
frame = 21;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
frame = 29;
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
frame = 15;
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
frame = frame2 + 5;
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
frame = 25;
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
frame = 27;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
frame = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v == -1 && (map._currentSteppedOn || party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, frame, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the top of blocked/wall cells on the map
|
|
|
|
for (int rowNum = 0, yp = 12, yDiff = 3; rowNum < MINIMAP_SIZE; ++rowNum, yp += 8, --yDiff) {
|
|
|
|
for (int colNum = 0, xp = 237, xDiff = -3; colNum < MINIMAP_SIZE; ++colNum, xp += 10, ++xDiff) {
|
|
|
|
v = map.mazeLookup(
|
|
|
|
Common::Point(party._mazePosition.x + xDiff, party._mazePosition.y + yDiff),
|
|
|
|
0, 0xffff);
|
|
|
|
|
|
|
|
if (v == INVALID_CELL || (!map._currentSteppedOn && !party._wizardEyeActive)) {
|
|
|
|
map._tileSprites.draw(window1, 1, Common::Point(xp, yp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw outer rectangle around the automap
|
|
|
|
res._globalSprites.draw(window1, 6, Common::Point(223, 3));
|
|
|
|
party._wizardEyeActive = eyeActive;
|
|
|
|
}
|
|
|
|
|
2015-01-03 03:19:14 -10:00
|
|
|
} // End of namespace Xeen
|