Initial commit
This commit is contained in:
412
engines/glk/comprehend/game_oo.cpp
Normal file
412
engines/glk/comprehend/game_oo.cpp
Normal file
@@ -0,0 +1,412 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/comprehend/game_oo.h"
|
||||
#include "glk/comprehend/comprehend.h"
|
||||
#include "glk/comprehend/draw_surface.h"
|
||||
#include "glk/comprehend/pics.h"
|
||||
#include "common/md5.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Comprehend {
|
||||
|
||||
enum OOToposRoomFlag {
|
||||
OO_ROOM_IN_SHIP = 1,
|
||||
OO_ROOM_FLAG_DARK = 2
|
||||
};
|
||||
|
||||
enum OOToposFlag {
|
||||
OO_FLAG_9 = 9,
|
||||
OO_FLAG_13 = 13,
|
||||
OO_FLAG_22 = 22,
|
||||
OO_BRIGHT_ROOM = 25,
|
||||
OO_FLAG_WEARING_GOGGLES = 27,
|
||||
OO_FLAG_FLASHLIGHT_ON = 39,
|
||||
OO_FLAG_43 = 43,
|
||||
OO_FLAG_44 = 44,
|
||||
OO_FLAG_SUFFICIENT_FUEL = 51,
|
||||
OO_FLAG_REVERSE_VIDEO = 53, // Effect of wearing goggles
|
||||
OO_FLAG_TOO_DARK = 55,
|
||||
OO_FLAG_TOO_BRIGHT = 56,
|
||||
OO_FLAG_58 = 58,
|
||||
OO_FLAG_59 = 59,
|
||||
OO_FLAG_READY_TO_DEPART = 60,
|
||||
OO_TRACTOR_BEAM = 71
|
||||
};
|
||||
|
||||
enum OOToposItem {
|
||||
ITEM_SERUM_VIAL = 39
|
||||
};
|
||||
|
||||
static const GameStrings OO_STRINGS = {
|
||||
EXTRA_STRING_TABLE(154)
|
||||
};
|
||||
|
||||
OOToposGame::OOToposGame() : ComprehendGameV2(), _restartMode(RESTART_IMMEDIATE),
|
||||
_noFloodfill(UNSET), _stringVal1(0), _stringVal2(0),
|
||||
_printComputerMsg(true), _shipNotWorking(false) {
|
||||
_gameDataFile = "g0";
|
||||
|
||||
// Extra strings are (annoyingly) stored in the game binary
|
||||
Common::File f;
|
||||
if (!f.open("novel.exe"))
|
||||
error("novel.exe is a required file");
|
||||
|
||||
Common::String md5 = Common::computeStreamMD5AsString(f, 1024);
|
||||
f.close();
|
||||
|
||||
if (md5 == "3fc2072f6996b17d2f21f0a92e53cdcc") {
|
||||
// DOS version from if-archive
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x16564, 0x17640));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x17702, 0x18600));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x186b2, 0x19b80));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x19c62, 0x1a590));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x1a634, 0x1b080));
|
||||
} else if (md5 == "e26858f2aaa9dcc28f468b07902813c5") {
|
||||
// DOS version from graphicsmagician.com
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x164c4, 0x175a0));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x17662, 0x18560));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x18612, 0x19ae0));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x19bc2, 0x1a4f0));
|
||||
_stringFiles.push_back(StringFile("NOVEL.EXE", 0x1a594, 0x1afe0));
|
||||
} else {
|
||||
error("Unrecognised novel.exe encountered");
|
||||
}
|
||||
|
||||
_locationGraphicFiles.push_back("RA");
|
||||
_locationGraphicFiles.push_back("RB");
|
||||
_locationGraphicFiles.push_back("RC");
|
||||
_locationGraphicFiles.push_back("RD");
|
||||
_locationGraphicFiles.push_back("RE");
|
||||
_itemGraphicFiles.push_back("OA");
|
||||
_itemGraphicFiles.push_back("OB");
|
||||
_itemGraphicFiles.push_back("OC");
|
||||
_itemGraphicFiles.push_back("OD");
|
||||
|
||||
_colorTable = 1;
|
||||
_gameStrings = &OO_STRINGS;
|
||||
_titleGraphicFile = "t0";
|
||||
}
|
||||
|
||||
void OOToposGame::beforeGame() {
|
||||
// Draw the title
|
||||
g_comprehend->drawPicture(TITLE_IMAGE);
|
||||
|
||||
// Print game information
|
||||
console_println("Story by Michael and Muffy Berlyn, graphics by Raim und Redlich and Brian Poff");
|
||||
console_println("IBM version by Jeffrey A. Jay. Copyright 1987 POLARWARE, Inc.");
|
||||
g_comprehend->readChar();
|
||||
|
||||
g_comprehend->glk_window_clear(g_comprehend->_bottomWindow);
|
||||
}
|
||||
|
||||
int OOToposGame::roomIsSpecial(uint room_index, uint *roomDescString) {
|
||||
Room *room = &_rooms[room_index];
|
||||
|
||||
// Is the room dark
|
||||
if ((room->_flags & OO_ROOM_FLAG_DARK) &&
|
||||
!(_flags[OO_FLAG_FLASHLIGHT_ON])) {
|
||||
if (roomDescString)
|
||||
*roomDescString = 0xb3;
|
||||
return ROOM_IS_DARK;
|
||||
}
|
||||
|
||||
// Is the room too bright
|
||||
if (room_index == OO_BRIGHT_ROOM &&
|
||||
!_flags[OO_FLAG_WEARING_GOGGLES]) {
|
||||
if (roomDescString)
|
||||
*roomDescString = 0x1c;
|
||||
return ROOM_IS_TOO_BRIGHT;
|
||||
}
|
||||
|
||||
return ROOM_IS_NORMAL;
|
||||
}
|
||||
|
||||
void OOToposGame::beforeTurn() {
|
||||
ComprehendGameV2::beforeTurn();
|
||||
|
||||
if (_flags[OO_FLAG_TOO_DARK]) {
|
||||
// Show placeholder room if room is too dark
|
||||
_currentRoom = 55;
|
||||
_updateFlags |= UPDATE_GRAPHICS;
|
||||
} else if (_flags[OO_FLAG_TOO_BRIGHT]) {
|
||||
// Show placeholder room if room is too bright
|
||||
_currentRoom = 54;
|
||||
_updateFlags |= UPDATE_GRAPHICS;
|
||||
} else {
|
||||
YesNo nff = _flags[OO_FLAG_REVERSE_VIDEO] ? YES : NO;
|
||||
|
||||
if (_noFloodfill != nff) {
|
||||
_noFloodfill = nff;
|
||||
_updateFlags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
|
||||
|
||||
if (_noFloodfill == YES)
|
||||
g_comprehend->_drawFlags |= IMAGEF_REVERSE;
|
||||
else
|
||||
g_comprehend->_drawFlags &= ~IMAGEF_REVERSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OOToposGame::beforePrompt() {
|
||||
// Handle the computer console if in front of it
|
||||
computerConsole();
|
||||
}
|
||||
|
||||
void OOToposGame::afterPrompt() {
|
||||
ComprehendGameV2::afterPrompt();
|
||||
|
||||
// WORKAROUND: Allow for the Apple 2 password in the DOS version
|
||||
if (!scumm_stricmp(_inputLine, "vug957a"))
|
||||
Common::strcpy_s(_inputLine, "tse957x");
|
||||
|
||||
if (_currentRoom != _currentRoomCopy)
|
||||
_updateFlags |= UPDATE_GRAPHICS;
|
||||
_currentRoom = _currentRoomCopy;
|
||||
}
|
||||
|
||||
void OOToposGame::handleSpecialOpcode() {
|
||||
switch (_specialOpcode) {
|
||||
case 1:
|
||||
// Update guard location
|
||||
randomizeGuardLocation();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
_restartMode = RESTART_IMMEDIATE;
|
||||
game_restart();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_restartMode = RESTART_WITH_MSG;
|
||||
game_restart();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
_restartMode = RESTART_WITHOUT_MSG;
|
||||
game_restart();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// Won the game
|
||||
g_comprehend->quitGame();
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// Save game
|
||||
game_save();
|
||||
break;
|
||||
|
||||
case 7:
|
||||
// Restore game
|
||||
game_restore();
|
||||
break;
|
||||
|
||||
case 8:
|
||||
// Computer response
|
||||
computerResponse();
|
||||
randomizeGuardLocation();
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// Checks the ship fuel
|
||||
checkShipFuel();
|
||||
randomizeGuardLocation();
|
||||
break;
|
||||
|
||||
case 10:
|
||||
// Checks whether the ship is working
|
||||
checkShipWorking();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool OOToposGame::handle_restart() {
|
||||
_ended = false;
|
||||
|
||||
if (_restartMode != RESTART_IMMEDIATE) {
|
||||
if (_restartMode == RESTART_WITH_MSG)
|
||||
console_println(stringLookup(_gameStrings->game_restart).c_str());
|
||||
|
||||
if (tolower(console_get_key()) != 'r') {
|
||||
g_comprehend->quitGame();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
loadGame();
|
||||
_updateFlags = UPDATE_ALL;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OOToposGame::synchronizeSave(Common::Serializer &s) {
|
||||
if (s.isSaving())
|
||||
_currentRoom = _currentRoomCopy;
|
||||
|
||||
ComprehendGameV2::synchronizeSave(s);
|
||||
|
||||
if (s.isLoading()) {
|
||||
_noFloodfill = UNSET;
|
||||
_currentRoomCopy = _currentRoom;
|
||||
|
||||
beforeTurn();
|
||||
}
|
||||
}
|
||||
|
||||
void OOToposGame::randomizeGuardLocation() {
|
||||
Item *item = get_item(22);
|
||||
if (_flags[OO_FLAG_13] && item->_room != _currentRoom) {
|
||||
if (getRandomNumber(255) > 128 && (_currentRoom == 3 || _currentRoom == 6))
|
||||
item->_room = _currentRoom;
|
||||
}
|
||||
}
|
||||
|
||||
void OOToposGame::computerConsole() {
|
||||
if (_currentRoom == 57) {
|
||||
if (!_flags[OO_FLAG_9]) {
|
||||
// Mission Code:
|
||||
console_println(_strings2[129].c_str());
|
||||
} else if (!_flags[OO_FLAG_58]) {
|
||||
// Welcome back! I was wondering if you would be returning
|
||||
console_println(_strings2[131].c_str());
|
||||
_flags[OO_FLAG_58] = true;
|
||||
_printComputerMsg = true;
|
||||
checkShipWorking();
|
||||
} else if (_flags[OO_FLAG_59]) {
|
||||
checkShipDepart();
|
||||
} else if (_flags[OO_FLAG_43]) {
|
||||
// We can reach Mealy Sukas with the fuel we have left
|
||||
console_println(_strings2[142].c_str());
|
||||
_flags[OO_FLAG_59] = true;
|
||||
|
||||
if (_flags[OO_FLAG_44])
|
||||
// The currency on Mealy Sukas is the 'frod'
|
||||
console_println(_strings2[144].c_str());
|
||||
else
|
||||
// Without evaluation data as to the current fuel prices
|
||||
console_println(_strings2[143].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OOToposGame::computerResponse() {
|
||||
console_println(_strings2[145].c_str());
|
||||
if (_flags[OO_FLAG_43])
|
||||
console_println(_strings2[144].c_str());
|
||||
else
|
||||
console_println(_strings2[152].c_str());
|
||||
}
|
||||
|
||||
void OOToposGame::checkShipWorking() {
|
||||
_stringVal1 = 164;
|
||||
_stringVal2 = 0;
|
||||
|
||||
// Iterate through the ship's flags
|
||||
for (int idx = 42; idx < 51; ++idx, ++_stringVal1) {
|
||||
if (!_flags[idx]) {
|
||||
if (!_stringVal2) {
|
||||
// The following components are not installed
|
||||
printComputerMsg(_strings2[132].c_str());
|
||||
_stringVal2 = 1;
|
||||
}
|
||||
|
||||
// Power Cylinder
|
||||
printComputerMsg(_strings[_stringVal1].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
_shipNotWorking = _stringVal2 != 0;
|
||||
if (!_shipNotWorking)
|
||||
// The ship is in working order
|
||||
printComputerMsg(_strings2[153].c_str());
|
||||
}
|
||||
|
||||
void OOToposGame::checkShipFuel() {
|
||||
const byte ITEMS[7] = { 24, 27, 28, 29, 30, 31, 32 };
|
||||
_variables[0x4b] = 0;
|
||||
_stringVal1 = 68;
|
||||
_stringVal2 = 0;
|
||||
|
||||
for (int idx = 168; idx < 175; ++idx, ++_stringVal1, ++_stringVal2) {
|
||||
if (_flags[idx]) {
|
||||
Item *item = get_item(ITEMS[_stringVal2] - 1);
|
||||
if (item->_room == ROOM_INVENTORY || (get_room(item->_room)->_flags & OO_ROOM_IN_SHIP) != 0) {
|
||||
Instruction varAdd(0x86, 0x4B, _stringVal1);
|
||||
execute_opcode(&varAdd, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Computer: "Our current evaluation...
|
||||
Instruction strReplace(0xC9, 0x4B);
|
||||
execute_opcode(&strReplace, nullptr, nullptr);
|
||||
printComputerMsg(_strings2[146].c_str());
|
||||
|
||||
FunctionState funcState;
|
||||
Instruction test(2, 75, 76);
|
||||
execute_opcode(&test, nullptr, nullptr);
|
||||
|
||||
if (funcState._testResult) {
|
||||
// Computer: "We should now have enough
|
||||
_flags[OO_FLAG_SUFFICIENT_FUEL] = true;
|
||||
printComputerMsg(_strings2[151].c_str());
|
||||
} else {
|
||||
_flags[OO_FLAG_SUFFICIENT_FUEL] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OOToposGame::checkShipDepart() {
|
||||
_printComputerMsg = false;
|
||||
checkShipWorking();
|
||||
checkShipFuel();
|
||||
_printComputerMsg = true;
|
||||
|
||||
if (!_shipNotWorking && _flags[OO_FLAG_SUFFICIENT_FUEL]) {
|
||||
Item *item = get_item(ITEM_SERUM_VIAL - 1);
|
||||
if (item->_room == ROOM_INVENTORY || (get_room(item->_room)->_flags & OO_ROOM_IN_SHIP) != 0) {
|
||||
if (!_flags[OO_TRACTOR_BEAM]) {
|
||||
// I detect a tractor beam
|
||||
console_println(_strings2[77].c_str());
|
||||
} else if (!_flags[OO_FLAG_READY_TO_DEPART]) {
|
||||
// All systems check. Ready to depart
|
||||
_flags[OO_FLAG_22] = true;
|
||||
console_println(_strings2[79].c_str());
|
||||
} else {
|
||||
// Please close the airlock
|
||||
console_println(_strings2[76].c_str());
|
||||
}
|
||||
} else {
|
||||
// The serum vial is not aboard the ship
|
||||
console_println(_strings2[78].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OOToposGame::printComputerMsg(const char *str) {
|
||||
if (_printComputerMsg)
|
||||
console_println(str);
|
||||
}
|
||||
|
||||
} // namespace Comprehend
|
||||
} // namespace Glk
|
||||
Reference in New Issue
Block a user