Files
scummvm-cursorfix/engines/bagel/spacebar/baglib/log_msg.cpp
2026-02-02 04:50:13 +01:00

1070 lines
26 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 "bagel/spacebar/baglib/log_msg.h"
#include "bagel/spacebar/baglib/button_object.h"
#include "bagel/spacebar/baglib/menu_dlg.h"
#include "bagel/spacebar/boflib/gui/movie.h"
#include "bagel/spacebar/baglib/master_win.h"
#include "bagel/spacebar/baglib/pda.h"
#include "bagel/spacebar/boflib/gfx/text.h"
#include "bagel/boflib/file_functions.h"
#include "bagel/boflib/log.h"
#include "bagel/boflib/sound.h"
namespace Bagel {
namespace SpaceBar {
CBagLog *CBagLog::_lastFloatPage;
#define LOG_BORDER (42)
#define LOG_Z_BORDER (84)
#define OVERRIDE_SMK "$SBARDIR\\BAR\\LOG\\OVERRIDE.SMK"
#define OVERRIDE_MOVIE "OVERRIDE_MOVIE"
CBagLog::CBagLog() : CBagStorageDevBmp() {
_queuedMsgList = new CBofList<CBagObject *>;
setCurFltPage(1);
}
CBagLog::~CBagLog() {
if (_queuedMsgList != nullptr) {
releaseMsg(); // Delete all master sprite objects
delete _queuedMsgList;
_queuedMsgList = nullptr;
}
}
CBofPoint CBagLog::arrangeFloater(CBofPoint &pos, CBagObject *bagObj) {
CBofPoint nextPos = pos;
// Things are so convoluted now, it is entirely possible that this method
// will get called on a storage device that is not the current one,
// so we will not require a backdrop.
if (getBackground() != nullptr) {
const CBofString sdevName = getName();
int borderSize = 0;
// Get this from script, allows individual log states to set border.
CBagVar *curVar = g_VarManager->getVariable("LOGBORDER");
if (curVar != nullptr) {
borderSize = curVar->getNumValue();
}
if (borderSize == 0) {
if (sdevName == "LOG_WLD") {
borderSize = LOG_BORDER;
} else if (sdevName == "LOGZ_WLD") {
borderSize = LOG_Z_BORDER;
}
}
// The log window has instructional text at the top and bottom, so
// create a floater rect to stay in the middle area
CBofRect floatRect = getBackground()->getRect();
floatRect.top += borderSize;
floatRect.bottom -= (borderSize / 2);
// calculate what page the whole object belongs on
int pageNum = ((nextPos.y + bagObj->getRect().height()) / floatRect.height());
// page numbering is 1-N
pageNum++;
setNumFloatPages(pageNum);
const int totalPages = getCurFltPage();
// Now position this object into the sdev
// if it fell on this page, show it
if (pageNum == totalPages) {
CBofPoint pagePos = nextPos;
// Bring the current page into view
pagePos.y = pagePos.y - ((pageNum - 1) * floatRect.height());
// Add in the border
pagePos.y += borderSize;
bagObj->setPosition(pagePos);
} else {
// Set the position to be off the sdev, so it won't show
bagObj->setPosition(CBofPoint(nextPos.x, getBackground()->height() + 1));
}
// Calculate the position for the next floater
// This will get sent back to the calling func
nextPos.x += bagObj->getRect().width();
// Check to see if the whole object can fit in width, if it can't wrap
if (nextPos.x > (floatRect.width() - bagObj->getRect().width())) {
nextPos.x = 0;
nextPos.y += bagObj->getRect().height();
}
}
_lastFloatPage = this;
return nextPos;
}
void CBagLog::arrangePages() {
// Don't bother if we don't have a floater worth arranging...
if (_lastFloatPage == nullptr) {
return;
}
CBagLog *lastFloat = _lastFloatPage;
// Get the up button and the down button...
CBagObject *upObj = lastFloat->getObject("LOGPAGUP");
CBagObject *downObj = lastFloat->getObject("LOGPAGDOWN");
if (upObj == nullptr || downObj == nullptr) {
return;
}
// Get current page number and last page number
const int lastPage = lastFloat->getNumFloatPages();
const int curPage = lastFloat->getCurFltPage();
const int firstPage = 1;
if (curPage > firstPage && curPage < lastPage) {
if (upObj->isAttached() == false) {
upObj->setActive();
upObj->attach();
}
if (downObj->isAttached() == false) {
downObj->setActive();
downObj->attach();
}
} else if (curPage == firstPage && curPage == lastPage) {
if (upObj->isAttached()) {
upObj->setActive(false);
upObj->detach();
}
if (downObj->isAttached()) {
downObj->setActive(false);
downObj->detach();
}
} else if (curPage <= firstPage) {
if (upObj->isAttached()) {
upObj->setActive(false);
upObj->detach();
}
if (downObj->isAttached() == false) {
downObj->setActive();
downObj->attach();
}
} else if (curPage >= lastPage) {
if (upObj->isAttached() == false) {
upObj->setActive();
upObj->attach();
}
if (downObj->isAttached()) {
downObj->setActive(false);
downObj->detach();
}
}
// Reinitialize
_lastFloatPage = nullptr;
}
int CBagLog::getCurFltPage() {
int nCurFltPage = 0;
// Read in their total nuggets from game
CBagVar *curVar = g_VarManager->getVariable("CUR_BAR_LOG_PAGE");
if (curVar) {
nCurFltPage = curVar->getNumValue();
}
return nCurFltPage;
}
void CBagLog::setCurFltPage(int fltPage) {
// Read in their total nuggets from game
CBagVar *curVar = g_VarManager->getVariable("CUR_BAR_LOG_PAGE");
if (curVar)
curVar->setValue(fltPage);
}
ErrorCode CBagLog::releaseMsg() {
const ErrorCode errorCode = ERR_NONE;
const int count = _queuedMsgList->getCount();
for (int i = 0; i < count; ++i) {
CBagObject *curObj = _queuedMsgList->removeHead();
// This is waiting to be played, mark it in memory as such, the fixes
// get uglier and uglier... since zoomed pda doesn't have a message light,
// only set this thing as waiting if we are in the regular PDA,
// otherwise, we get superfluous blinking of the PDA light.
CBofString devName = getName();
if (devName == "LOG_WLD") {
curObj->setMsgWaiting(true);
}
}
_queuedMsgList->removeAll();
return errorCode;
}
CBagObject *CBagLog::onNewUserObject(const CBofString &initStr) {
CBagTextObject *retLogObj = nullptr;
const CBofRect sdevRect = getRect();
const CBofString sdevName = getName();
int pointSize = 10;
if (sdevName == "LOG_WLD")
pointSize = FONT_8POINT;
else if (sdevName == "LOGZ_WLD")
pointSize = FONT_18POINT;
if (initStr == "MSG") {
retLogObj = (CBagTextObject *)new CBagLogMsg(sdevRect.width());
retLogObj->setInitInfo(initStr);
retLogObj->setPointSize(pointSize);
retLogObj->setColor(7);
retLogObj->setFloating();
} else if (initStr == "SUS") {
retLogObj = (CBagTextObject *)new CBagLogSuspect(sdevRect.width());
retLogObj->setInitInfo(initStr);
// Reduce point size on zoompda suspect list, make it
// all fit in the zoompda window.
if (pointSize == FONT_18POINT) {
pointSize -= 2;
}
retLogObj->setPointSize(pointSize);
retLogObj->setColor(7);
retLogObj->setFloating();
} else if (initStr == "CLU") {
retLogObj = (CBagTextObject *)new CBagLogClue(initStr, sdevRect.width(), pointSize);
} else if (initStr == "RES") {
retLogObj = (CBagTextObject *)new CBagLogResidue(sdevRect.width());
retLogObj->setInitInfo(initStr);
retLogObj->setPointSize(pointSize);
retLogObj->setColor(7);
retLogObj->setFloating();
}
return retLogObj;
}
bool CBagLog::removeFromMsgQueue(CBagObject *deletedObj) {
bool removedFl = false;
const int count = _queuedMsgList->getCount();
for (int i = 0; i < count; i++) {
CBagObject *curObj = _queuedMsgList->getNodeItem(i);
if (curObj == deletedObj) {
_queuedMsgList->remove(i);
removedFl = true;
break;
}
}
return removedFl;
}
ErrorCode CBagLog::activateLocalObject(CBagObject *bagObj) {
ErrorCode errorCode = ERR_NONE;
if (bagObj == nullptr)
return errorCode;
if (bagObj->isMsgWaiting() ||
(bagObj->getType() == USER_OBJ && (bagObj->getInitInfo() != nullptr) && (*bagObj->getInitInfo() == "MSG"))) {
_queuedMsgList->addToTail(bagObj);
// Since zoomed pda doesn't have a message light, only set this thing
// as waiting if we are in the regular PDA, otherwise, we get superfluous
// blinking of the PDA light.
const CBofString sdevName = getName();
if (sdevName == "LOG_WLD") {
bagObj->setMsgWaiting(true);
}
CBagStorageDev *pda = g_SDevManager->getStorageDevice("BPDA_WLD");
if (pda) {
CBagButtonObject *msgLight = (CBagButtonObject *)pda->getObject("MSGLIGHT");
if (msgLight) {
if (!msgLight->isAttached()) {
msgLight->setActive();
msgLight->attach();
}
// Make sure this guy always gets updated regardless of its
// dirty bit.
msgLight->setAlwaysUpdate(true);
msgLight->setAnimated(true);
}
}
} else {
errorCode = CBagStorageDev::activateLocalObject(bagObj);
}
return errorCode;
}
ErrorCode CBagLog::playMsgQueue() {
ErrorCode errorCode = ERR_NONE;
int count = _queuedMsgList->getCount();
// Walk through the message queue and play all the messages
// Only play one message per click on the pda message light.
if (count) {
CBagStorageDev *bpda = g_SDevManager->getStorageDevice("BPDA_WLD");
// If we're in a closeup, then don't play the message!
CBagStorageDev *sdev = CBagel::getBagApp()->getMasterWnd()->getCurrentStorageDev();
bool playMsgFl = true;
if ((sdev != nullptr) && sdev->isCIC()) {
playMsgFl = false;
char localBuffer[256];
CBofString smkName(localBuffer, 256);
smkName = OVERRIDE_SMK;
fixPathName(smkName);
CBagMovieObject *pMovie = (CBagMovieObject *)getObject(OVERRIDE_MOVIE);
if (pMovie) {
if (pMovie->isAttached() == false) {
pMovie->attach();
pMovie->setVisible();
}
pMovie->runObject();
}
}
// If we're playing a valid message (not the override message) then make sure
// we remove it from the queue.
if (playMsgFl) {
CBagObject *curObj = _queuedMsgList->removeHead();
if (curObj) {
CBofRect r = getRect();
errorCode = CBagStorageDev::activateLocalObject(curObj);
CBagMenu *objMenu = curObj->getMenuPtr();
if (objMenu)
objMenu->trackPopupMenu(0, 0, 0, CBofApp::getApp()->getMainWindow(), nullptr, &r);
curObj->runObject();
curObj->setMsgWaiting(false);
// Mark this guy as played...
((CBagLogMsg *)curObj)->setMsgPlayed(true);
}
// Although this might seem like a superfluous thing to do, but wait!
// it is not! the runObject call above can cause the number of objects in the
// message queue to be decremented.
count = _queuedMsgList->getCount();
// Don't stop message light from blinking unless we're down to zero
// messages in the queue.
if (bpda) {
CBagButtonObject *pMsgLight = (CBagButtonObject *)bpda->getObject("MSGLIGHT");
if (pMsgLight) {
if (count) {
pMsgLight->setAnimated(true);
} else {
pMsgLight->setAnimated(false);
}
}
}
}
}
return errorCode;
}
CBagLogResidue::CBagLogResidue(int sdevWidth) : CBagTextObject() {
_xObjType = USER_OBJ;
_sdevWidth = sdevWidth;
_bTitle = true;
}
void CBagLogResidue::setSize(const CBofSize &size) {
CBagTextObject::setSize(CBofSize(_sdevWidth, size.cy));
}
CBagLogMsg::CBagLogMsg(int sdevWidth) : CBagTextObject() {
_xObjType = USER_OBJ;
_sdevWidth = sdevWidth;
_bTitle = true;
// Start all messages off as not played
setMsgPlayed(false);
}
void CBagLogMsg::setSize(const CBofSize &size) {
CBagTextObject::setSize(CBofSize(_sdevWidth, size.cy));
}
ParseCodes CBagLogMsg::setInfo(CBagIfstream &istr) {
bool nObjectUpdated = false;
char localBuffer[256];
CBofString string1(localBuffer, 256);
char localBuffer2[256];
CBofString string2(localBuffer2, 256);
while (!istr.eof()) {
istr.eatWhite();
const char ch = (char)istr.peek();
switch (ch) {
//
// SENDEE FRANK - Sets the sendee name of the message to FRANK
//
case 'S': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("SENDEE")) {
istr.eatWhite();
getAlphaNumFromStream(istr, string2);
// Replace any underscores with spaces
string2.replaceChar('_', ' ');
setMsgSendee(string2);
nObjectUpdated = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
//
// TIME x- Sets the time of the message to xx:xx
//
case 'T': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("TIME")) {
istr.eatWhite();
const char nextCh = (char)istr.peek();
int msgTime = 0;
if (Common::isDigit(nextCh)) {
getIntFromStream(istr, msgTime);
} else {
getAlphaNumFromStream(istr, _msgTimeStr);
}
setMsgTime(msgTime);
nObjectUpdated = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
default: {
const ParseCodes parseCode = CBagObject::setInfo(istr);
if (parseCode == PARSING_DONE) {
return PARSING_DONE;
}
if (parseCode == UPDATED_OBJECT) {
nObjectUpdated = true;
} else { // rc==UNKNOWN_TOKEN
if (nObjectUpdated)
return UPDATED_OBJECT;
return UNKNOWN_TOKEN;
}
break;
}
}
}
return PARSING_DONE;
}
void CBagLogMsg::setProperty(const CBofString &prop, int val) {
if (!prop.find("TIME")) {
setMsgTime(val);
} else if (!prop.find("PLAYED")) {
setMsgPlayed(val);
}
CBagObject::setProperty(prop, val);
}
int CBagLogMsg::getProperty(const CBofString &prop) {
if (!prop.find("TIME"))
return getMsgTime();
// Played requires a 1 or a 0 (don't use true or false).
if (!prop.find("PLAYED")) {
const bool playedFl = getMsgPlayed();
return (playedFl ? 1 : 0);
}
return CBagObject::getProperty(prop);
}
ErrorCode CBagLogMsg::update(CBofBitmap *bmp, CBofPoint pt, CBofRect *srcRect, int maskColor) {
// We could use a variable here, translate it's value if that's the case.
if (getMsgTime() == 0) {
CBagVar *pVar = g_VarManager->getVariable(_msgTimeStr);
int nMsgTime = pVar->getNumValue();
setMsgTime(nMsgTime);
}
const int msgTime = getMsgTime();
const int hour = msgTime / 100;
const int minutes = msgTime - (hour * 100);
setFont(FONT_MONO);
setText(buildString("%-30s%02d:%02d", _msgSendee.getBuffer(), hour, minutes));
return CBagTextObject::update(bmp, pt, srcRect, maskColor);
}
ErrorCode CBagLogResidue::update(CBofBitmap *bmp, CBofPoint pt, CBofRect *srcRect, int maskColor) {
return CBagTextObject::update(bmp, pt, srcRect, maskColor);
}
CBagLogSuspect::CBagLogSuspect(int sdevWidth) : CBagTextObject() {
_xObjType = USER_OBJ;
_nSdevWidth = sdevWidth;
_bTitle = true;
// Need to save state info, set all to false.
CBagObject::setState(0);
}
ParseCodes CBagLogSuspect::setInfo(CBagIfstream &istr) {
bool objectUpdatedFl = false;
char localBuffer[256];
CBofString string1(localBuffer, 256);
char localBuffer2[256];
CBofString string2(localBuffer2, 256);
while (!istr.eof()) {
istr.eatWhite();
const char ch = (char)istr.peek();
switch (ch) {
//
// NAME FRANK - Sets the sendee name of the message to FRANK
//
case 'N': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("NAME")) {
istr.eatWhite();
getAlphaNumFromStream(istr, string2);
// Replace any underscores with spaces
string2.replaceChar('_', ' ');
setSusName(string2);
objectUpdatedFl = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
case 'S': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("SPECIES")) {
istr.eatWhite();
getAlphaNumFromStream(istr, string2);
// Replace any underscores with spaces
string2.replaceChar('_', ' ');
setSusSpecies(string2);
objectUpdatedFl = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
case 'R': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("ROOM")) {
istr.eatWhite();
getAlphaNumFromStream(istr, string2);
// Replace any underscores with spaces
string2.replaceChar('_', ' ');
setSusRoom(string2);
objectUpdatedFl = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
default: {
const ParseCodes parseCode = CBagObject::setInfo(istr);
if (parseCode == PARSING_DONE) {
return PARSING_DONE;
}
if (parseCode == UPDATED_OBJECT) {
objectUpdatedFl = true;
} else { // rc==UNKNOWN_TOKEN
if (objectUpdatedFl)
return UPDATED_OBJECT;
return UNKNOWN_TOKEN;
}
break;
}
}
}
return PARSING_DONE;
}
void CBagLogSuspect::setProperty(const CBofString &prop, int val) {
if (!prop.find("ROOM")) {
switch (val) {
case 1: // BAP
setSusRoom("Entry Vestibule");
break;
case 2: // BBP
setSusRoom("Howdy Saloon");
break;
case 4: // BDP
setSusRoom("Bar Area");
break;
case 5: // BEP
setSusRoom("Dance Floor");
break;
case 6: // BFP
setSusRoom("Dining Area");
break;
case 7: // BGP
setSusRoom("Gambling Hall");
break;
case 10: // BJP
setSusRoom("Kitchen");
break;
case 23: // BWP
setSusRoom("Outside Howdy Saloon");
break;
default:
break;
}
} else {
// Hack alert! If our value is 2, then this means toggle the boolean!!!
int hackVal = false;
if (val == 1)
hackVal = true;
if (val == 0)
hackVal = false;
if (val == 2)
hackVal = 2;
if (!prop.find("CHECKED"))
setSusChecked(hackVal == 2 ? !getSusChecked() : hackVal);
else if (!prop.find("VP"))
setSusVoicePrinted(hackVal == 2 ? !getSusVoicePrinted() : hackVal);
else if (!prop.find("RP"))
setSusResiduePrinted(hackVal == 2 ? !getSusResiduePrinted() : hackVal);
else
CBagObject::setProperty(prop, val);
}
}
int CBagLogSuspect::getProperty(const CBofString &prop) {
if (!prop.find("CHECKED"))
return getSusChecked();
if (!prop.find("VP"))
return getSusVoicePrinted();
if (!prop.find("RP"))
return getSusResiduePrinted();
return CBagObject::getProperty(prop);
}
void CBagLogSuspect::setSize(const CBofSize &size) {
CBagTextObject::setSize(CBofSize(_nSdevWidth, size.cy));
}
ErrorCode CBagLogSuspect::update(CBofBitmap *bmp, CBofPoint pt, CBofRect *srcRect, int maskColor) {
char susCheckedFl[256];
CBofString susCheckedString(susCheckedFl, 256);
// Remove all the references to the jamming and voice printer state
char voiceBuffer[256];
char residueBuffer[256];
CBofString voicePrintString(voiceBuffer, 256);
CBofString residuePrintString(residueBuffer, 256);
if (getSusChecked())
susCheckedString = "Y";
else
susCheckedString = "N";
if (getSusVoicePrinted())
voicePrintString = "OK";
else
voicePrintString = "?";
if (getSusResiduePrinted())
residuePrintString = "Y";
else
residuePrintString = "N";
setFont(FONT_MONO);
setText(buildString(" %-5.5s %-17.17s %-12.12s %-20.20s %-4.4s %-4.4s",
susCheckedString.getBuffer(),
_susName.getBuffer(),
_susSpecies.getBuffer(),
_susRoom.getBuffer(),
voicePrintString.getBuffer(),
residuePrintString.getBuffer()));
return CBagTextObject::update(bmp, pt, srcRect, maskColor);
}
// Energy detector objects, this should be pretty straightforward.
CBagEnergyDetectorObject::CBagEnergyDetectorObject() {
setFont(FONT_MONO); // Correct for spacing
setColor(7); // Make it white
setFloating(); // Is definitely floating
setHighlight(); // Is highlight
setTitle(); // As title
_textInitializedFl = false; // Not initialized yet
}
CBagEnergyDetectorObject::~CBagEnergyDetectorObject() {
}
ParseCodes CBagEnergyDetectorObject::setInfo(CBagIfstream &istr) {
bool objectUpdatedFl = false;
char localBuffer[256];
CBofString string1(localBuffer, 256);
char localBuffer2[256];
CBofString string2(localBuffer2, 256);
while (!istr.eof()) {
istr.eatWhite();
const char ch = (char)istr.peek();
switch (ch) {
//
// ZHAPS - NUMBER OF ZHAPS (ENERGY UNITS)
//
case 'Z': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("ZHAPS")) {
istr.eatWhite();
getAlphaNumFromStream(istr, string2);
_zhapsStr = string2;
objectUpdatedFl = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
//
// CAUSE - REASON FOR ENERGY BURST
//
case 'C': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("CAUSE")) {
istr.eatWhite();
getAlphaNumFromStream(istr, string2);
_causeStr = string2;
objectUpdatedFl = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
//
// TIME x- Sets the time of the message to xx:xx
//
case 'T': {
getAlphaNumFromStream(istr, string1);
if (!string1.find("TIME")) {
istr.eatWhite();
istr.peek();
getAlphaNumFromStream(istr, _energyTimeStr);
objectUpdatedFl = true;
} else {
putbackStringOnStream(istr, string1);
}
break;
}
//
// SIZE n - n point size of the txt
//
case 'S': {
char localBuffer3[256];
localBuffer3[0] = 0;
CBofString string3(localBuffer3, 256);
getAlphaNumFromStream(istr, string3);
if (!string3.find("SIZE")) {
istr.eatWhite();
int n;
getIntFromStream(istr, n);
setPointSize(n);
objectUpdatedFl = true;
} else {
putbackStringOnStream(istr, string3);
}
break;
}
default: {
const ParseCodes parseCode = CBagObject::setInfo(istr);
if (parseCode == PARSING_DONE) {
return PARSING_DONE;
}
if (parseCode == UPDATED_OBJECT) {
objectUpdatedFl = true;
} else { // rc==UNKNOWN_TOKEN
if (objectUpdatedFl)
return UPDATED_OBJECT;
return UNKNOWN_TOKEN;
}
break;
}
}
}
return PARSING_DONE;
}
ErrorCode CBagEnergyDetectorObject::update(CBofBitmap *bmp, CBofPoint pt, CBofRect *srcRect, int maskColor) {
// Don't draw until we're attached
if (isAttached() == false) {
return ERR_NONE;
}
return CBagTextObject::update(bmp, pt, srcRect, maskColor);
}
ErrorCode CBagEnergyDetectorObject::attach() {
assert(isValidObject(this));
int nMsgTime;
char localBuffer[256];
CBofString causeString(localBuffer, 256);
char zhapsBuffer[256];
CBofString zhapsString(zhapsBuffer, 256);
// We could use a variable here, translate it's value if that's the case.
CBagVar *curVar = g_VarManager->getVariable(_energyTimeStr);
if (curVar) {
nMsgTime = curVar->getNumValue();
} else {
nMsgTime = atoi(_energyTimeStr.getBuffer());
}
const int hour = nMsgTime / 100;
const int minute = nMsgTime - (hour * 100);
// Get the number of zhaps.
curVar = g_VarManager->getVariable(_zhapsStr);
if (curVar) {
zhapsString = curVar->getValue();
} else {
zhapsString = _zhapsStr;
}
// Get the cause
curVar = g_VarManager->getVariable(_causeStr);
if (curVar) {
causeString = curVar->getValue();
} else {
causeString = _causeStr;
}
// Replace any underscores with spaces
causeString.replaceChar('_', ' ');
CBofString cStr;
setPSText(&cStr);
setText(buildString("%02d:%02d %6.6s %s %-35.35s", hour, minute, zhapsString.getBuffer(), "zhaps", causeString.getBuffer()));
recalcTextRect(false);
return CBagObject::attach();
}
CBagLogClue::CBagLogClue(const CBofString &initStr, int sdevWidth, int pointSize) : CBagTextObject() {
_xObjType = USER_OBJ;
_sdevWidth = sdevWidth;
_bTitle = true;
_stringVar1 = nullptr;
_stringVar2 = nullptr;
_stringVar3 = nullptr;
_stringVar4 = nullptr;
setFont(FONT_MONO);
setInitInfo(initStr);
setPointSize(pointSize);
setColor(7);
setFloating();
}
ErrorCode CBagLogClue::attach() {
char szFormatStr[256];
char szClueStr[256];
CBofString cFormat(szFormatStr, 256);
assert(isValidObject(this));
const ErrorCode errorCode = CBagTextObject::attach();
// Get what is defined in the script.
cFormat = getFileName();
// Replace '$' with '%' (% is an illegal character embedded in a clue string).
cFormat.replaceChar('_', ' ');
cFormat.replaceChar('$', '%');
// Format the text appropriately.
Common::sprintf_s(szClueStr, cFormat.getBuffer(),
(_stringVar1 ? (const char *)_stringVar1->getValue() : (const char *)""),
(_stringVar2 ? (const char *)_stringVar2->getValue() : (const char *)""),
(_stringVar3 ? (const char *)_stringVar3->getValue() : (const char *)""),
(_stringVar4 ? (const char *)_stringVar4->getValue() : (const char *)""));
CBofString cStr(szClueStr);
setPSText(&cStr);
return errorCode;
}
ParseCodes CBagLogClue::setInfo(CBagIfstream &istr) {
bool nObjectUpdated = false;
char szLocalBuff[256];
CBofString sStr(szLocalBuff, 256);
while (!istr.eof()) {
istr.eatWhite();
const char ch = (char)istr.peek();
if (ch == 'S') {
//
// STRINGVAR - This will be a variable used to display some information that
// is contained in script in a clue statement.
//
getAlphaNumFromStream(istr, sStr);
if (!sStr.find("STRINGVAR")) {
istr.eatWhite();
getAlphaNumFromStream(istr, sStr);
CBagVar *pVar = g_VarManager->getVariable(sStr);
// The variable must have been found, if it wasn't, then
// complain violently.
if (pVar == nullptr) {
return UNKNOWN_TOKEN;
}
if (_stringVar1 == nullptr) {
_stringVar1 = pVar;
} else if (_stringVar2 == nullptr) {
_stringVar2 = pVar;
} else if (_stringVar3 == nullptr) {
_stringVar3 = pVar;
} else if (_stringVar4 == nullptr) {
_stringVar4 = pVar;
} else {
return UNKNOWN_TOKEN;
}
} else {
putbackStringOnStream(istr, sStr);
}
} else {
const ParseCodes parseCode = CBagObject::setInfo(istr);
if (parseCode == PARSING_DONE) {
return PARSING_DONE;
}
if (parseCode == UPDATED_OBJECT) {
nObjectUpdated = true;
} else { // rc==UNKNOWN_TOKEN
if (nObjectUpdated)
return UPDATED_OBJECT;
return UNKNOWN_TOKEN;
}
}
}
return PARSING_DONE;
}
ErrorCode CBagLogClue::update(CBofBitmap *pBmp, CBofPoint pt, CBofRect *srcRect, int maskColor) {
return CBagTextObject::update(pBmp, pt, srcRect, maskColor);
}
} // namespace SpaceBar
} // namespace Bagel