mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-02 14:51:40 +00:00
473 lines
8.5 KiB
C++
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
|