aboutsummaryrefslogtreecommitdiff
path: root/engines/m4/dialogs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/m4/dialogs.cpp')
-rw-r--r--engines/m4/dialogs.cpp163
1 files changed, 141 insertions, 22 deletions
diff --git a/engines/m4/dialogs.cpp b/engines/m4/dialogs.cpp
index 2796fe4030..442c31f35d 100644
--- a/engines/m4/dialogs.cpp
+++ b/engines/m4/dialogs.cpp
@@ -35,6 +35,13 @@ static void strToUpper(char *s) {
}
}
+static void strToLower(char *s) {
+ while (*s) {
+ *s = tolower(*s);
+ ++s;
+ }
+}
+
const RGB8 DIALOG_PALETTE[8] = {
{0x80, 0x80, 0x80, 0xff}, {0x90, 0x90, 0x90, 0xff}, {0x70, 0x70, 0x70, 0xff}, {0x9c, 0x9c, 0x9c, 0xff},
{0x80, 0x80, 0x80, 0xff}, {0x90, 0x90, 0x90, 0xff}, {0xDC, 0xDC, 0xDC, 0xff}, {0x00, 0x00, 0x00, 0xff}
@@ -44,10 +51,16 @@ const RGB8 DIALOG_PALETTE[8] = {
const int DIALOG_SPACING = 1;
+/**
+ * Handles any dialog initialisation
+ */
void Dialog::initDialog() {
incLine();
}
+/**
+ * Adds a new line to the dialog output
+ */
void Dialog::incLine() {
_lineX = 0;
_widthX = 0;
@@ -56,6 +69,10 @@ void Dialog::incLine() {
assert(_lines.size() <= 20);
}
+/**
+ * Writes some text to the dialog output, taking care of word wrapping if the text size
+ * exceeds the dialog's width
+ */
void Dialog::writeChars(const char *srcLine) {
char wordStr[80];
char line[80];
@@ -124,6 +141,9 @@ void Dialog::writeChars(const char *srcLine) {
}
}
+/**
+ * Appends some text to the current dialog line
+ */
void Dialog::appendText(const char *line) {
_lineX += strlen(line);
_widthX += _vm->_font->getWidth(line, DIALOG_SPACING);
@@ -131,6 +151,9 @@ void Dialog::appendText(const char *line) {
strcat(_lines[_lines.size() - 1].data, line);
}
+/**
+ * Adds a line of text to the dialog lines list
+ */
void Dialog::addLine(const char *line, bool underlineP) {
if ((_widthX > 0) || (_lineX > 0))
incLine();
@@ -141,7 +164,7 @@ void Dialog::addLine(const char *line, bool underlineP) {
if ((lineWidth > _dialogWidth) || (lineLen >= _widthChars))
writeChars(line);
else {
- _lines[_lines.size() - 1].xp = (_dialogWidth - lineWidth) / 2;
+ _lines[_lines.size() - 1].xp = (_dialogWidth - 10 - lineWidth) / 2;
strcpy(_lines[_lines.size() - 1].data, line);
}
@@ -151,12 +174,97 @@ void Dialog::addLine(const char *line, bool underlineP) {
incLine();
}
+/**
+ * Adds a bar separation line to the dialog lines list
+ */
+void Dialog::addBarLine() {
+ if ((_widthX > 0) || (_lineX > 0))
+ incLine();
+
+ // Flag the line as being a bar separator
+ _lines[_lines.size() - 1].barLine = true;
+ incLine();
+}
+
+/**
+ * Retrieves a specified vocab entry
+ */
+void Dialog::getVocab(int vocabId, char **line) {
+ assert(vocabId > 0);
+ const char *vocabStr = _vm->_globals->getVocab(vocabId);
+ strcpy(*line, vocabStr);
+
+ if (_commandCase)
+ strToUpper(*line);
+ else
+ strToLower(*line);
+
+ // Move the string pointer to after the added string
+ while (!**line)
+ ++*line;
+}
+
+bool Dialog::handleNounSuffix(char *destP, int nounNum, const char *srcP) {
+ char srcLine[40];
+
+ // The next source character must be a colon in front of the first verb
+ if (*srcP != ':')
+ return false;
+
+ // Copy the remainder of the line into a temporary buffer to get the seperate verbs
+ strcpy(srcLine, ++srcP);
+ char *altP = strchr(srcLine, ':');
+ if (altP)
+ *altP = '\0';
+
+ if (*srcP != '\0') {
+ while (*srcP != ':') {
+ ++srcP;
+ if (!*srcP) break;
+ }
+ }
+
+ if (*srcP != '\0')
+ ++srcP;
+
+ //
+ char var_FC[40];
+ char tempLine[40];
+ strcpy(var_FC, srcP);
+ char *tmpP = &tempLine[0];
+ char *tmp2P = tmpP;
+
+ uint16 _vocabIds[2] = {1, 1}; // FIXME/TODO: Proper vocab ids
+ getVocab(_vocabIds[nounNum], &tmpP);
+
+ if ((*(tmpP - 1) != 'S') && (*(tmpP - 1) != 's')) {
+ // Singular object
+ tmpP = &var_FC[0];
+ } else if (!strcmp(tempLine, "a ")) {
+ // Pontially plural
+ char ch = tolower(*tmp2P);
+
+ if (!((ch > 'U') || ((ch != 'A') && (ch != 'E') && (ch != 'I') && (ch != 'O'))))
+ strcpy(tempLine, "an ");
+ }
+
+ strcpy(destP, tmpP);
+ return true;
+}
+
+/**
+ * Checks whether the start of an extracted command matches a specified given command constant
+ */
bool Dialog::matchCommand(const char *s1, const char *s2) {
- return strncmp(s1, s2, strlen(s2)) == 0;
+ bool result = scumm_strnicmp(s1, s2, strlen(s2)) == 0;
+ _commandCase = isupper(*s1);
+ return result;
}
Dialog::Dialog(M4Engine *vm, const char *msgData, const char *title): View(vm, Common::Rect(0, 0, 0, 0)) {
assert(msgData);
+ _vm->_font->setFont(FONT_INTERFACE_MADS);
+
const char *srcP = msgData;
bool skipLine = false;
bool initFlag = false;
@@ -172,6 +280,7 @@ Dialog::Dialog(M4Engine *vm, const char *msgData, const char *title): View(vm, C
_lineX = 0;
_widthX = 0;
_dialogWidth = 0;
+ _commandCase = false;
char dialogLine[256];
char cmdText[80];
@@ -226,7 +335,7 @@ Dialog::Dialog(M4Engine *vm, const char *msgData, const char *title): View(vm, C
if (id > 0) {
// Suffix provided - specifies the dialog width in number of chars
_widthChars = id * 2;
- _dialogWidth = id * (_vm->_font->getMaxWidth() + 1) + 10;
+ _dialogWidth = id * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
}
} else if (matchCommand(cmdText, "SENTENCE")) {
// Sentence command - loads the title into the line buffer
@@ -234,31 +343,45 @@ Dialog::Dialog(M4Engine *vm, const char *msgData, const char *title): View(vm, C
strToUpper(dialogLine);
lineP += strlen(dialogLine) + 1;
+ } else if (matchCommand(cmdText, "BAR")) {
+ // Adds a full-width line instead of normal text
+ addBarLine();
+
+ } else if (matchCommand(cmdText, "CENTER")) {
+ // Center command
+ skipLine = true;
+
} else if (matchCommand(cmdText, "CR")) {
// CR command
if (skipLine)
crFlag = true;
- else {
+ else if (!initFlag) {
initDialog();
+ initFlag = true;
}
+ } else if (matchCommand(cmdText, "NOUN1")) {
+ // Noun command 1
+ handleNounSuffix(lineP, 1, cmdText + 5);
+
+ } else if (matchCommand(cmdText, "NOUN1")) {
+ // Noun command 2
+ handleNounSuffix(lineP, 2, cmdText + 5);
+
+ } else if (matchCommand(cmdText, "VERB")) {
+ // Verb/vocab retrieval
+ int verbId = 1; // TODO: Get correct vocab
+ getVocab(verbId, &lineP);
+
} else if (matchCommand(cmdText, "UNDER")) {
// Underline command
underline = true;
} else if (matchCommand(cmdText, "ASK")) {
// doAsk();
- } else if (matchCommand(cmdText, "CENTER")) {
- // Center command
- skipLine = true;
- } else if (matchCommand(cmdText, "VERB")) {
- // Verb/vocab retrieval
- /*getVocab(); */
} else if (matchCommand(cmdText, "INDEX")) {
// Index command
_dialogIndex = atoi(cmdText + 5);
- } else if (matchCommand(cmdText, "NOUN")) {
- // Noun command
} else {
error("Unknown dialog command '%s' encountered", cmdText);
}
@@ -279,19 +402,13 @@ Dialog::~Dialog() {
}
void Dialog::draw() {
- _vm->_font->setFont(FONT_INTERFACE_MADS);
+ assert(_widthChars != 0);
// Set up the palette for this view
_palette = new RGBList(8, NULL);
_palette->setRange(0, 8, DIALOG_PALETTE);
_vm->_palette->addRange(_palette);
- // Validation
- if (_widthChars == 0) {
- warning("Dialog being shown without TITLE specified");
- _widthChars = 30;
- }
-
// Calculate bounds
int dlgWidth = _dialogWidth;
int dlgHeight = _lines.size() * (_vm->_font->getHeight() + 1) + 10;
@@ -338,10 +455,12 @@ void Dialog::draw() {
for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->getHeight() + 1) {
- if (_lines[lineCtr].xp == 0xff) {
- hLine(2, width() - 6, ((_vm->_font->getHeight() + 1) >> 1) + yp);
+ if (_lines[lineCtr].barLine) {
+ // Bar separation line
+ hLine(5, width() - 6, ((_vm->_font->getHeight() + 1) >> 1) + yp);
} else {
- Common::Point pt((_lines[lineCtr].xp & 0x7f) + 5, yp);
+ // Standard line
+ Common::Point pt(_lines[lineCtr].xp + 5, yp);
if (_lines[lineCtr].xp & 0x40)
++pt.y;