scummvm/engines/titanic/room_flags.cpp

532 lines
11 KiB
C++

/* 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 "titanic/room_flags.h"
#include "titanic/titanic.h"
namespace Titanic {
#define ELEVATOR_SHIFT 18
#define ELEVATOR_MASK 3
#define PASSENGER_CLASS_SHIFT 16
#define PASSENGER_CLASS_MASK 3
#define FLOOR_SHIFT 8
#define FLOOR_MASK 0xFF
#define ROOM_SHIFT 1
#define ROOM_MASK 0x7F
struct TransportFlagsEntry {
const char *const _roomName;
uint _roomFlags;
};
struct SuccUBusFlagsEntry {
const char *const _roomName;
uint _roomFlags;
uint _succubusNum;
};
#define TRANSPORT_ROOMS_SIZE 6
const TransportFlagsEntry TRANSPORT_ROOMS[TRANSPORT_ROOMS_SIZE] = {
{ "TopOfWell", 0xDF4D1 },
{ "Pellerator", 0xC95E9 },
{ "Dome", 0xAD171 },
{ "Lift", 0x96E45 },
{ "SGTLeisure", 0x5D3AD },
{ "ServiceElevator", 0x68797 }
};
#define SUCCUBUS_ROOMS_SIZE 17
const SuccUBusFlagsEntry SUCCUBUS_ROOMS[SUCCUBUS_ROOMS_SIZE] = {
{ "ParrotLobby", 0x1D0D9, 3 },
{ "SculptureChamber", 0x465FB, 2 },
{ "Bar", 0x0B3D97, 2 },
{ "EmbLobby", 0x0CC971, 3 },
{ "MoonEmbLobby", 0x0CC971, 3 },
{ "MusicRoom", 0x0F34DB, 2 },
{ "MusicRoomLobby", 0x0F34DB, 2 },
{ "Titania", 0x8A397, 3 },
{ "BottomOfWell", 0x59FAD, 3 },
{ "Arboretum", 0x4D6AF, 1 },
{ "PromenadeDeck", 0x79C45, 2 },
{ "1stClassRestaurant", 0x896B9, 1 },
{ "CreatorsChamber", 0x2F86D, 2 },
{ "CreatorsChamberOn", 0x2F86D, 2 },
{ "BilgeRoom", 0x3D94B, 3 },
{ "BilgeRoomWith", 0x3D94B, 3 },
{ "Bridge", 0x39FCB, 3 }
};
int CRoomFlags::getConditionally() const {
if (getRoomArea() != 5 || getRoomCategory() != 5)
return _data;
else
return 5;
}
bool CRoomFlags::isTransportRoom() const {
for (int idx = 0; idx < TRANSPORT_ROOMS_SIZE; ++idx) {
if (TRANSPORT_ROOMS[idx]._roomFlags == _data)
return true;
}
return false;
}
int CRoomFlags::getRoomCategory() const {
if (getRoomNum() != 0)
return false;
CRoomFlags tempFlags = _data;
tempFlags.setRoomBits(1);
return tempFlags.getRoomArea() != 5;
}
int CRoomFlags::getRoomArea() const {
if (isSuccUBusRoomFlags())
return 4;
if (!getBit0()) {
uint v3 = getFloorNum();
if (v3 <= 38) {
uint v4 = getRoomNum();
if (v4 <= 18) {
uint v6 = getElevatorNum();
if (v6 >= 1 && v6 <= 4) {
uint v7 = (int)getPassengerClassNum() - 1;
if (v7) {
uint v8 = v7 - 1;
if (v8) {
if (v8 == 1 && is28To38(v3) && (v6 & 1) && v4 >= 1)
return 3;
} else if (is20To27(v3)) {
if (v6 & 1) {
if (v4 >= 1 && v4 <= 3)
return 2;
} else if (v4 >= 1 && v4 <= 4) {
return 2;
}
}
} else if (is2To19(v3) && v4 >= 1 && v4 <= 3) {
return 1;
}
}
}
}
}
return 5;
}
CString CRoomFlags::getRoomDesc() const {
Strings &str = g_vm->_strings;
switch (getRoomArea()) {
case 1:
case 2:
case 3: {
CString result = getPassengerClassDesc();
result += ", ";
result += getFloorDesc();
result += ", ";
result += getElevatorDesc();
result += ", ";
result += getRoomNumDesc();
return result;
}
case 4:
switch (_data) {
case 0x1D0D9:
return str[THE_PARROT_LOBBY];
case 0x2F86D:
return str[THE_CREATORS_CHAMBER];
case 0x39FCB:
return str[THE_BRIDGE];
case 0x3D94B:
return str[THE_BILGE_ROOM];
case 0x465FB:
return str[THE_SCULPTURE_CHAMBER];
case 0x4D6AF:
return str[THE_ARBORETUM];
case 0x59FAD:
return str[THE_BOTTOM_OF_THE_WELL];
case 0x79C45:
return str[THE_PROMENADE_DECK];
case 0x896B9:
return str[RESTAURANT_1ST_CLASS];
case 0x8A397:
return str[TITANIAS_ROOM];
case 0xB3D97:
return str[THE_BAR];
case 0xCC971:
return str[THE_EMBARKATION_LOBBY];
case 0xF34DB:
return str[THE_MUSIC_ROOM];
default:
break;
}
return str[UNKNOWN_ROOM];
case 5:
if (isTransportRoom()) {
switch (_data) {
case 0x68797:
return str[THE_SERVICE_ELEVATOR];
case 0x5D3AD:
return str[SGT_LEISURE_LOUNGE];
case 0x96E45:
return str[THE_ELEVATOR];
case 0xAD171:
return str[THE_DOME];
case 0xC95E9:
return str[THE_PELLERATOR];
case 0xDF4D1:
return str[THE_TOP_OF_THE_WELL];
default:
break;
}
}
if (getRoomCategory() == 0) {
return str[NOWHERE_TO_GO];
} else {
CString result = getPassengerClassDesc();
result += ", ";
result += getFloorDesc();
return result;
}
break;
default:
break;
}
return str[UNKNOWN_ROOM];
}
void CRoomFlags::setElevatorBits(uint val) {
_data &= ~(ELEVATOR_MASK << ELEVATOR_SHIFT);
_data |= (val & ELEVATOR_MASK) << ELEVATOR_SHIFT;
}
uint CRoomFlags::getElevatorBits() const {
return (_data >> ELEVATOR_SHIFT) & ELEVATOR_MASK;
}
void CRoomFlags::setPassengerClassBits(uint val) {
_data &= ~(PASSENGER_CLASS_MASK << PASSENGER_CLASS_SHIFT);
_data |= (val & PASSENGER_CLASS_MASK) << PASSENGER_CLASS_SHIFT;
}
uint CRoomFlags::getPassengerClassBits() const {
return (_data >> PASSENGER_CLASS_SHIFT) & PASSENGER_CLASS_MASK;
}
CString CRoomFlags::getPassengerClassDesc() const {
PassengerClass classNum = getPassengerClassNum();
Strings &str = g_vm->_strings;
switch (classNum) {
case FIRST_CLASS:
return str[CLASS_1];
case SECOND_CLASS:
return str[CLASS_2];
case THIRD_CLASS:
return str[CLASS_3];
default:
return str[CLASS_NONE];
}
}
void CRoomFlags::setFloorBits(uint val) {
_data &= ~(FLOOR_MASK << FLOOR_SHIFT);
_data |= (val & FLOOR_MASK) << FLOOR_SHIFT;
}
uint CRoomFlags::getFloorBits() const {
return (_data >> FLOOR_SHIFT) & FLOOR_MASK;
}
uint CRoomFlags::decodeFloorBits(uint bits) const {
int base = 0;
int offset = bits & 0xF;
switch ((bits >> 4) & 0xF) {
case 9:
base = 0;
break;
case 0xD:
base = 10;
break;
case 0xE:
base = 20;
break;
case 0xF:
base = 30;
break;
default:
base = 40;
break;
}
return offset >= 10 ? 0 : base + offset;
}
void CRoomFlags::setFloorNum(uint floorNum) {
uint base = 0;
switch (floorNum / 10) {
case 0:
base = 0x90;
break;
case 1:
base = 0xD0;
case 2:
base = 0xE0;
case 3:
base = 0xF0;
break;
default:
break;
}
setFloorBits(base | (floorNum % 10));
}
uint CRoomFlags::getFloorNum() const {
return decodeFloorBits(getFloorBits());
}
void CRoomFlags::setRoomBits(uint roomBits) {
_data &= ~(ROOM_MASK << ROOM_SHIFT);
_data |= (roomBits & ROOM_MASK) << ROOM_SHIFT;
}
uint CRoomFlags::getRoomBits() const {
return (_data >> ROOM_SHIFT) & ROOM_MASK;
}
bool CRoomFlags::isSuccUBusRoomFlags() const {
for (int idx = 0; idx < SUCCUBUS_ROOMS_SIZE; ++idx) {
if (SUCCUBUS_ROOMS[idx]._roomFlags == _data)
return true;
}
return false;
}
bool CRoomFlags::getBit0() const {
return _data & 1;
}
uint CRoomFlags::getSpecialRoomFlags(const CString &roomName) {
for (int idx = 0; idx < SUCCUBUS_ROOMS_SIZE; ++idx) {
if (roomName == SUCCUBUS_ROOMS[idx]._roomName)
return SUCCUBUS_ROOMS[idx]._roomFlags;
}
for (int idx = 0; idx < TRANSPORT_ROOMS_SIZE; ++idx) {
if (roomName == TRANSPORT_ROOMS[idx]._roomName)
return TRANSPORT_ROOMS[idx]._roomFlags;
}
return 0;
}
uint CRoomFlags::getSuccUBusNum(const CString &roomName) const {
for (int idx = 0; idx < SUCCUBUS_ROOMS_SIZE; ++idx) {
if (roomName == SUCCUBUS_ROOMS[idx]._roomName)
return SUCCUBUS_ROOMS[idx]._succubusNum;
}
return 0;
}
CString CRoomFlags::getSuccUBusRoomName() const {
for (int idx = 0; idx < SUCCUBUS_ROOMS_SIZE; ++idx) {
if (SUCCUBUS_ROOMS[idx]._roomFlags == _data)
return SUCCUBUS_ROOMS[idx]._roomName;
}
return CString();
}
void CRoomFlags::changeClass(PassengerClass newClassNum) {
uint floorNum = getFloorNum();
uint roomNum = getRoomNum();
uint elevatorNum = getElevatorNum();
PassengerClass classNum = getPassengerClassNum();
uint v10, v11, v12, v13;
switch (classNum) {
case FIRST_CLASS:
v10 = 2;
v11 = 19;
v12 = 1;
v13 = 3;
break;
case SECOND_CLASS:
v10 = 20;
v11 = 27;
v12 = 1;
v13 = (elevatorNum & 1) ? 3 : 4;
break;
case THIRD_CLASS:
v10 = 28;
v11 = 38;
v12 = 1;
v13 = 18;
break;
default:
v10 = 0;
v11 = 0;
v12 = 0;
v13 = 0;
break;
}
// Perform action to change room or floor
switch (newClassNum) {
case FIRST_CLASS:
if (--roomNum < v12)
roomNum = v12;
break;
case SECOND_CLASS:
if (++roomNum > v13)
roomNum = v13;
break;
case THIRD_CLASS:
if (--floorNum < v10)
floorNum = v10;
break;
case UNCHECKED:
if (++floorNum > v11)
floorNum = v11;
default:
break;
}
// Set new floor and room
setFloorNum(floorNum);
setRoomBits(roomNum);
}
bool CRoomFlags::compareClassElevator(uint flags1, uint flags2) {
CRoomFlags f1(flags1);
CRoomFlags f2(flags2);
if (f1.getFloorNum() != f2.getFloorNum())
return false;
uint elev1 = f1.getElevatorNum();
uint elev2 = f2.getElevatorNum();
PassengerClass class1 = f1.getPassengerClassNum();
PassengerClass class2 = f2.getPassengerClassNum();
if (class1 == FIRST_CLASS || class1 == SECOND_CLASS) {
if (elev1 == 2)
elev1 = 1;
else if (elev1 == 4)
elev1 = 3;
}
if (class2 == FIRST_CLASS || class2 == SECOND_CLASS) {
if (elev2 == 2)
elev2 = 1;
else if (elev2 == 4)
elev2 = 3;
}
return elev1 == elev2;
}
bool CRoomFlags::compareLocation(uint flags1, uint flags2) {
CRoomFlags f1(flags1);
CRoomFlags f2(flags2);
return f1.getElevatorNum() == f2.getElevatorBits() &&
f1.getFloorNum() == f2.getFloorNum() &&
f1.getRoomNum() == f2.getRoomNum();
}
bool CRoomFlags::isTitania(uint flags1, uint flags2) {
return flags2 == 0x8A397;
}
void CRoomFlags::setRandomLocation(PassengerClass classNum, bool flag) {
uint minRoom, elevNum, maxRoom, maxFloor, minFloor;
do {
switch (classNum) {
case FIRST_CLASS:
minFloor = 2;
maxFloor = 19;
minRoom = 1;
maxRoom = 3;
elevNum = g_vm->getRandomNumber(flag ? 2 : 3);
break;
case SECOND_CLASS:
minFloor = 20;
maxFloor = 27;
elevNum = g_vm->getRandomNumber(flag ? 2 : 3);
minRoom = 1;
maxRoom = ((elevNum - 1) & 1) ? 3 : 4;
break;
case THIRD_CLASS:
minRoom = 1;
minFloor = 28;
maxFloor = 38;
maxRoom = 18;
elevNum = g_vm->getRandomNumber(1) ? 2 : 0;
break;
default:
return;
}
uint floorNum = minFloor + g_vm->getRandomNumber(maxFloor - minFloor);
uint roomNum = minRoom + g_vm->getRandomNumber(maxRoom - minRoom);
setElevatorBits(elevNum);
setRoomBits(roomNum);
setFloorNum(floorNum);
setPassengerClassBits(classNum);
} while (_data == 0x59706);
}
PassengerClass CRoomFlags::whatPassengerClass(int floorNum) {
if (is2To19(floorNum))
return FIRST_CLASS;
return is20To27(floorNum) ? SECOND_CLASS : THIRD_CLASS;
}
} // End of namespace Titanic