scummvm/engines/dreamweb/monitor.cpp
Thierry Crozat 4530dd23a5 DREAMWEB: Add localised commands in the network terminal
The original interpreter only used english commands in the terminal
even when playing one of the localised version (and even though
everything else in the terminal was localised). This adds the possibility
to either use the English commands or the localised ones.
Localized commands have been added for French, German (thanks to
SimSaw, who also proposed that idea) and Italian (thanks to Maff).
2013-02-26 22:17:42 +00:00

771 lines
16 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
namespace DreamWeb {
struct MonitorKeyEntry {
uint8 keyAssigned;
char username[12];
char password[12];
};
// New monitor key list
static MonitorKeyEntry monitorKeyEntries[4] = {
{ 1, "PUBLIC", "PUBLIC" },
{ 0, "RYAN", "BLACKDRAGON" },
{ 0, "LOUIS", "HENDRIX" },
{ 0, "BECKETT", "SEPTIMUS" }
};
void DreamWebEngine::useMon() {
_vars._lastTrigger = 0;
_currentFile[0] = 34;
memset(_currentFile+1, ' ', 12);
_currentFile[13] = 0;
monitorKeyEntries[0].keyAssigned = 1;
monitorKeyEntries[1].keyAssigned = 0;
monitorKeyEntries[2].keyAssigned = 0;
monitorKeyEntries[3].keyAssigned = 0;
createPanel();
showPanel();
showIcon();
drawFloor();
getRidOfAll();
loadGraphicsFile(_monitorGraphics, "G03"); // mon. graphic name
loadPersonal();
loadNews();
loadCart();
loadGraphicsFile(_monitorCharset, "C01"); // character set 2
printOuterMon();
initialMonCols();
printLogo();
workToScreen();
turnOnPower();
fadeUpYellows();
fadeUpMonFirst();
_monAdX = 76;
_monAdY = 141;
monMessage(1);
hangOnCurs(120);
monMessage(2);
randomAccess(60);
monMessage(3);
hangOnCurs(100);
printLogo();
scrollMonitor();
_bufferIn = 0;
_bufferOut = 0;
bool stop = false;
do {
uint16 oldMonadx = _monAdX;
uint16 oldMonady = _monAdY;
input();
_monAdX = oldMonadx;
_monAdY = oldMonady;
stop = execCommand();
if (_quitRequested) //TODO : Check why it crashes when put before the execcommand
break;
} while (!stop);
_monitorGraphics.clear();
_monitorCharset.clear();
_textFile1.clear();
_textFile2.clear();
_textFile3.clear();
_getBack = 1;
_sound->playChannel1(26);
_manIsOffScreen = 0;
restoreAll();
redrawMainScrn();
workToScreenM();
}
int DreamWebEngine::findCommand(const char* cmdList[]) {
// Loop over all commands in the list and see if we get a match
int cmd = 0;
while (cmdList[cmd] != NULL) {
const char *cmdStr = cmdList[cmd];
const char *inputStr = _inputLine;
// Compare the command, char by char, to see if we get a match.
// We only care about the prefix matching, though.
char inputChar, cmdChar;
do {
inputChar = *inputStr; inputStr += 2;
cmdChar = *cmdStr++;
if (cmdChar == 0)
return cmd;
} while (inputChar == cmdChar);
++cmd;
}
return -1;
}
bool DreamWebEngine::execCommand() {
static const char *comlist[] = {
"EXIT",
"HELP",
"LIST",
"READ",
"LOGON",
"KEYS",
NULL
};
static const char *comlistFR[] = {
"SORTIR",
"AIDE",
"LISTE",
"LIRE",
"CONNEXION",
"TOUCHES", // should be CLES but it is translated as TOUCHES in the game...
NULL
};
static const char *comlistDE[] = {
"ENDE",
"HILFE",
"LISTE",
"LIES",
"ZUGRIFF",
"DATEN",
NULL
};
static const char *comlistIT[] = {
"ESCI",
"AIUTO",
"ELENCA",
"LEGGI",
"ACCEDI",
"CHIAVI",
NULL
};
if (_inputLine[0] == 0) {
// No input
scrollMonitor();
return false;
}
int cmd = findCommand(comlist);
if (cmd == -1) {
// This did not match an english command. Try to find a localized one.
switch (getLanguage()) {
case Common::FR_FRA:
cmd = findCommand(comlistFR);
break;
case Common::DE_DEU:
cmd = findCommand(comlistDE);
break;
case Common::IT_ITA:
cmd = findCommand(comlistIT);
break;
case Common::ES_ESP:
default:
break;
}
}
// Execute the selected command
switch (cmd) {
case 0:
return true;
case 1:
monMessage(6);
// An extra addition in ScummVM: available commands.
// Since the reference to the game manual is a form of copy protection,
// this extra text is wrapped around the common copy protection check,
// to keep it faithful to the original, if requested.
if (!_copyProtection) {
switch (getLanguage()) {
case Common::FR_FRA:
monPrint("LES COMMANDES VALIDES SONT SORTIR, AIDE, LISTE, LIRE, CONNEXION, TOUCHES");
break;
case Common::DE_DEU:
monPrint("G\232LTIGE BEFEHLE SIND ENDE, HILFE, LISTE, LIES, ZUGRIFF, DATEN");
break;
case Common::IT_ITA:
monPrint("I COMANDI VALIDI SONO ESCI, AIUTO, ELENCA, LEGGI, ACCEDI, CHIAVI");
break;
case Common::ES_ESP:
default:
monPrint("VALID COMMANDS ARE EXIT, HELP, LIST, READ, LOGON, KEYS");
break;
}
}
break;
case 2:
dirCom();
break;
case 3:
read();
break;
case 4:
signOn();
break;
case 5:
showKeys();
break;
default:
netError();
break;
}
return false;
}
void DreamWebEngine::monitorLogo() {
if (_logoNum != _oldLogoNum) {
_oldLogoNum = _logoNum;
//fadeDownMon(); // FIXME: Commented out in ASM
printLogo();
printUnderMonitor();
workToScreen();
printLogo();
//fadeUpMon(); // FIXME: Commented out in ASM
printLogo();
_sound->playChannel1(26);
randomAccess(20);
} else {
printLogo();
}
}
void DreamWebEngine::printLogo() {
showFrame(_monitorGraphics, 56, 32, 0, 0);
showCurrentFile();
}
void DreamWebEngine::input() {
memset(_inputLine, 0, sizeof(_inputLine));
_curPos = 0;
printChar(_monitorCharset, _monAdX, _monAdY, '>', 0, NULL, NULL);
multiDump(_monAdX, _monAdY, 6, 8);
_monAdX += 6;
_cursLocX = _monAdX;
_cursLocY = _monAdY;
while (true) {
printCurs();
waitForVSync();
delCurs();
readKey();
if (_quitRequested)
return;
uint8 currentKey = _currentKey;
if (currentKey == 0)
continue;
if (currentKey == 13)
return;
if (currentKey == 8) {
if (_curPos > 0)
delChar();
continue;
}
if (_curPos == 28)
continue;
if ((currentKey == 32) && (_curPos == 0))
continue;
currentKey = makeCaps(currentKey);
_inputLine[_curPos * 2 + 0] = currentKey;
if (currentKey > 'Z')
continue;
multiGet(_mapStore + _curPos * 256, _monAdX, _monAdY, 8, 8);
uint8 charWidth;
printChar(_monitorCharset, _monAdX, _monAdY, currentKey, 0, &charWidth, NULL);
_inputLine[_curPos * 2 + 1] = charWidth;
_monAdX += charWidth;
++_curPos;
_cursLocX += charWidth;
}
}
byte DreamWebEngine::makeCaps(byte c) {
// TODO: Replace calls to this by toupper() ?
if (c >= 'a')
c -= 'a' - 'A'; // = 32
return c;
}
void DreamWebEngine::delChar() {
--_curPos;
_inputLine[_curPos * 2] = 0;
uint8 width = _inputLine[_curPos * 2 + 1];
_monAdX -= width;
_cursLocX -= width;
uint16 offset = _curPos;
offset = ((offset & 0x00ff) << 8) | ((offset & 0xff00) >> 8);
multiPut(_mapStore + offset, _monAdX, _monAdY, 8, 8);
multiDump(_monAdX, _monAdY, 8, 8);
}
void DreamWebEngine::printCurs() {
uint16 x = _cursLocX;
uint16 y = _cursLocY;
uint16 height;
if (_foreignRelease) {
y -= 3;
height = 11;
} else
height = 8;
multiGet(_textUnder, x, y, 6, height);
++_mainTimer;
if ((_mainTimer & 16) == 0)
showFrame(_monitorCharset, x, y, '/' - 32, 0);
multiDump(x - 6, y, 12, height);
}
void DreamWebEngine::delCurs() {
uint16 x = _cursLocX;
uint16 y = _cursLocY;
uint16 width = 6;
uint16 height;
if (_foreignRelease) {
y -= 3;
height = 11;
} else
height = 8;
multiPut(_textUnder, x, y, width, height);
multiDump(x, y, width, height);
}
void DreamWebEngine::scrollMonitor() {
printLogo();
printUnderMonitor();
workToScreen();
_sound->playChannel1(25);
}
void DreamWebEngine::showCurrentFile() {
uint16 x;
// Monitor Frame position differs between Floppy and CD version
if (isCD())
x = 178;
else
x = 199;
const char *currentFile = _currentFile + 1;
while (*currentFile) {
char c = *currentFile++;
c = modifyChar(c);
printChar(_monitorCharset, &x, 37, c, 0, NULL, NULL);
}
}
void DreamWebEngine::accessLightOn() {
showFrame(_monitorGraphics, 74, 182, 8, 0);
multiDump(74, 182, 12, 8);
}
void DreamWebEngine::accessLightOff() {
showFrame(_monitorGraphics, 74, 182, 7, 0);
multiDump(74, 182, 12, 8);
}
void DreamWebEngine::randomAccess(uint16 count) {
for (uint16 i = 0; i < count; ++i) {
waitForVSync();
waitForVSync();
uint16 v = _rnd.getRandomNumber(15);
if (v < 10)
accessLightOff();
else
accessLightOn();
}
accessLightOff();
}
void DreamWebEngine::monMessage(uint8 index) {
assert(index > 0);
const char *string = _textFile1._text;
for (uint8 i = 0; i < index; ++i) {
while (*string++ != '+') {
}
}
monPrint(string);
}
void DreamWebEngine::netError() {
monMessage(5);
scrollMonitor();
}
void DreamWebEngine::powerLightOn() {
showFrame(_monitorGraphics, 257+4, 182, 6, 0);
multiDump(257+4, 182, 12, 8);
}
void DreamWebEngine::powerLightOff() {
showFrame(_monitorGraphics, 257+4, 182, 5, 0);
multiDump(257+4, 182, 12, 8);
}
void DreamWebEngine::lockLightOn() {
showFrame(_monitorGraphics, 56, 182, 10, 0);
multiDump(58, 182, 12, 8);
}
void DreamWebEngine::lockLightOff() {
showFrame(_monitorGraphics, 56, 182, 9, 0);
multiDump(58, 182, 12, 8);
}
void DreamWebEngine::turnOnPower() {
for (uint i = 0; i < 3; ++i) {
powerLightOn();
hangOn(30);
powerLightOff();
hangOn(30);
}
powerLightOn();
}
void DreamWebEngine::printOuterMon() {
showFrame(_monitorGraphics, 40, 32, 1, 0);
showFrame(_monitorGraphics, 264, 32, 2, 0);
showFrame(_monitorGraphics, 40, 12, 3, 0);
showFrame(_monitorGraphics, 40, 164, 4, 0);
}
void DreamWebEngine::loadPersonal() {
if (_vars._location == 0 || _vars._location == 42)
loadTextFile(_textFile1, "T01"); // monitor file 1
else
loadTextFile(_textFile1, "T02"); // monitor file 2
}
void DreamWebEngine::loadNews() {
// textfile2 holds information accessible by anyone
if (_vars._newsItem == 0)
loadTextFile(_textFile2, "T10"); // monitor file 10
else if (_vars._newsItem == 1)
loadTextFile(_textFile2, "T11"); // monitor file 11
else if (_vars._newsItem == 2)
loadTextFile(_textFile2, "T12"); // monitor file 12
else
loadTextFile(_textFile2, "T13"); // monitor file 13
}
void DreamWebEngine::loadCart() {
byte cartridgeId = 0;
uint16 objectIndex = findSetObject("INTF");
uint16 cartridgeIndex = checkInside(objectIndex, 1);
if (cartridgeIndex != kNumexobjects)
cartridgeId = getExAd(cartridgeIndex)->objId[3] + 1;
if (cartridgeId == 0)
loadTextFile(_textFile3, "T20"); // monitor file 20
else if (cartridgeId == 1)
loadTextFile(_textFile3, "T21"); // monitor file 21
else if (cartridgeId == 2)
loadTextFile(_textFile3, "T22"); // monitor file 22
else if (cartridgeId == 3)
loadTextFile(_textFile3, "T23"); // monitor file 23
else
loadTextFile(_textFile3, "T24"); // monitor file 24
}
void DreamWebEngine::showKeys() {
randomAccess(10);
scrollMonitor();
monMessage(18);
for (int i = 0; i < 4; i++) {
if (monitorKeyEntries[i].keyAssigned)
monPrint(monitorKeyEntries[i].username);
}
scrollMonitor();
}
const char *DreamWebEngine::getKeyAndLogo(const char *foundString) {
byte newLogo = foundString[1] - 48;
byte keyNum = foundString[3] - 48;
if (monitorKeyEntries[keyNum].keyAssigned == 1) {
// Key OK
_logoNum = newLogo;
return foundString + 4;
} else {
monMessage(12); // "Access denied, key required -"
monPrint(monitorKeyEntries[keyNum].username);
scrollMonitor();
return 0;
}
}
const char *DreamWebEngine::searchForString(const char *topic, const char *text) {
char delim = *topic;
while (true) {
const char *s = topic;
int delimCount = 0;
char c;
do {
c = makeCaps(*text++);
if (c == '*' || (delim == '=' && c == 34))
return 0;
if (c == delim) {
delimCount++;
if (delimCount == 2)
return text;
}
} while (c == *s++);
}
}
void DreamWebEngine::dirCom() {
randomAccess(30);
const char *dirname = parser();
if (dirname[1]) {
dirFile(dirname);
return;
}
_logoNum = 0;
memcpy(_currentFile+1, "ROOT ", 12);
monitorLogo();
scrollMonitor();
monMessage(9);
searchForFiles(_textFile1._text);
searchForFiles(_textFile2._text);
searchForFiles(_textFile3._text);
scrollMonitor();
}
void DreamWebEngine::dirFile(const char *dirName) {
char topic[14];
memcpy(topic, dirName, 14);
topic[0] = 34;
const char *text = _textFile1._text;
const char *found = searchForString(topic, text);
if (!found) {
text = _textFile2._text;
found = searchForString(topic, text);
if (!found) {
text = _textFile3._text;
found = searchForString(topic, text);
}
}
if (found) {
found = getKeyAndLogo(found);
if (!found)
return; // not logged in
} else {
monMessage(7);
return;
}
// "keyok2"
memcpy(_currentFile+1, dirName+1, 12);
monitorLogo();
scrollMonitor();
monMessage(10);
while (true) {
byte curChar = *found++;
if (curChar == 34 || curChar == '*') {
// "endofdir2"
scrollMonitor();
return;
}
if (curChar == '=')
found = monPrint(found);
}
}
void DreamWebEngine::read() {
randomAccess(40);
const char *name = parser();
if (name[1] == 0) {
netError();
return;
}
const char *topic = _currentFile;
const char *text = _textFile1._text;
const char *found = searchForString(topic, text);
if (!found) {
text = _textFile2._text;
found = searchForString(topic, text);
if (!found) {
text = _textFile3._text;
found = searchForString(topic, text);
}
}
if (found) {
if (!getKeyAndLogo(found))
return;
} else {
monMessage(7);
return;
}
// "keyok1"
found = searchForString(name, found);
if (!found) {
_logoNum = _oldLogoNum;
monMessage(11);
return;
}
// "findtopictext"
monitorLogo();
scrollMonitor();
found++;
while (true) {
found = monPrint(found);
if (found[0] == 34 || found[0] == '=' || found[0] == '*') {
// "endoftopic"
scrollMonitor();
return;
}
processTrigger();
randomAccess(24);
}
}
void DreamWebEngine::signOn() {
const char *name = parser();
int8 foundIndex = -1;
Common::String inputLine = name + 1;
inputLine.trim();
for (byte i = 0; i < 4; i++) {
if (inputLine.equalsIgnoreCase(monitorKeyEntries[i].username)) {
// Check if the key has already been assigned
if (monitorKeyEntries[i].keyAssigned) {
monMessage(17);
return;
} else {
foundIndex = i;
break;
}
}
}
if (foundIndex == -1) {
monMessage(13);
return;
}
monMessage(15);
uint16 prevX = _monAdX;
uint16 prevY = _monAdY;
input(); // password input
_monAdX = prevX;
_monAdY = prevY;
// The entered line has zeroes in-between each character
uint32 len = strlen(monitorKeyEntries[foundIndex].password);
bool found = true;
for (uint32 i = 0; i < len; i++) {
if (monitorKeyEntries[foundIndex].password[i] != _inputLine[i * 2]) {
found = false;
break;
}
}
if (!found) {
scrollMonitor();
monMessage(16);
} else {
monMessage(14);
monPrint(monitorKeyEntries[foundIndex].username);
scrollMonitor();
monitorKeyEntries[foundIndex].keyAssigned = 1;
}
}
void DreamWebEngine::searchForFiles(const char *filesString) {
byte curChar;
while (true) {
curChar = filesString[0];
filesString++;
if (curChar == '*')
return; // "endofdir"
if (curChar == 34)
filesString = monPrint(filesString);
}
}
const char *DreamWebEngine::parser() {
char *output = _operand1;
memset(output, 0, sizeof(_operand1));
*output++ = '=';
const char *in = _inputLine;
uint8 c;
// skip command
do {
c = *in++;
in++;
if (!c)
return output;
} while (c != 32);
// skip spaces between command and operand
do {
c = *in++;
in++;
} while (c == 32);
// copy first operand
do {
*output++ = c;
c = *in++;
in++;
if (!c)
return _operand1;
} while (c != 32);
return _operand1;
}
} // End of namespace DreamWeb