473 lines
8.5 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 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 "immortal/immortal.h"
namespace Immortal {
/*
*
* ----- -----
* ----- Main Functions -----
* ----- -----
*
*/
void ImmortalEngine::miscInit() {
// In the source, this is where the seed for the rng is set, but we don't need to do that as we used _randomSource
_lastGauge = 0;
}
void ImmortalEngine::setRandomSeed() {}
void ImmortalEngine::getRandom() {}
/*
*
* ----- -----
* ----- Text Printing -----
* ----- -----
*
*/
// myFadeOut and myFadeIn are just RTS in the source, but they are called quite a lot
void ImmortalEngine::myFadeOut() {
return;
}
void ImmortalEngine::myFadeIn() {
return;
}
bool ImmortalEngine::textPrint(Str s, int n) {
_slowText = 0;
_formatted = 0;
_collumn = 0;
_row = 0;
playTextSong();
clearScreen();
return textSub(s, kTextFadeIn, n);
}
bool ImmortalEngine::textBeginning(Str s, int n) {
_slowText = 0;
_formatted = 0;
_collumn = 0;
_row = 0;
playTextSong();
clearScreen();
return textSub(s, kTextDontFadeIn, n);
}
void ImmortalEngine::textEnd(Str s, int n) {
textSub(s, kTextFadeIn, n);
}
void ImmortalEngine::textMiddle(Str s, int n) {
textSub(s, kTextDontFadeIn, n);
}
bool ImmortalEngine::textSub(Str s, FadeType f, int n) {
bool done = false;
char chr = 0;
int index = 0;
Common::String text = _strPtrs[s];
while (done == false) {
switch (text[index]) {
case '@':
case '=':
case char(0):
done = true;
// This is so the while loop can be a little cleaner
index--;
break;
case '&':
textCR();
break;
case '$':
printByte(n);
copyToScreen();
break;
case '_':
myFadeIn();
_slowText = 1;
break;
case '<':
_slowText = 0;
break;
case '>':
_formatted = 0;
break;
case '\\':
normalFadeOut();
break;
case '/':
slowFadeOut();
break;
case '|':
normalFadeIn();
break;
case '}':
_formatted = 1;
break;
case ']':
myDelay(40);
break;
case '{':
index++;
myDelay(text[index]);
break;
case '*':
textPageBreak(text, index);
break;
case '[':
textAutoPageBreak();
break;
case '#':
index++;
drawIcon(text[index]);
break;
case '~':
text = _strPtrs[(int)text[index + 1]];
index = -1;
break;
case '^':
center();
break;
case '%':
return yesNo();
case '+':
chr = 0x27;
break;
case '(':
chr = 0x60;
break;
default:
chr = text[index];
_collumn++;
if (chr == ' ') {
if (text[index + 1] == '~') {
text = _strPtrs[(int)text[index + 2]];
index = -1;
}
textDoSpace(text, index);
} else {
printChr(chr);
// We need this to show up now, not when the frame ends, so we have to update the screen here
copyToScreen();
if (_slowText != 0) {
myDelay(5);
switch (chr) {
case '?':
// fall through
case ':':
myDelay(13);
// fall through
case '.':
myDelay(13);
// fall through
case ',':
myDelay(13);
// fall through
default:
break;
}
}
}
break;
}
if (index == 0xFF) {
debug("String too long!");
return false;
}
index++;
}
chr = text[index];
if (f != kTextFadeIn) {
return false;
}
// If we need to display an 'OK' message
if (chr != '=') {
setPen(_penX, kYesNoY);
center();
drawIcon(kOkayFrame);
copyToScreen();
if (_slowText == 0) {
myFadeIn();
}
waitClick();
standardBeep();
textBounceDelay();
} else if (_slowText == 0) {
myFadeIn();
}
return false;
}
void ImmortalEngine::textCR() {
carriageReturn();
_row++;
_collumn = 0;
}
void ImmortalEngine::textPageBreak(Common::String s, int &index) {
_collumn = 0;
_row = 0;
if (_slowText == 0) {
myFadeIn();
}
index++;
myDelay((int) s[index]);
myFadeOut();
clearScreen();
if (_slowText != 0) {
myFadeIn();
}
}
void ImmortalEngine::textAutoPageBreak() {
_collumn = 0;
_row = 0;
if (_slowText == 0) {
myFadeIn();
}
myDelay(140);
myFadeOut();
clearScreen();
if (_slowText != 0) {
myFadeIn();
}
}
void ImmortalEngine::textDoSpace(Common::String s, int index) {
// If text is formatted, then check if the space between here and the end of the string will fit, if not, use a newline or pagebreak
if (_formatted != 0) {
bool foundEnd = false;
int start = index;
while (foundEnd == false) {
index++;
switch (s[index]) {
case '=':
// fall through
case '@':
// fall through
case '%':
// fall through
case '[':
// fall through
case ' ':
foundEnd = true;
// fall through
default:
break;
}
}
if (((index - start) + _collumn) >= kMaxCollumns) {
if (_row < kMaxRows) {
textCR();
} else {
textAutoPageBreak();
}
return;
}
}
printChr(' ');
}
void ImmortalEngine::textBounceDelay() {
Utilities::delay(7);
}
bool ImmortalEngine::yesNo() {
uint8 tyes[9] = {0, 1, 1, 1, 0, 0, 0, 0, 0};
getInput();
if (tyes[_heldDirection] == 0) {
noOn();
_lastYes = 0;
} else {
yesOn();
_lastYes = 1;
}
while (buttonPressed() || firePressed()) {
// If they have not pressed a button yet, we get the input after a delay
Utilities::delay(4);
getInput();
// And then if they have changed direction, we play a sound and update the direction and button gfx
if (tyes[_heldDirection] != _lastYes) {
_lastYes = tyes[_heldDirection];
standardBeep();
if (_lastYes == 0) {
noOn();
} else {
yesOn();
}
// Since we need this to show up right during the text sequence, we need to update the screen
copyToScreen();
}
}
standardBeep();
textBounceDelay();
// In source this is done weirdly so that it can use a result in A, except it never uses that result, so it's just weird.
return (!(bool) _lastYes);
}
void ImmortalEngine::noOn() {
// Draw the No icon as on, and the Yes icon as off
setPen(kYesNoX1, kYesNoY);
drawIcon(kNoIconOn);
setPen(kYesNoX2, kYesNoY);
drawIcon(kYesIconOff);
}
void ImmortalEngine::yesOn() {
// Draw the No icon as off, and the Yes icon as on
setPen(kYesNoX1, kYesNoY);
drawIcon(kNoIconOff);
setPen(kYesNoX2, kYesNoY);
drawIcon(kYesIconOn);
}
void ImmortalEngine::myDelay(int j) {
int type = 0;
// Update input
getInput();
// 0 = neither button held, 1 = one held, 2 = both held
if (_heldAction & kActionButton) {
type++;
}
if (_heldAction & kActionFire) {
type++;
}
do {
// If the button was *pressed* and not held, then skip any delay
if (!buttonPressed()) {
return;
}
if (!firePressed()) {
return;
}
// Otherwise, we delay by different amounts based on what's held down
switch (type) {
case 1:
Utilities::delay4(1);
break;
case 0:
Utilities::delay(1);
// fall through
case 2:
// fall through
default:
break;
}
j--;
} while (j != 0);
}
/*
*
* ----- -----
* ----- Input Related -----
* ----- -----
*
*/
bool ImmortalEngine::buttonPressed() {
// Returns false if the button was pressed, but not held or up
getInput();
if (_heldAction == kActionButton) {
// Zero just the button0held bit
_myButton &= (0xFF - kButton0Held);
} else if ((_myButton & kButton0Held) == 0) {
_myButton |= kButton0Held;
return false;
}
return true;
}
bool ImmortalEngine::firePressed() {
// Returns false if the button was pressed, but not held or up
getInput();
if (_heldAction == kActionFire) {
_myButton &= (0xFF - kButton1Held);
} else if ((_myButton & kButton1Held) == 0) {
_myButton |= kButton1Held;
return false;
}
return true;
}
/*
*
* ----- -----
* ----- Screen Related -----
* ----- -----
*
*/
/*
*
* ----- -----
* ----- Sound Related -----
* ----- -----
*
*/
void ImmortalEngine::standardBeep() {
//playNote(4, 5, 0x4C);
}
} // namespace Immortal