/* 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 . * */ #include "bagel/spacebar/baglib/storage_dev_win.h" #include "bagel/boflib/misc.h" #include "bagel/boflib/error.h" #include "bagel/spacebar/boflib/gfx/sprite.h" #include "bagel/boflib/event_loop.h" #include "bagel/spacebar/baglib/bagel.h" #include "bagel/spacebar/baglib/master_win.h" #include "bagel/spacebar/baglib/wield.h" #include "bagel/spacebar/baglib/menu_dlg.h" #include "bagel/spacebar/baglib/log_msg.h" #include "bagel/spacebar/baglib/event_sdev.h" // Objects up the yang #include "bagel/spacebar/baglib/area_object.h" #include "bagel/spacebar/baglib/bmp_object.h" #include "bagel/spacebar/baglib/button_object.h" #include "bagel/spacebar/baglib/character_object.h" #include "bagel/spacebar/baglib/command_object.h" #include "bagel/spacebar/baglib/expression_object.h" #include "bagel/spacebar/baglib/link_object.h" #include "bagel/spacebar/baglib/movie_object.h" #include "bagel/spacebar/baglib/sound_object.h" #include "bagel/spacebar/baglib/sprite_object.h" #include "bagel/spacebar/baglib/text_object.h" #include "bagel/spacebar/baglib/variable_object.h" #include "bagel/spacebar/baglib/thing_object.h" #include "bagel/spacebar/baglib/rp_object.h" #include "bagel/spacebar/baglib/dossier_object.h" #include "bagel/spacebar/baglib/pan_window.h" #include "bagel/bagel.h" #include "bagel/boflib/file_functions.h" namespace Bagel { namespace SpaceBar { // Globals (hacks) bool g_allowPaintFl = true; bool g_bAAOk = true; // Prevent attachActiveObjects() after a RUN LNK bool g_allowattachActiveObjectsFl = true; // Prevent attachActiveObjects() after a RUN LNK CBagStorageDevWnd *g_lastWindow = nullptr; extern bool g_pauseTimerFl; extern bool g_waitOKFl; // Statics CBagEventSDev *CBagStorageDevWnd::_pEvtSDev = nullptr; // Pointer to the EventSDev CBofPoint *CBagStorageDev::_xCursorLocation; CBofRect *CBagStorageDev::gRepaintRect; bool CBagStorageDev::_hidePdaFl = false; bool CBagStorageDev::_bHandledUpEvent = false; // Dirty object variables bool CBagStorageDev::_bPanPreFiltered = false; bool CBagStorageDev::_bDirtyAllObjects = false; bool CBagStorageDev::_bPreFilter = false; int CBagStorageDevManager::nSDevMngrs = 0; // Local globals static int gLastBackgroundUpdate = 0; #define kCursWidth 55 void CBagStorageDev::initialize() { g_allowPaintFl = true; g_bAAOk = true; g_allowattachActiveObjectsFl = true; g_lastWindow = nullptr; _xCursorLocation = new CBofPoint(); gRepaintRect = new CBofRect(); _hidePdaFl = false; _bHandledUpEvent = false; _bPanPreFiltered = false; _bDirtyAllObjects = false; _bPreFilter = false; gLastBackgroundUpdate = 0; } void CBagStorageDev::shutdown() { delete _xCursorLocation; delete gRepaintRect; } CBagStorageDev::CBagStorageDev() { _pLActiveObject = nullptr; // The last object selected on mouse down _pAssociateWnd = nullptr; // The associate window for attaching sounds _bForeignList = false; _pObjectList = new CBofList; _pExpressionList = nullptr; _nDiskID = 1; _bCloseup = false; _bCIC = false; // run object stuff _bFirstPaint = true; _nFloatPages = 0; _xSDevType = SDEV_UNDEF; _pBitmapFilter = nullptr; setCloseOnOpen(false); setExitOnEdge(0); setFilterId(0); setFadeId(0); // Default is this thing is not a customized sdev. setCustom(false); // Make sure all objects that are prefiltered are dirty setDirtyAllObjects(true); // Not sure what the hell is going on here... setLActivity(kMouseNONE); g_SDevManager->registerStorageDev(this); } CBagStorageDev::~CBagStorageDev() { if (!_bForeignList) { if (_pObjectList != nullptr) { // Delete all master sprite objects CBagStorageDev::releaseObjects(); delete _pObjectList; _pObjectList = nullptr; } if (_pExpressionList) { while (_pExpressionList->getCount()) { CBagExpression *pExp = _pExpressionList->removeHead(); delete pExp; } delete _pExpressionList; _pExpressionList = nullptr; } } // If the lists belong to this storage device g_SDevManager->unregisterStorageDev(this); if (CBagStorageDevWnd::_pEvtSDev == this) { CBagStorageDevWnd::_pEvtSDev = nullptr; } } void CBagStorageDev::setPosition(const CBofPoint &pos) { CBofRect OrigRect = getRect(); // Get the destination (screen) rect _cDestRect.setRect(pos.x, pos.y, pos.x + OrigRect.width() - 1, pos.y + OrigRect.height() - 1); } bool CBagStorageDev::contains(CBagObject *pObj, bool bActive) { int nCount = getObjectCount(); if (nCount != 0) { for (int i = 0; i < nCount; ++i) { if (pObj == getObjectByPos(i)) { if (bActive && (pObj->isActive())) return true; } } } return false; } ErrorCode CBagStorageDev::addObject(CBagObject *pObj, int /*nPos*/) { ErrorCode errorCode = ERR_NONE; // can't use a null pointer assert(pObj != nullptr); _pObjectList->addToTail(pObj); return errorCode; } ErrorCode CBagStorageDev::removeObject(CBagObject *pRObj) { ErrorCode errorCode = ERR_NONE; if (!_bForeignList) { int nCount = getObjectCount(); for (int i = 0; i < nCount; ++i) { if (pRObj == getObjectByPos(i)) { _pObjectList->remove(i); return errorCode; } } } return errorCode; } ErrorCode CBagStorageDev::activateLocalObject(CBagObject *pObj) { ErrorCode errCode = ERR_NONE; if (pObj != nullptr) { pObj->setLocal(); if (!pObj->isActive() && (!pObj->getExpression() || pObj->getExpression()->evaluate(pObj->isNegative()))) { pObj->setActive(); pObj->attach(); // Perform an update and arrange objects in the storage device if (g_allowattachActiveObjectsFl) { attachActiveObjects(); } } } else { errCode = ERR_FFIND; } return errCode; } ErrorCode CBagStorageDev::activateLocalObject(const CBofString &sName) { // can't use a empty string assert(!sName.isEmpty()); return activateLocalObject(getObject(sName)); } ErrorCode CBagStorageDev::deactivateLocalObject(CBagObject *pObj) { ErrorCode errorCode = ERR_NONE; if (pObj != nullptr) { pObj->setLocal(false); if (pObj->isActive()) { pObj->setActive(false); pObj->detach(); } } else { errorCode = ERR_FFIND; } return errorCode; } ErrorCode CBagStorageDev::deactivateLocalObject(const CBofString &sName) { // Can't use a empty string assert(!sName.isEmpty()); return deactivateLocalObject(getObject(sName)); } CBofPoint CBagStorageDev::arrangeFloater(CBofPoint &nPos, CBagObject *pObj) { CBofPoint NextPos = nPos; if (getBackground() != nullptr) { int nBackWidth = getBackground()->width(); int nBackHeight = getBackground()->height(); int nObjWidth = pObj->getRect().width(); int nObjHeight = pObj->getRect().height(); // Check to see if the whole object can fit in, if it can't wrap if (NextPos.x > (nBackWidth - nObjWidth)) { NextPos.x = 0; NextPos.y += pObj->getRect().height(); } pObj->setPosition(NextPos); // Always round this figure up... int nPageNum = ((NextPos.y + nObjHeight) / nBackHeight); if (((NextPos.y + nObjHeight) % nBackHeight) != 0) { nPageNum++; } setNumFloatPages(nPageNum); NextPos.x += pObj->getRect().width(); } return NextPos; } ErrorCode CBagStorageDev::attachActiveObjects() { ErrorCode errorCode = ERR_NONE; CBofPoint nArrangePos(0, 0); // Removed 5,5 padding CBagLog::initArrangePages(); int nCount = getObjectCount(); if (nCount != 0) { for (int i = 0; i < nCount; ++i) { if (g_engine->shouldQuit()) return ERR_NONE; CBagObject *pObj = getObjectByPos(i); if (pObj != nullptr) { if (pObj->isLocal() && (!pObj->getExpression() || pObj->getExpression()->evaluate(pObj->isNegative()))) { if (!pObj->isAttached()) { pObj->setActive(); pObj->attach(); } // If we have already painted the storage device once if (pObj->isImmediateRun()) { if (_bFirstPaint == false) { pObj->runObject(); if (pObj->getType() == LINK_OBJ) { break; } } } if (pObj->isFloating()) { nArrangePos = arrangeFloater(nArrangePos, pObj); } } else if (pObj->isAttached()) { if (pObj->getType() != SOUND_OBJ || !((CBagSoundObject *)pObj)->isPlaying()) { pObj->setActive(false); pObj->detach(); } } } else errorCode = ERR_FFIND; } } CBagLog::arrangePages(); return errorCode; } ErrorCode CBagStorageDev::detachActiveObjects() { ErrorCode errorCode = ERR_NONE; int nCount = getObjectCount(); if (nCount != 0) { for (int i = 0; i < nCount; ++i) { CBagObject *pObj = getObjectByPos(i); if (pObj != nullptr) { if (pObj->isAttached()) { // If this object is not removed from memory, then // make sure it is drawn next time it is activated. pObj->setDirty(true); pObj->detach(); } } else errorCode = ERR_FFIND; } } return errorCode; } ErrorCode CBagStorageDev::loadObjects() { ErrorCode errorCode = ERR_NONE; return errorCode; } ErrorCode CBagStorageDev::releaseObjects() { ErrorCode errorCode = ERR_NONE; int nCount = getObjectCount(); if (!_bForeignList) { if (nCount) { for (int i = 0; i < nCount; ++i) { CBagObject *pObj = _pObjectList->removeHead(); delete pObj; } } _pObjectList->removeAll(); } return errorCode; } void CBagStorageDev::setObjectList(CBofList *pOList, CBofList *pEList) { delete _pObjectList; _bForeignList = true; _pObjectList = pOList; _pExpressionList = pEList; } ErrorCode CBagStorageDev::paintStorageDevice(CBofWindow * /*pWnd*/, CBofBitmap *pBmp, CBofRect * /*pRect*/) { bool bMouseOverObj = false; int nCount = getObjectCount(); if (nCount) { CBofWindow *pWnd1 = CBagel::getBagApp()->getMasterWnd(); if (pWnd1) pWnd1->screenToClient(&*_xCursorLocation); for (int i = 0; i < nCount; ++i) { CBagObject *pObj = getObjectByPos(i); if (pObj->isAttached()) { CBofRect xBmpRect = pObj->getRect(); CBofPoint pt = xBmpRect.topLeft(); xBmpRect.offsetRect(-pt.x, -pt.y); if (pObj->isVisible()) { if (pBmp) { // Only update dirty objects... if (pObj->isDirty() || pObj->isAlwaysUpdate()) { pObj->update(pBmp, pt, &xBmpRect); } } } // if it is visible update it if (pObj->getRect().ptInRect(*_xCursorLocation)) { pObj->onMouseOver(0, *_xCursorLocation, this); bMouseOverObj = true; } // if on screen } // If the object is attached } // While a valid object } // if there is any valid objects if (!bMouseOverObj) noObjectsUnderMouse(); return ERR_NONE; } ErrorCode CBagStorageDev::onLActiveObject(uint32 /*nFlags*/, CBofPoint */*xPoint*/, void */*vpInfo*/) { return ERR_NONE; } ErrorCode CBagStorageDev::noObjectsUnderMouse() { return ERR_NONE; } void CBagStorageDev::onMouseMove(uint32 nFlags, CBofPoint *xPoint, void *vpInfo) { *_xCursorLocation = *xPoint; if (getLActiveObject() && getLActivity()) { getLActiveObject()->onMouseMove(nFlags, *xPoint, vpInfo); } } ErrorCode CBagStorageDev::onMouseOver(uint32 /*nFlags*/, CBofPoint */*xPoint*/, void *) { return ERR_NONE; } void CBagStorageDev::onLButtonDown(uint32 nFlags, CBofPoint *xPoint, void *vpInfo) { if (CBagPDA::isMoviePlaying() && CBagMasterWin::getActiveCursor() == 6) { return; } *_xCursorLocation = *xPoint; CBofPoint xCursorLocation = devPtToViewPort(*xPoint); setLActivity(kMouseNONE); CBagObject *pObj = getObject(xCursorLocation, true); if ((pObj != nullptr) && (pObj->isActive())) { pObj->onLButtonDown(nFlags, xPoint, vpInfo); setLActivity(kMouseDRAGGING); } setLActiveObject(pObj); } // TODO: This is a global, move it to the main class bool g_noMenuFl = false; void CBagStorageDev::onLButtonUp(uint32 nFlags, CBofPoint *xPoint, void *vpInfo) { char szLocalBuff[256]; CBofString sCurrSDev(szLocalBuff, 256); if (CBagPDA::isMoviePlaying() && CBagMasterWin::getActiveCursor() == 6) { return; } sCurrSDev = CBagel::getBagApp()->getMasterWnd()->getCurrentStorageDev()->getName(); *_xCursorLocation = *xPoint; CBofPoint xCursorLocation = devPtToViewPort(*xPoint); bool bUseWield = true; CBagObject *pObj = getObject(xCursorLocation, true); if (pObj != nullptr) { bUseWield = false; g_noMenuFl = false; if (pObj->isActive()) { pObj->onLButtonUp(nFlags, xPoint, vpInfo); if (g_noMenuFl) { g_noMenuFl = false; bUseWield = true; } setLActiveObject(pObj); } _bHandledUpEvent = true; } if (bUseWield) { CBagel *pApp = CBagel::getBagApp(); if (pApp != nullptr) { CBagPanWindow *pWin = (CBagPanWindow *)pApp->getMasterWnd(); if (pWin != nullptr) { if (pWin->_pWieldBmp != nullptr) { pObj = pWin->_pWieldBmp->getCurrObj(); if ((pObj != nullptr) && pObj->isActive()) { pObj->onLButtonUp(nFlags, xPoint, vpInfo); setLActiveObject(pObj); _bHandledUpEvent = true; } } } } } setLActivity(kMouseNONE); if (g_bAAOk && (sCurrSDev == (CBagel::getBagApp()->getMasterWnd()->getCurrentStorageDev()->getName()))) { attachActiveObjects(); } g_bAAOk = true; } ErrorCode CBagStorageDev::loadFile(const CBofString &sWldName) { char szLocalBuff[256]; CBofString sWldFileName(szLocalBuff, 256); sWldFileName = sWldName; fixPathName(sWldFileName); // Force buffer to be big enough so that the entire script // is pre-loaded int nLength = fileLength(sWldFileName); if (nLength <= 0) error("Unable to open or read %s", sWldFileName.getBuffer()); char *pBuf = (char *)bofAlloc(nLength); CBagIfstream fpInput(pBuf, nLength); CBofFile cFile; cFile.open(sWldFileName); cFile.read(pBuf, nLength); cFile.close(); CBagStorageDev::loadFileFromStream(fpInput, sWldFileName); bofFree(pBuf); // Add everything to the window return ERR_NONE; } ErrorCode CBagStorageDev::loadFileFromStream(CBagIfstream &fpInput, const CBofString &sWldName, bool bAttach) { char szWorkStr[256]; char szStr[256]; szWorkStr[0] = 0; szStr[0] = 0; CBofString sWorkStr(szWorkStr, 256); CBofString str(szStr, 256); CBagExpression *pActiveExpr = nullptr; CBofList bElseExprList; releaseObjects(); setName(sWldName); fpInput.eatWhite(); int ch = fpInput.getCh(); if (ch != SDEV_START_DELIM) { char szWarningMsg[256]; CBofString s(szWarningMsg, 256); s = "Warning: { expected: at start of storage device: "; s += sWldName; bofMessageBox(s.getBuffer(), "Warning"); fpInput.putBack(); } fpInput.eatWhite(); while (/*fpInput &&*/ !fpInput.eof() && !(fpInput.peek() == SDEV_END_DELIM)) { bool bOperSet = false; // Set if an operator was found bool bHoldActivation = false; // Set if the object should be held bool bRunActivation = true; // Set if the object should be run instantly on attach // Get Operator SET or HOLD or RUN; on none RUN is default getAlphaNumFromStream(fpInput, sWorkStr); if (sWorkStr.isEmpty()) { parseAlertBox(fpInput, "Error in line No Operator:", __FILE__, __LINE__); bOperSet = true; } if (!sWorkStr.find("SET")) { bRunActivation = false; bOperSet = true; } else if (!sWorkStr.find("HOLD")) { bHoldActivation = true; bOperSet = true; } else if (!sWorkStr.find("RUN")) { bOperSet = true; } fpInput.eatWhite(); if (bOperSet) { // If we are not doing the default RUN get next argument getAlphaNumFromStream(fpInput, sWorkStr); } if (sWorkStr.isEmpty()) { parseAlertBox(fpInput, "Error in line:", __FILE__, __LINE__); } fpInput.eatWhite(); CBagObject *pObj = nullptr; if (!sWorkStr.find("BKG")) { setInfo(fpInput); if (bAttach && attach()) { assert(false); } } else if (!sWorkStr.find("DISKID")) { fpInput.eatWhite(); ch = (char)fpInput.getCh(); if (ch == '=') { getAlphaNumFromStream(fpInput, str); fpInput.eatWhite(); _nDiskID = (uint16)atoi(str); if (fpInput.peek() == ';') { fpInput.getCh(); } } } else if (!sWorkStr.find("HELP")) { fpInput.eatWhite(); ch = (char)fpInput.getCh(); if (ch == '=') { getAlphaNumFromStream(fpInput, str); fpInput.eatWhite(); setHelpFilename(str); if (fpInput.peek() == ';') { fpInput.getCh(); } } } else if (!sWorkStr.find("ENDIF")) { if (bElseExprList.isEmpty()) { parseAlertBox(fpInput, "Error: ENDIF without IF", __FILE__, __LINE__); } else { bElseExprList.removeHead(); } if (pActiveExpr) { pActiveExpr = pActiveExpr->getPrevExpression(); } else { CBofString str2("Unexpected ENDIF:"); str2 += sWldName; parseAlertBox(fpInput, str2.getBuffer(), __FILE__, __LINE__); } } else if (!sWorkStr.find("IF")) { // Added a bPrevNeg to keep track of nested else-if's bool bPrevNeg = false; if (bElseExprList.getHead()) bPrevNeg = bElseExprList.getHead()->getNodeItem(); bElseExprList.addToHead((bool) false); // Added a bPrevNeg to keep track of nested else-if's CBagExpression *pExp = new CBagExpression(pActiveExpr, bPrevNeg); pExp->setInfo(fpInput); if (!_pExpressionList) _pExpressionList = new CBofList; _pExpressionList->addToTail(pExp); pActiveExpr = pExp; } else if (!sWorkStr.find("ELSE")) { if (bElseExprList.isEmpty()) { parseAlertBox(fpInput, "Error: ELSE without IF", __FILE__, __LINE__); } else { bElseExprList.removeHead(); bElseExprList.addToHead((bool) true); } } else if (!sWorkStr.find("BMP")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewSpriteObject(sWorkStr); } else if (!sWorkStr.find("SPR")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewSpriteObject(sWorkStr); } else if (!sWorkStr.find("LNK")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewLinkObject(sWorkStr); } else if (!sWorkStr.find("RPO")) { // Allow residue printing objects getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewRPObject(sWorkStr); } else if (!sWorkStr.find("EDO")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewEDObject(sWorkStr); } else if (!sWorkStr.find("DOS")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewDosObject(sWorkStr); } else if (!sWorkStr.find("SND")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewSoundObject(sWorkStr); } else if (!sWorkStr.find("BUT")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewButtonObject(sWorkStr); } else if (!sWorkStr.find("CHR")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewCharacterObject(sWorkStr); } else if (!sWorkStr.find("TNG")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewThingObject(sWorkStr); } else if (!sWorkStr.find("ARE")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewAreaObject(sWorkStr); } else if (!sWorkStr.find("VAR")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewVariableObject(sWorkStr); } else if (!sWorkStr.find("TXT")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewTextObject(sWorkStr); } else if (!sWorkStr.find("MOVIE")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewMovieObject(sWorkStr); } else if (!sWorkStr.find("COMMAND")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewCommandObject(sWorkStr); } else if (!sWorkStr.find("EXPR")) { getStringFromStream(fpInput, sWorkStr, "=", true); pObj = onNewExpressionObject(sWorkStr); } else if (!sWorkStr.find("REM") || !sWorkStr.find("//")) { char s[256]; fpInput.getCh(s, 256); } else { pObj = onNewUserObject(sWorkStr); } if (pObj != nullptr) { assert(CBofObject::isValidObject(pObj)); if (!bElseExprList.isEmpty() && bElseExprList[0]) { pObj->setNegative(); } else if (pActiveExpr && pActiveExpr->isNegative()) { // If there is an active expression that is negative // i.e if NOT( blah blah blah) pObj->setNegative(); } // Determine if the object is an active object in this world if (!bHoldActivation) { pObj->setLocal(); if (!pActiveExpr || pActiveExpr->evaluate(pObj->isNegative())) { pObj->setActive(); } } if (bRunActivation) { pObj->setImmediateRun(); } pObj->setInfo(fpInput); pObj->setExpression(pActiveExpr); addObject(pObj); } fpInput.eatWhite(); } // While not eof if (fpInput.peek() == SDEV_END_DELIM) fpInput.getCh(); fpInput.eatWhite(); if (pActiveExpr) { CBofString str2("Mismatch in IF/ENDIF:"); str2 += sWldName; parseAlertBox(fpInput, str2.getBuffer(), __FILE__, __LINE__); return ERR_UNKNOWN; } if (bAttach) return attachActiveObjects(); // Add everything to the window return ERR_NONE; } int CBagStorageDev::getObjectCount() { if (_pObjectList != nullptr) { return _pObjectList->getCount(); } return 0; } CBagObject *CBagStorageDev::getObjectByPos(int nIndex) { assert(_pObjectList != nullptr); assert((nIndex >= 0) && (nIndex < _pObjectList->getCount())); return _pObjectList->getNodeItem(nIndex); } CBagObject *CBagStorageDev::getObject(int nRefId, bool bActiveOnly) { assert(_pObjectList != nullptr); int nListLen = _pObjectList->getCount(); for (int i = 0; i < nListLen; ++i) { CBagObject *pObj = getObjectByPos(i); if ((pObj->getRefId() == nRefId) && (!bActiveOnly || (pObj->isActive() && pObj->isAttached()))) return pObj; } return nullptr; } CBagObject *CBagStorageDev::getObject(const CBofString &sName, bool bActiveOnly) { assert(_pObjectList != nullptr); CBagObject *pObjFound = nullptr; CBofListNode *pNode = _pObjectList->getHead(); while (pNode != nullptr) { CBagObject *pObj = pNode->getNodeItem(); if (pObj->getRefName().compare(sName) == 0) { pObjFound = pObj; break; } pNode = pNode->_pNext; } if (bActiveOnly && (pObjFound != nullptr) && !pObjFound->isActive()) pObjFound = nullptr; return pObjFound; } CBagObject *CBagStorageDev::getObjectByType(const CBofString &sType, bool bActiveOnly) { assert(_pObjectList != nullptr); int nListLen = _pObjectList->getCount(); for (int i = 0; i < nListLen; ++i) { CBagObject *pObj = getObjectByPos(i); if (bActiveOnly) { if (pObj->isActive() && !getStringTypeOfObject(pObj->getType()).find(sType)) return pObj; } else if (!getStringTypeOfObject(pObj->getType()).find(sType)) return pObj; } return nullptr; } CBagObject *CBagStorageDev::getObject(const CBofPoint &xPoint, bool bActiveOnly) { int nCount = getObjectCount(); // Resolve in reverse order since the last painted is on top if (nCount != 0) { for (int i = nCount - 1; i >= 0; --i) { CBagObject *pObj = getObjectByPos(i); if (pObj->isInside(xPoint) && (!bActiveOnly || (pObj->isActive() && pObj->isAttached()))) return pObj; } } return nullptr; } ParseCodes CBagStorageDev::setInfo(CBagIfstream &fpInput) { char szStr[256]; szStr[0] = 0; CBofString str(szStr, 256); fpInput.eatWhite(); char ch = (char)fpInput.getCh(); if (ch == '=') { getAlphaNumFromStream(fpInput, str); fpInput.eatWhite(); fixPathName(str); _sBackgroundName = str; if (fpInput.peek() == ';') { fpInput.getCh(); } } return PARSING_DONE; } ErrorCode CBagStorageDev::attach() { // Assume no error ErrorCode errorCode = ERR_NONE; _bFirstPaint = true; if (!_sBackgroundName.isEmpty()) { CBofBitmap *pBmp = new CBofBitmap(_sBackgroundName); if (!pBmp->errorOccurred()) { setBackground(pBmp); errorCode = attachActiveObjects(); } else { errorCode = ERR_FOPEN; } } return errorCode; } ErrorCode CBagStorageDev::detach() { // Must force people to not use a bad App's palette CBofApp::getApp()->setPalette(nullptr); setBackground(nullptr); // Notify the main window that we need to redraw the background filter. CBagStorageDevWnd *pMainWin = (CBagel::getBagApp()->getMasterWnd()->getCurrentStorageDev()); if (pMainWin != nullptr) { ((CBagPanWindow *)pMainWin)->setPreFilterPan(true); } return detachActiveObjects(); } ErrorCode CBagStorageDev::close() { return ERR_NONE; } CBagObject *CBagStorageDev::onNewSpriteObject(const CBofString &) { return new CBagSpriteObject(); } CBagObject *CBagStorageDev::onNewBitmapObject(const CBofString &) { return new CBagBmpObject(); } CBagObject *CBagStorageDev::onNewLinkObject(const CBofString &) { return new CBagLinkObject(); } CBagObject *CBagStorageDev::onNewRPObject(const CBofString &) { return new CBagRPObject(); } CBagObject *CBagStorageDev::onNewEDObject(const CBofString &) { return new CBagEnergyDetectorObject(); } CBagObject *CBagStorageDev::onNewDosObject(const CBofString &) { return new CBagDossierObject(); } CBagObject *CBagStorageDev::onNewTextObject(const CBofString &) { return new CBagTextObject(); } CBagObject *CBagStorageDev::onNewSoundObject(const CBofString &) { return new CBagSoundObject(); } CBagObject *CBagStorageDev::onNewButtonObject(const CBofString &) { return new CBagButtonObject(); } CBagObject *CBagStorageDev::onNewCharacterObject(const CBofString &) { return new CBagCharacterObject(); } CBagObject *CBagStorageDev::onNewThingObject(const CBofString &) { return new CBagThingObject(); } CBagObject *CBagStorageDev::onNewMovieObject(const CBofString &) { return new CBagMovieObject(); } CBagObject *CBagStorageDev::onNewCommandObject(const CBofString &) { return new CBagCommandObject(); } CBagObject *CBagStorageDev::onNewAreaObject(const CBofString &) { return new CBagAreaObject(); } CBagObject *CBagStorageDev::onNewExpressionObject(const CBofString &) { return new CBagExpressionObject(); } CBagObject *CBagStorageDev::onNewVariableObject(const CBofString &) { return new CBagVariableObject(); } CBagObject *CBagStorageDev::onNewUserObject(const CBofString &sInit) { char szLocalBuff[256]; CBofString s(szLocalBuff, 256); s = sInit; bofMessageBox(s.getBuffer(), "Could not find object type"); return nullptr; } void CBagStorageDev::onSetFilter(bool (*filterFunction)(uint16 nFilterId, CBofBitmap *, CBofRect *)) { _pBitmapFilter = filterFunction; } FilterFunction CBagStorageDev::getFilter() { return _pBitmapFilter; } ErrorCode CBagStorageDev::preFilter(CBofBitmap *pBmp, CBofRect *pRect, CBofList *pList) { if (pBmp != nullptr) { // If we are not dirtying all the objects, then only fill up the viewport. CBofRect viewPortRect(80, 10, 559, 369); CBofRect *fillRect; if (getDirtyAllObjects()) { fillRect = pRect; } else { fillRect = &viewPortRect; } pBmp->fillRect(fillRect, 0); } // Let pda know that we've been prefiltered setPreFiltered(true); if (getDirtyAllObjects()) { makeListDirty(_pObjectList); makeListDirty(pList); } else { setDirtyAllObjects(true); } return ERR_NONE; } void CBagStorageDev::makeListDirty(CBofList *pList) { if (pList) { int nCount = pList->getCount(); if (nCount != 0) { for (int i = 0; i < nCount; ++i) { CBagObject *pObj = pList->getNodeItem(i); pObj->setDirty(true); } } } } /***************************************************************************** * * CBagStorageDevWnd - * * *****************************************************************************/ CBagStorageDevWnd::CBagStorageDevWnd() : CBofWindow() { setOnUpdate(true); setCloseOnOpen(false); _pWorkBmp = nullptr; // Set a default help file for when there is not one specified _sHelpFileName = "$SBARDIR\\GENERAL\\RULES\\DEFAULT.TXT"; fixPathName(_sHelpFileName); _xSDevType = SDEV_WND; } CBagStorageDevWnd::~CBagStorageDevWnd() { assert(isValidObject(this)); CBagStorageDevWnd::killWorkBmp(); } ErrorCode CBagStorageDevWnd::attach() { char szLocalBuff[256]; CBofString s(szLocalBuff, 256); s = getName(); if (!getBackgroundName().isEmpty()) { // This should actually be moved to sbarapp, but the load file will then // need to be removed from the constructor. //CBofApp::getApp()->setMainWindow(this); // Associate this window with callbacks so that any public member function can // be accessed by objects inserted into this class. setAssociateWnd(this); CBofBitmap *pBmp = new CBofBitmap(getBackgroundName()); if ((pBmp->height() <= 0) || (pBmp->width() <= 0)) { reportError(ERR_FOPEN, "BarComputer Background Opened Failed"); } else { setBackground(pBmp); // Set the bagel crap CBofPalette *pPalette = pBmp->getPalette(); CBofApp::getApp()->setPalette(pPalette); CBofSprite::openLibrary(pPalette); CBofRect r = pBmp->getRect(); if (r.width() && r.height()) { create(s.getBuffer(), &r, CBagel::getBagApp()->getMasterWnd()); } else { create(s.getBuffer(), nullptr, CBagel::getBagApp()->getMasterWnd()); } show(); attachActiveObjects(); } } else { reportError(ERR_UNKNOWN, "No background for this storage device window"); } setPreFilterPan(true); g_lastWindow = this; CBagStorageDev *pSDev = g_SDevManager->getStorageDevice("EVT_WLD"); if (pSDev != nullptr) { // Have we allocated one yet ? if (_pEvtSDev == nullptr) { _pEvtSDev = (CBagEventSDev *)pSDev; _pEvtSDev->setAssociateWnd(this); if (!_pEvtSDev->isAttached()) _pEvtSDev->attach(); setTimer(EVAL_EXPR, 1000); g_pauseTimerFl = false; } else { // We already allocated one // We just need to re-associate the parent window and reset the timer _pEvtSDev->setAssociateWnd(this); setTimer(EVAL_EXPR, 1000); g_pauseTimerFl = false; } } return _errCode; } void CBagStorageDevWnd::onTimer(uint32 nEventID) { assert(isValidObject(this)); static bool bAlready = false; if (!g_pauseTimerFl) { // Don't allow recursion if (!bAlready) { bAlready = true; // Evaluate the event storage device IF MOVIE NOT PLAYING if ((CBofApp::getApp()->getMainWindow())->isEnabled() && nEventID == EVAL_EXPR) { if (_pEvtSDev != nullptr) { _pEvtSDev->evaluateExpressions(); // If our turncount was updated, then execute the event world // for the turncount dependent storage device. if (CBagEventSDev::getEvalTurnEvents() == true) { CBagEventSDev::setEvalTurnEvents(false); CBagTurnEventSDev *pSDev = (CBagTurnEventSDev *) g_SDevManager->getStorageDevice("TURN_WLD"); if (pSDev != nullptr) { // If unable to execute event world, try again next time through. if (pSDev->evaluateExpressions() == ERR_UNKNOWN) { CBagEventSDev::setEvalTurnEvents(true); } } } } g_waitOKFl = true; } bAlready = false; } } } ErrorCode CBagStorageDevWnd::detach() { detachActiveObjects(); CBofApp::getApp()->setPalette(nullptr); setBackground(nullptr); CBofSprite::closeLibrary(); CBagStorageDev::detach(); killTimer(EVAL_EXPR); destroy(); return _errCode; } ErrorCode CBagStorageDevWnd::close() { CBagel::getBagApp()->getMasterWnd()->setStorageDev(getPrevSDev(), false); return _errCode; } ErrorCode CBagStorageDevWnd::setBackground(CBofBitmap *pBmp) { if (pBmp) { setBackdrop(pBmp); setWorkBmp(); } else { killBackdrop(); killWorkBmp(); } return _errCode; } ErrorCode CBagStorageDevWnd::setWorkBmp() { // Delete any previous work area killWorkBmp(); CBofBitmap *pBmp = getBackground(); if (pBmp != nullptr) { _pWorkBmp = new CBofBitmap(pBmp->width(), pBmp->height(), pBmp->getPalette()); pBmp->paint(_pWorkBmp); } return _errCode; } ErrorCode CBagStorageDevWnd::killWorkBmp() { delete _pWorkBmp; _pWorkBmp = nullptr; return _errCode; } void CBagStorageDevWnd::onPaint(CBofRect *) { assert(isValidObject(this)); paintScreen(); } void CBagStorageDevWnd::onMainLoop() { assert(isValidObject(this)); paintScreen(); g_lastWindow = this; } ErrorCode CBagStorageDevWnd::paintScreen(CBofRect *pRect) { assert(isValidObject(this)); if (_pBackdrop != nullptr) { onRender(_pBackdrop, pRect); if (g_allowPaintFl) { _pBackdrop->paint(this, pRect, pRect); } } if (_bFirstPaint) { _bFirstPaint = false; attachActiveObjects(); } return _errCode; } ErrorCode CBagStorageDevWnd::onRender(CBofBitmap *pBmp, CBofRect *pRect) { assert(isValidObject(this)); assert(pBmp != nullptr); if (preFilterPan()) { preFilter(pBmp, pRect, nullptr); setPreFilterPan(false); if (_pWorkBmp != nullptr) { _pWorkBmp->paint(pBmp, pRect, pRect); } } paintStorageDevice(this, pBmp, pRect); if (isFiltered()) { uint16 nFilterId = getFilterId(); (*_pBitmapFilter)(nFilterId, pBmp, pRect); } return _errCode; } ErrorCode CBagStorageDevWnd::runModal(CBagObject *pObj) { assert(pObj != nullptr); if (pObj->isModal() && pObj->isActive()) { EventLoop eventLoop; CBofBitmap *pBmp = getBackdrop(); if (pBmp != nullptr) { while (!g_engine->shouldQuit() && !pObj->isModalDone()) { // Make sure we redraw each and every frame! setPreFilterPan(true); onRender(pBmp, nullptr); if (g_allowPaintFl) { pBmp->paint(this, 0, 0); } if (eventLoop.frame()) break; } } } return _errCode; } ErrorCode CBagStorageDevWnd::paintObjects(CBofList * /*list*/, CBofBitmap * /*pBmp*/, CBofRect & /*viewRect*/, CBofList * /*pUpdateArea*/, bool /*tempVar*/) { return _errCode; } ErrorCode CBagStorageDevWnd::loadFile(const CBofString &sFile) { char szWldFile[256]; szWldFile[0] = 0; CBofString sWldFile(szWldFile, 256); // performance improvement if (sFile.isEmpty()) sWldFile = "StoreDev.Wld"; else sWldFile = sFile; fixPathName(sWldFile); // Force buffer to be big enough so that the entire script // is pre-loaded int nLength = fileLength(sWldFile); if (nLength <= 0) reportError(ERR_FOPEN, "Unable to open file %s", sWldFile.getBuffer()); else { char *pBuf = (char *)bofAlloc(nLength); CBagIfstream fpInput(pBuf, nLength); CBofFile cFile; cFile.open(sWldFile); cFile.read(pBuf, nLength); cFile.close(); CBagStorageDev::loadFileFromStream(fpInput, sWldFile); // If the window.isCreated() // if (isCreated()) invalidateRect(nullptr); bofFree(pBuf); } // Add everything to the window return _errCode; } void CBagStorageDevWnd::onClose() { CBofWindow::onClose(); // destruct the main window destroyWindow(); } void CBagStorageDevWnd::onMouseMove(uint32 n, CBofPoint *pPoint, void *) { CBagStorageDev::onMouseMove(n, pPoint, getAssociateWnd()); if (CBagCursor::isSystemCursorVisible()) return; CBagMasterWin::setActiveCursor(0); // If a zelda movie is playing then just give 'em the wait cursor // as we're not gonna allow them to do squat anyway. if (CBagPDA::isMoviePlaying()) { CBagMasterWin::setActiveCursor(6); return; } if (getExitOnEdge() && (pPoint->x < getExitOnEdge()) && (pPoint->y < 360 + 10) && !(getPrevSDev().isEmpty())) { CBagMasterWin::setActiveCursor(10); } else { // Added wield cursors bool bWield = false; if (CBagWield::getWieldCursor() >= 0 && !CBagCursor::isSystemCursorVisible()) { CBagMasterWin::setActiveCursor(CBagWield::getWieldCursor()); bWield = true; } // Run through background object list and find if the cursor is over an object CBofList *pList = getObjectList(); if (pList != nullptr) { CBofPoint cCursorLocation = devPtToViewPort(*_xCursorLocation); // Go through list backwards to find the 1st top-most object CBofListNode *pNode = pList->getTail(); while (pNode != nullptr) { CBagObject *pObj = pNode->getNodeItem(); // Change cursor as long as it's not a link to a closeup, or // link to another Pan, or a text menu, or button. // if (pObj->isAttached() && pObj->isInside(cCursorLocation)) { int nCursor = pObj->getOverCursor(); if (!bWield || (nCursor == 2 || nCursor == 5 || nCursor == 55 || pObj->getType() == TEXT_OBJ || pObj->getType() == BUTTON_OBJ)) { CBagMasterWin::setActiveCursor(nCursor); } break; } pNode = pNode->_pPrev; } } } } void CBagStorageDevWnd::onLButtonDown(uint32 nFlags, CBofPoint *xPoint, void *) { // If asynch movie playing in PDA don't react to mouse down (8033) // if it's not a wait cursor, then allow the user to access that hotspot. if (CBagPDA::isMoviePlaying() && CBagMasterWin::getActiveCursor() == 6) { return; } CBagStorageDev::onLButtonDown(nFlags, xPoint, getAssociateWnd()); CBofWindow::onLButtonDown(nFlags, xPoint); } void CBagStorageDevWnd::onLButtonUp(uint32 nFlags, CBofPoint *xPoint, void *) { // If asynch movie playing in PDA don't react to mouse down (8033) // if it's not a wait cursor, then allow the user to access that hotspot. if (CBagPDA::isMoviePlaying() && CBagMasterWin::getActiveCursor() == 6) { return; } // React to a mouse up, it will probably involve drawing a new window... setPreFilterPan(true); if (getExitOnEdge() && xPoint->x < getExitOnEdge() && !(getPrevSDev().isEmpty())) { // Set the initial location as the last full panoramas position close(); } else { CBagStorageDev::onLButtonUp(nFlags, xPoint, getAssociateWnd()); CBofWindow::onLButtonUp(nFlags, xPoint); } } void CBagStorageDevWnd::onKeyHit(uint32 lKey, uint32 nRepCount) { CBofWindow::onKeyHit(lKey, nRepCount); } CBagStorageDevDlg::CBagStorageDevDlg() : CBofDialog() { _xSDevType = SDEV_DLG; // Set a default help file for when there is not one specified // _sHelpFileName = "$SBARDIR\\GENERAL\\RULES\\DEFAULT.TXT"; fixPathName(_sHelpFileName); } ErrorCode CBagStorageDevDlg::attach() { assert(isValidObject(this)); CBagStorageDev::attach(); char szLocalBuff[256]; CBofString s(szLocalBuff, 256); s = getName(); CBofBitmap *pBmp = getBackground(); CBofRect r; if (pBmp) r = pBmp->getRect(); if (r.width() && r.height()) { create(s.getBuffer(), &r, CBagel::getBagApp()->getMasterWnd()); } else { create(s.getBuffer(), nullptr, CBagel::getBagApp()->getMasterWnd()); } setPreFilterPan(true); CBofDialog::doModal(); destroy(); return _errCode; } ErrorCode CBagStorageDevDlg::close() { releaseCapture(); CBofDialog::close(); return _errCode; } ErrorCode CBagStorageDevDlg::onRender(CBofBitmap *pBmp, CBofRect *pRect) { assert(isValidObject(this)); assert(pBmp != nullptr); paintStorageDevice(this, pBmp, pRect); if (isFiltered()) { uint16 nFilterId = getFilterId(); (*_pBitmapFilter)(nFilterId, pBmp, pRect); } return _errCode; } void CBagStorageDevDlg::onMainLoop() { assert(isValidObject(this)); // The background of a storage device might be in motion, i.e. it // might need updates, but since it is a background screen, it probably isn't that // important, so we'll update it 4 times / second. int nCurTime = getTimer(); gLastBackgroundUpdate = nCurTime; if (g_lastWindow) { g_lastWindow->setPreFilterPan(true); } paintScreen(); } void CBagStorageDevDlg::onPaint(CBofRect *) { assert(isValidObject(this)); paintScreen(); validateAnscestors(); CBagPanWindow::flushInputEvents(); } ErrorCode CBagStorageDevDlg::paintScreen(CBofRect *pRect) { assert(isValidObject(this)); if (_pBackdrop != nullptr) { CBagStorageDevWnd *pWin = g_lastWindow; if (pWin != nullptr) { CBofBitmap *pBmp = pWin->getBackdrop(); if (pBmp != nullptr) { // Don't redraw the background window unless we have to. if (pWin->preFilterPan()) { CBofBitmap *pWorkBmp = pWin->getWorkBmp(); if (pWorkBmp != nullptr) { pWorkBmp->paint(pBmp, pRect, pRect); } pWin->onRender(pBmp, pRect); } onRender(_pBackdrop, pRect); CBofRect wrect(getWindowRect()); _pBackdrop->paint(pBmp, &wrect, nullptr); if (g_allowPaintFl) { pBmp->paint(pWin, pRect, pRect); } } } } // Set the firstpaint flag and attach objects // to allow for immediate run objects to run if (_bFirstPaint) { _bFirstPaint = false; attachActiveObjects(); } return _errCode; } ErrorCode CBagStorageDevDlg::paintObjects(CBofList * /*list*/, CBofBitmap * /*pBmp*/, CBofRect & /*viewRect*/, CBofList * /*pUpdateArea*/, bool /*tempVar*/) { return _errCode; } ErrorCode CBagStorageDevDlg::loadFile(const CBofString &sFile) { char szWldFile[256]; szWldFile[0] = 0; CBofString sWldFile(szWldFile, 256); if (sFile.isEmpty()) sWldFile = "StoreDev.Wld"; else sWldFile = sFile; fixPathName(sWldFile); // Force buffer to be big enough so that the entire script is pre-loaded int nLength = fileLength(sWldFile); if (nLength <= 0) reportError(ERR_FOPEN, "Unable to open file %s", sWldFile.getBuffer()); else { char *pBuf = (char *)bofAlloc(nLength); CBagIfstream fpInput(pBuf, nLength); CBofFile cFile; cFile.open(sWldFile); cFile.read(pBuf, nLength); cFile.close(); CBagStorageDev::loadFileFromStream(fpInput, sWldFile); bofFree(pBuf); if (isCreated()) invalidateRect(nullptr); } // Add everything to the window return _errCode; } ErrorCode CBagStorageDevDlg::create(const char *pszName, CBofRect *pRect, CBofWindow *pParent, uint32 nControlID) { ErrorCode errorCode = CBofDialog::create(pszName, pRect, pParent, nControlID); setCapture(); return errorCode; } void CBagStorageDevDlg::onClose() { delete _pDlgBackground; _pDlgBackground = nullptr; // Since our sdevdlg doesn't have a detach active objects // method, we will have to manually take all the existing objects and // tell them to redraw themselves should they ever be called on in life // to do as such. int nCount = getObjectCount(); for (int i = 0; i < nCount; ++i) { CBagObject *pObj = getObjectByPos(i); if (pObj != nullptr) { pObj->setDirty(true); } } CBofDialog::onClose(); destroy(); // Destruct the main window // Our dlog may have dirtied our backdrop, make sure it is redrawn. if (g_lastWindow != nullptr) { g_lastWindow->setPreFilterPan(true); g_lastWindow->paintScreen(nullptr); // This is fairly shameful, but for some reason, some // updates don't work in the above paintscreen and must be updated the // next time through. Don't know why, would love to find out, but // running out of time. g_lastWindow->setPreFilterPan(true); } } void CBagStorageDevDlg::onMouseMove(uint32 n, CBofPoint *xPoint, void *) { CBagStorageDev::onMouseMove(n, xPoint, getAssociateWnd()); } void CBagStorageDevDlg::onLButtonDown(uint32 nFlags, CBofPoint *xPoint, void *) { CBagStorageDev::onLButtonDown(nFlags, xPoint, getAssociateWnd()); CBofDialog::onLButtonDown(nFlags, xPoint); } void CBagStorageDevDlg::onLButtonUp(uint32 nFlags, CBofPoint *xPoint, void *) { if (CBofDialog::getRect().ptInRect(*xPoint)) { CBagStorageDev::onLButtonUp(nFlags, xPoint, getAssociateWnd()); CBofDialog::onLButtonUp(nFlags, xPoint); } else { close(); } } CBagStorageDevManager::CBagStorageDevManager() { ++nSDevMngrs; assert(nSDevMngrs < 2); } CBagStorageDevManager::~CBagStorageDevManager() { assert(isValidObject(this)); --nSDevMngrs; assert(nSDevMngrs >= 0); releaseStorageDevices(); _xStorageDeviceList.removeAll(); } ErrorCode CBagStorageDevManager::registerStorageDev(CBagStorageDev *pSDev) { assert(isValidObject(this)); _xStorageDeviceList.addToTail(pSDev); return ERR_NONE; } ErrorCode CBagStorageDevManager::unregisterStorageDev(CBagStorageDev *pSDev) { assert(isValidObject(this)); CBofListNode *pList = _xStorageDeviceList.getHead(); while (pList != nullptr) { if (pSDev == pList->getNodeItem()) { _xStorageDeviceList.remove(pList); break; } pList = pList->_pNext; } return ERR_NONE; } ErrorCode CBagStorageDevManager::releaseStorageDevices() { assert(isValidObject(this)); while (_xStorageDeviceList.getCount()) { CBagStorageDev *pSDev = _xStorageDeviceList[0]; // The CBagStorageDev destructor will remove it from the list delete pSDev; } return ERR_NONE; } CBagStorageDev *CBagStorageDevManager::getStorageDeviceContaining(CBagObject *pObj) { assert(isValidObject(this)); for (int i = 0; i < _xStorageDeviceList.getCount(); ++i) { CBagStorageDev *pSDev = _xStorageDeviceList[i]; if (pSDev && pSDev->contains(pObj)) return _xStorageDeviceList[i]; } return nullptr; } CBagStorageDev *CBagStorageDevManager::getStorageDeviceContaining(const CBofString &sName) { assert(isValidObject(this)); for (int i = 0; i < _xStorageDeviceList.getCount(); ++i) { CBagStorageDev *pSDev = _xStorageDeviceList[i]; if (pSDev && pSDev->getObject(sName)) return _xStorageDeviceList[i]; } return nullptr; } CBagStorageDev *CBagStorageDevManager::getStorageDevice(const CBofString &sName) { assert(isValidObject(this)); for (int i = 0; i < _xStorageDeviceList.getCount(); ++i) { CBagStorageDev *pSDev = _xStorageDeviceList[i]; if (pSDev && (pSDev->getName().getLength() == sName.getLength()) && !pSDev->getName().find(sName)) return _xStorageDeviceList[i]; } return nullptr; } bool CBagStorageDevManager::moveObject(const CBofString &sDstName, const CBofString &sSrcName, const CBofString &sObjName) { assert(isValidObject(this)); CBagStorageDev *pDstSDev = g_SDevManager->getStorageDevice(sDstName); // Find the storage device if (pDstSDev == nullptr) return false; CBagStorageDev *pSrcSDev = g_SDevManager->getStorageDevice(sSrcName); if (pSrcSDev == nullptr) return false; // Find the storage device if (pDstSDev->activateLocalObject(sObjName) != ERR_NONE) return false; if (pSrcSDev->deactivateLocalObject(sObjName) != ERR_NONE) { pDstSDev->deactivateLocalObject(sObjName); return false; } return true; } bool CBagStorageDevManager::addObject(const CBofString &sDstName, const CBofString &sObjName) { assert(isValidObject(this)); CBagStorageDev *pDstSDev = g_SDevManager->getStorageDevice(sDstName); // Find the storage device if (pDstSDev == nullptr) return false; // Find the storage device if (pDstSDev->activateLocalObject(sObjName) != ERR_NONE) return false; return true; } bool CBagStorageDevManager::removeObject(const CBofString &sSrcName, const CBofString &sObjName) { assert(isValidObject(this)); CBagStorageDev *pSrcSDev = g_SDevManager->getStorageDevice(sSrcName); // Find the storage device if (pSrcSDev == nullptr) return false; // Find the storage device if (pSrcSDev->deactivateLocalObject(sObjName) != ERR_NONE) return false; return true; } int CBagStorageDevManager::getObjectValue(const CBofString &sObject, const CBofString &sProperty) { assert(isValidObject(this)); for (int i = 0; i < _xStorageDeviceList.getCount(); ++i) { CBagStorageDev *pSDev = _xStorageDeviceList[i]; if (pSDev) { CBagObject *pObj = pSDev->getObject(sObject); if (pObj != nullptr) return pObj->getProperty(sProperty); } } return 0; } // Set object will set a property to a numeric value or set the object to a string value - // I am too lazy to write two funtions void CBagStorageDevManager::setObjectValue(const CBofString &sObject, const CBofString &sProperty, int nValue/*=DO_NOT_USE_THIS_VALUE*/) { assert(isValidObject(this)); // Make sure that all objects are set and not just one? // Make sure that the first object is changed? for (int i = 0; i < _xStorageDeviceList.getCount(); ++i) { CBagStorageDev *pSDev = _xStorageDeviceList[i]; if (pSDev) { CBagObject *pObj = pSDev->getObject(sObject); if (pObj != nullptr) { pObj->setProperty(sProperty, nValue); } } } } void CBagStorageDevManager::saveObjList(StObj *pObjList, int nNumEntries) { assert(isValidObject(this)); assert(pObjList != nullptr); int k = 0; int n = getNumStorageDevices(); for (int i = 0; i < n; i++) { CBagStorageDev *pSDev = getStorageDevice(i); if (pSDev != nullptr) { int m = pSDev->getObjectCount(); for (int j = 0; j < m; j++) { CBagObject *pObj = pSDev->getObjectByPos(j); if (!pObj->getRefName().isEmpty()) { assert(strlen(pObj->getRefName()) < MAX_OBJ_NAME); Common::strlcpy((pObjList + k)->_szName, pObj->getRefName(), MAX_OBJ_NAME); // We MUST have put something in here assert((pObjList + k)->_szName[0] != '\0'); assert(strlen(pSDev->getName()) < MAX_SDEV_NAME); Common::strlcpy((pObjList + k)->_szSDev, pSDev->getName(), MAX_SDEV_NAME); // Save if this guy is waiting to play (pObjList + k)->_nFlags = (uint16)(pObj->isMsgWaiting() ? mIsMsgWaiting : 0); (pObjList + k)->_lState = pObj->getState(); (pObjList + k)->_lProperties = pObj->getProperties(); (pObjList + k)->_lType = pObj->getType(); (pObjList + k)->_bUsed = 1; k++; assert(k < nNumEntries); // This is pretty dangerous, put up an error if (k >= nNumEntries) { bofMessageBox("saveObjList encountered too many objects", "Internal Error"); break; } } } } } } void CBagStorageDevManager::restoreObjList(StObj *pObjList, int nNumEntries) { assert(isValidObject(this)); assert(pObjList != nullptr); // Restore the state of all objects for (int i = 0; i < nNumEntries; i++) { if ((pObjList + i)->_bUsed) { CBagStorageDev *pSDev = getStorageDevice((pObjList + i)->_szSDev); if (pSDev != nullptr) { CBagObject *pObj = pSDev->getObject((pObjList + i)->_szName); if (pObj != nullptr) { pObj->setProperties((pObjList + i)->_lProperties); pObj->setState((pObjList + i)->_lState); pObj->setType((BagObjectType)(pObjList + i)->_lType); pObj->setMsgWaiting(((pObjList + i)->_nFlags & mIsMsgWaiting) == mIsMsgWaiting); } } } } } bool CBagStorageDev::isCIC() { // Slightly more complicated then before... if we're in a CIC, then return true, // however, if we're in the zoompda, then return the previous SDEV's cic value. if (_bCIC != false) { return true; } char szLocalBuff[256]; CBofString sStr(szLocalBuff, 256); sStr = "BPDAZ_WLD"; if (_sName == sStr) { return getCICStatus(); } return false; } } // namespace SpaceBar } // namespace Bagel