/* 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/hodjnpodj/hnplibs/stdafx.h" #include "bagel/hodjnpodj/barbershop/paint.h" #include "bagel/hodjnpodj/barbershop/barb.h" #include "bagel/hodjnpodj/hnplibs/bitmaps.h" namespace Bagel { namespace HodjNPodj { namespace Barbershop { static const char *DECKS[] = { // bitmap loading "art\\deck0.bmp", "art\\deck1.bmp", "art\\deck2.bmp", "art\\deck3.bmp", "art\\deck4.bmp", "art\\deck5.bmp", "art\\deck6.bmp", "art\\deck7.bmp" }; /***************************************************************** * * CPaint * * FUNCTIONAL DESCRIPTION: * * [Description of function] * * FORMAL PARAMETERS: * * [Show arguments] * * IMPLICIT INPUT PARAMETERS: * * [External data read] * * IMPLICIT OUTPUT PARAMETERS: * * [External data modified] * * RETURN VALUE: * * [Discuss return value] * ****************************************************************/ CPaint::CPaint(CDC *pDC) { CBitmap *pBmpCardSet = nullptr; CBitmap *pCard = nullptr; bool bSuccess; int i, j; for (i = 0; i < CARDS_PER_COL; i++) { // Initialize master alphabet list pBmpCardSet = FetchBitmap(pDC, (CPalette**) nullptr, DECKS[i]); ASSERT(pBmpCardSet); for (j = 0; j < CARDS_PER_ROW; j ++) { pCard = ExtractBitmap( // fetch the proper card pDC, pBmpCardSet, pGamePalette, j * BITMAP_WTH, 0, BITMAP_WTH, BITMAP_HEI ); ASSERT(pCard); m_cCardSet[(i * CARDS_PER_ROW) + j] = new OSpr(); // Initize the individual letter of the alphabet list bSuccess = (*m_cCardSet[(i * CARDS_PER_ROW) + j]).LoadSprite(pCard, pGamePalette); ASSERT(bSuccess); (*m_cCardSet[(i * CARDS_PER_ROW) + j]).SetHotspot(CARD_HOT_X, CARD_HOT_Y); (*m_cCardSet[(i * CARDS_PER_ROW) + j]).SetMobile(true); (*m_cCardSet[(i * CARDS_PER_ROW) + j]).SetMasked(true); } // end for delete pBmpCardSet; pBmpCardSet = nullptr; } // end for m_nCardBack = CARD_BACK1; m_nUsedInd = 0; // Used in Stack() proc; for indenting cards placed on used stack m_cFound.SetRect( FND_LEF, FND_TOP, FND_RIG, FND_BOT ); for (i = 0; i < TAB_COUNT; i++) m_cTab[i].SetRect( TAB_LEF + (TAB_OFFSET * i), TAB_TOP, TAB_RIG + (TAB_OFFSET * i), TAB_BOT ); m_cStock.SetRect( STOC_LEF, STOC_TOP, STOC_RIG, STOC_BOT ); m_cUsed.SetRect( STOC_LEF + USED_OFFSET, STOC_TOP, STOC_RIG + USED_OFFSET, STOC_BOT ); } /***************************************************************** * * ~CPaint * * FUNCTIONAL DESCRIPTION: * * [Description of function] * * FORMAL PARAMETERS: * * [Show arguments] * * IMPLICIT INPUT PARAMETERS: * * [External data read] * * IMPLICIT OUTPUT PARAMETERS: * * [External data modified] * * RETURN VALUE: * * [Discuss return value] * ****************************************************************/ CPaint::~CPaint() { int i; CSprite::FlushSpriteChain(); for (i = 0; i < CARD_SET; i++) delete m_cCardSet[i]; // each letter in the alpha } /***************************************************************** * * Board * * FUNCTIONAL DESCRIPTION: * * [Description of function] * * FORMAL PARAMETERS: * * [Show arguments] * * IMPLICIT INPUT PARAMETERS: * * [External data read] * * IMPLICIT OUTPUT PARAMETERS: * * [External data modified] * * RETURN VALUE: * * [Discuss return value] * ****************************************************************/ void CPaint::Board(CDC *pDC, CBoard *pBoard) { int i, j; CCard *pCard[TAB_COUNT]; /************************************************************ * Goes thru each stack on the tableau, dealing cards one at * * a time rotating to next stack, in turn. * ************************************************************/ for (i = 0; i < TAB_COUNT; i++) pCard[i] = pBoard->GetStack((loc)(tab + (loc) i))->Bottom(); for (i = 0; i < TABLEAU; i++) { j = i % TAB_COUNT; m_pSprite = new OSpr(); if (pCard[j] == pCard[j]->m_pStack->Top()) { m_cCardSet[pCard[j]->GetValue()]->DuplicateSprite(pDC, (CSprite*) m_pSprite); m_pSprite->m_cCard = pCard[j]; (*m_pSprite).LinkSprite(); pCard[j]->m_bIsBack = false; } else { m_cCardSet[m_nCardBack]->DuplicateSprite(pDC, (CSprite*) m_pSprite); m_pSprite->m_cCard = pCard[j]; (*m_pSprite).LinkSprite(); pCard[j]->m_bIsBack = true; } // end if pCard[j]->m_pSprite = m_pSprite; Stack(pDC, pCard[j], (int) i / TAB_COUNT); pCard[j] = pCard[j]->m_pNextCard; // Advance to next card } // end for /************************************************************ * used any random pCard index, didn't matter, so 0 is used. * ************************************************************/ pCard[0] = pBoard->GetStack(stock)->Bottom(); // Get first card in stack i = 0; while (pCard[0] != nullptr) { m_pSprite = new OSpr(); // set up visual sprite m_cCardSet[m_nCardBack]->DuplicateSprite(pDC, (CSprite*) m_pSprite); (*m_pSprite).LinkSprite(); m_pSprite->m_cCard = pCard[0]; // update internal card struct pCard[0]->m_pSprite = m_pSprite; pCard[0]->m_bIsBack = true; Stack(pDC, pCard[0], i); // paint it on screen pCard[0] = pCard[0]->m_pNextCard; // Advance to next card i++; } // end while } void CPaint::Refresh(CDC *pDC, CBoard *pBoard) { int i; int nCardPos; // card pos in stack CStack *pStack; CCard *pCard; CPoint cPos; m_pSprite = (OSpr*) OSpr::GetSpriteChain(); if (m_pSprite == nullptr) // any sprites to refresh? return; // no OSpr::ClearBackgrounds(); pStack = pBoard->GetStack(fnd); // refresh foundation pCard = pStack->Bottom(); nCardPos = 0; while (pCard != nullptr) { if (pCard->m_pSprite != nullptr) { pCard->m_pSprite->RefreshSprite(pDC); } pCard = pCard->m_pNextCard; nCardPos++; } for (i = tab; i < stock; i++) { // refresh tableau pStack = pBoard->GetStack((loc) i); pCard = pStack->Bottom(); nCardPos = 0; while (pCard != nullptr) { if (pCard->m_pSprite != nullptr) { pCard->m_pSprite->RefreshSprite(pDC); } pCard = pCard->m_pNextCard; nCardPos++; } // end while } // end for pStack = pBoard->GetStack(stock); // refresh stock top card only pCard = pStack->Bottom(); nCardPos = 0; while (pCard != nullptr) { if (pCard->m_pSprite != nullptr) { pCard->m_pSprite->RefreshSprite(pDC); } pCard = pCard->m_pNextCard; nCardPos++; } pStack = pBoard->GetStack(used); // refresh used stack pCard = pStack->Bottom(); nCardPos = 0; while (pCard != nullptr) { if (pCard->m_pSprite != nullptr) { pCard->m_pSprite->RefreshSprite(pDC); } pCard = pCard->m_pNextCard; nCardPos++; } (void)nCardPos; // avoid unused variable warning } CCard *CPaint::IsOnCard(CPoint cPoint) { if ((m_pSprite = (OSpr *) m_pSprite->Touched(cPoint)) == nullptr) return nullptr; return m_pSprite->m_cCard->m_pStack->Top(); } void CPaint::MoveCard(CDC *pDC, CCard *pCard, CPoint point) { point.x -= pCard->m_pSprite->GetHotspot().x; // causes the point to appear in the point.y -= pCard->m_pSprite->GetHotspot().y; // center of the card. pCard->m_pSprite->PaintSprite(pDC, point); } void CPaint::UpdateCard(CDC *pDC, CCard *pCard) { pCard->m_pSprite->PaintSprite(pDC, pCard->m_cOrigin); // paint card @ cur pos } void CPaint::FlipCard(CDC *pDC, CCard *pCard) { /********************************** * Get rid of current card bitmap. * **********************************/ pCard->m_pSprite->RefreshBackground(pDC); // ...repaint background pCard->m_pSprite->UnlinkSprite(); // unlink from refresh chain delete pCard->m_pSprite; /****************************************************************** * Reverse card. If it is a back, flip it forward, and vise versa. * ******************************************************************/ pCard->m_pSprite = new OSpr(); if (pCard->m_bIsBack == true) { (*m_cCardSet[pCard->GetValue()]).DuplicateSprite(pDC, (CSprite*) pCard->m_pSprite); pCard->m_bIsBack = false; } else { (*m_cCardSet[m_nCardBack]).DuplicateSprite(pDC, (CSprite*) pCard->m_pSprite); pCard->m_bIsBack = true; } pCard->m_pSprite->LinkSprite(); pCard->m_pSprite->m_cCard = pCard; // update internal rep } /***************************************************************** * * Stack * * FUNCTIONAL DESCRIPTION: * * Indents top card properly relative to it's current stack. * Assigns pCard->m_cOrigin to correct position. * * FORMAL PARAMETERS: * * [Show arguments] * * IMPLICIT INPUT PARAMETERS: * * [External data read] * * IMPLICIT OUTPUT PARAMETERS: * * [External data modified] * * RETURN VALUE: * * [Discuss return value] * ****************************************************************/ void CPaint::Stack(CDC *pDC, CCard *pCard, int nSize) { int i; if (pCard == nullptr) return; if (nSize == -1) { // funct overloaded? i = pCard->m_pStack->Size() - 1;// no, use stack size info } else { i = nSize; // yes, use info from param } switch (pCard->m_pStack->GetID()) { // Update card visual coordinates case fnd: case stock: pCard->m_cOrigin = pCard->m_pStack->m_cRect.TopLeft(); pCard->m_cOrigin.x += ((int) i / STACK_INDENT) * STACK_DX; pCard->m_cOrigin.y += ((int) i / STACK_INDENT) * STACK_DY; break; case used: if (pCard->m_pStack->Bottom() == pCard) // bottom card? m_nUsedInd = 0; // reset stack offset counter pCard->m_cOrigin = pCard->m_pStack->m_cRect.TopLeft(); pCard->m_cOrigin.x += ((int) m_nUsedInd % USED_INDENT) * USED_DX; pCard->m_cOrigin.y += ((int) m_nUsedInd % USED_INDENT) * USED_DY; m_nUsedInd++; break; default: if (pCard->m_pPrevCard != nullptr) { // card face req pos? if (pCard->m_pPrevCard->m_bIsBack == false) { pCard->m_cOrigin.x = pCard->m_pPrevCard->m_cOrigin.x + STACK_FACE_DX; pCard->m_cOrigin.y = pCard->m_pPrevCard->m_cOrigin.y + STACK_FACE_DY; break; } // end if } // // Card back requires positioning // pCard->m_cOrigin = pCard->m_pStack->m_cRect.TopLeft(); pCard->m_cOrigin.x += ((int) i / TAB_INDENT) * TAB_DX; pCard->m_cOrigin.y += ((int) i / TAB_INDENT) * TAB_DY; break; } pCard->m_pSprite->PaintSprite(pDC, pCard->m_cOrigin); } /***************************************************************** * * IsNewBack * * FUNCTIONAL DESCRIPTION: * * * FORMAL PARAMETERS: * * [Show arguments] * * IMPLICIT INPUT PARAMETERS: * * [External data read] * * IMPLICIT OUTPUT PARAMETERS: * * [External data modified] * * RETURN VALUE: * * [Discuss return value] * ****************************************************************/ bool CPaint::IsNewBack(int nBack) { if (m_nCardBack == nBack) { // any change? return false; } else { return true; } } /***************************************************************** * * ChangeBack * * FUNCTIONAL DESCRIPTION: * * * FORMAL PARAMETERS: * * [Show arguments] * * IMPLICIT INPUT PARAMETERS: * * [External data read] * * IMPLICIT OUTPUT PARAMETERS: * * [External data modified] * * RETURN VALUE: * * [Discuss return value] * ****************************************************************/ void CPaint::ChangeBack(CDC *pDC, CBoard *pBoard, int nBack) { int i; CStack *pStack; CCard *pCard; if (m_nCardBack == nBack) { // any change? return; // no - just return } else { m_nCardBack = nBack; } for (i = fnd; i <= used; i++) { // refresh tableau pStack = pBoard->GetStack((loc) i); pCard = pStack->Bottom(); while (pCard != nullptr) { if (pCard->m_bIsBack == false) { pCard = pCard->m_pNextCard; continue; } pCard->m_pSprite->UnlinkSprite(); // unlink from refresh chain delete pCard->m_pSprite; pCard->m_pSprite = new OSpr(); (*m_cCardSet[m_nCardBack]).DuplicateSprite(pDC, (CSprite*) pCard->m_pSprite); pCard->m_pSprite->LinkSprite(); pCard->m_pSprite->SetPosition(pCard->m_cOrigin); pCard->m_pSprite->m_cCard = pCard; // update internal rep pCard = pCard->m_pNextCard; } // end while } // end for } } // namespace Barbershop } // namespace HodjNPodj } // namespace Bagel