home *** CD-ROM | disk | FTP | other *** search
- /*
- * - Need to check whether icons are distinct. This is particularly a
- * problem if a 'cicn' B/W image and an 'ICON' are similar on a B/W machine.
- * - Change ReadPieces() to read a particular file.
- * - Should put max/default/size stuff into a structure and pass it around.
- */
-
- # include "TransSkel.h"
- # if ENABLE_DEBUG
- # include "Debug.h"
- # endif ENABLE_DEBUG
-
- # include "Concentration.h"
-
-
- # define normalHilite 0
- # define dimHilite 255
-
- # define returnKey '\r'
- # define enterKey 3
-
- /*
- * Possible game states
- */
-
- typedef enum
- {
- waitFirstChoice = 1, /* waiting for current player's first choice */
- waitSecondChoice, /* waiting for current player's second choice */
- waitNextPlayer, /* waiting for click in "Next Player" button */
- waitNewGame, /* game over; waiting for new one to begin */
- boardSizeTooBig
- };
-
-
- static BlobSetHandle receptors = (BlobSetHandle) nil;
- static BlobHandle firstChoice = (BlobHandle) nil;
- static BlobHandle secondChoice = (BlobHandle) nil;
-
- static ControlHandle nextPlayerBtn;
- static ControlHandle newGameBtn;
-
- WindowPtr gameWind;
-
- short nPairs;
- short pairsLeft;
-
- static GameBoard largePieceBoard =
- {
- largePiece,
- maxLargeRows, maxLargeCols,
- defLargeRows, defLargeCols,
- defLargeRows, defLargeCols,
- iconSize,
- iconGap,
- 0
- /* piece array left unspecified */
- };
- static GameBoard smallPieceBoard =
- {
- smallPiece,
- maxSmallRows, maxSmallCols,
- defSmallRows, defSmallCols,
- defSmallRows, defSmallCols,
- sitmSize,
- sitmGap,
- 0
- /* piece array left unspecified */
- };
-
- GameBoard *gb = &largePieceBoard;
-
- static short gameState;
- static short movesMade = 0;
-
-
- static short
- GetButtonHilite (ControlHandle ctrl)
- {
- return ((**ctrl).contrlHilite);
- }
-
-
- /*
- * Read 'cicn', 'ICON', and 'SICN' resources from application resource
- * fork. Read color resources first in preference to the B/W resources.
- */
-
- void
- ReadPieces (void)
- {
- GameBoard *tmpGB;
- short nRsrcs;
- short i, j, k;
- Handle h;
- SitmHandle sitmHandle;
- short resID;
- Str255 resName;
- ResType resType;
-
- # if ENABLE_DEBUG
- DisplayCString ("Number of 'cicn' resources: ");
- DisplayShort (Count1Resources ('cicn'));
- DisplayLn ();
- DisplayCString ("Number of 'ICON' resources: ");
- DisplayShort (Count1Resources ('ICON'));
- DisplayLn ();
- DisplayCString ("Number of 'SICN' resources: ");
- DisplayShort (Count1Resources ('SICN'));
- DisplayLn ();
- # endif
-
- tmpGB = &largePieceBoard;
- tmpGB->nPieces = 0;
-
- nRsrcs = Count1Resources ('cicn');
- for (i = 1; i <= nRsrcs; i++)
- {
- if (tmpGB->nPieces >= maxPieces)
- break;
- SetResLoad (false);
- h = GetIndResource ('cicn', i);
- SetResLoad (true);
- if (h == (Handle) nil)
- break;
- GetResInfo (h, &resID, &resType, resName);
- h = (Handle) GetCIcon (resID);
- if (h == (Handle) nil)
- break;
- tmpGB->piece[tmpGB->nPieces].pieceType = cicnType;
- tmpGB->piece[tmpGB->nPieces].pieceData = h;
- ++tmpGB->nPieces;
- }
-
- nRsrcs = Count1Resources ('ICON');
- for (i = 1; i <= nRsrcs; i++)
- {
- if (tmpGB->nPieces >= maxPieces)
- break;
- h = GetIndResource ('ICON', i);
- if (h == (Handle) nil)
- break;
- DetachResource (h);
- tmpGB->piece[tmpGB->nPieces].pieceType = iconType;
- tmpGB->piece[tmpGB->nPieces].pieceData = h;
- ++tmpGB->nPieces;
- }
- # if ENABLE_DEBUG
- DisplayCString ("Large pieces: ");
- DisplayShort (tmpGB->nPieces);
- DisplayLn ();
- # endif
-
- tmpGB = &smallPieceBoard;
- tmpGB->nPieces = 0;
-
- nRsrcs = Count1Resources ('SICN');
- for (i = 1; i <= nRsrcs; i++)
- {
- h = GetIndResource ('SICN', i);
- if (h == (Handle) nil)
- break;
- j = GetHandleSize ((Handle) h) / sizeof (Sitm);
- for (k = 0; k < j; k++)
- {
- if (tmpGB->nPieces >= maxPieces)
- break;
- sitmHandle = (SitmHandle) NewHandle (sizeof (Sitm));
- if (sitmHandle == (SitmHandle) nil)
- break;
- HLock (h);
- HLock ((Handle) sitmHandle);
- **sitmHandle = (**(SicnHandle) h)[k];
- HUnlock (h);
- HUnlock ((Handle) sitmHandle);
- tmpGB->piece[tmpGB->nPieces].pieceType = sicnType;
- tmpGB->piece[tmpGB->nPieces].pieceData = (Handle) sitmHandle;
- ++tmpGB->nPieces;
- }
- ReleaseResource (h);
- }
- # if ENABLE_DEBUG
- DisplayCString ("Small pieces: ");
- DisplayShort (tmpGB->nPieces);
- DisplayLn ();
- # endif
- }
-
-
-
- /*
- * Set up the list of pieces for play.
- */
-
- void
- InitBoard (short sizeType)
- {
- BlobHandle b;
- Rect r;
- short i, h, v;
-
- if (receptors != (BlobSetHandle) nil)
- {
- HideBlobSet (receptors);
- DisposeBlobSet (receptors);
- receptors = (BlobSetHandle) nil;
- }
-
- if (sizeType == largePiece)
- gb = &largePieceBoard;
- else
- gb = &smallPieceBoard;
-
- nPairs = (gb->nRows * gb->nCols) / 2;
- receptors = NewBlobSet ();
- for (i = 0; i < nPairs * 2; ++i)
- {
- h = gbHOffset + (gb->pieceSize + gb->pieceGap) * (i % gb->nCols);
- v = gbVOffset + (gb->pieceSize + gb->pieceGap) * (i / gb->nCols);
- MakeBlob (receptors, h, v, gb->sizeType);
- }
- }
-
-
- /*
- * Force window to be frontmost and everything to be redrawn.
- * Call this after setting up for a new round of the game.
- */
-
- static void
- ForceRedraw (void)
- {
- InvalRect (&gameWind->portRect);
- SelectWindow (gameWind); /* select and show in case this */
- ShowWindow (gameWind); /* is the first game */
- SkelDoUpdates ();
- if (gameState != boardSizeTooBig)
- FlashPlayerFrame (sb->player);
- }
-
-
- /*
- * Set up for a new round of the game.
- *
- * First check whether there are enough game pieces available for the
- * given board size. (nPieces must be at least half nRows * nCols.)
- *
- * If enough pieces, randomize the piece array. This allows new pieces
- * to come into the board if there are more pieces available than needed
- * to fill the board each time.
- *
- * Then assign each piece used to two different blobs and shuffle the
- * blobs to randomize the images on the board.
- */
-
- void
- NewGameRound (void)
- {
- BlobHandle b;
- short i, j;
- Piece tmpPiece;
-
- if (gb->nPieces * 2 < gb->nRows * gb->nCols)
- {
- gameState = boardSizeTooBig;
- HideControl (nextPlayerBtn);
- HideControl (newGameBtn);
- ForceRedraw ();
- return;
- }
-
- gameState = waitFirstChoice;
-
- ResetScoreBoard (movesMade > 0);
- movesMade = 0;
-
- /*
- * Shuffle all available pieces, then pick the first nPairs of
- * them. This randomizes the pieces that get used for each
- * round of the game.
- */
-
- for (i = 0; i < gb->nPieces; ++i)
- {
- j = BlobRand (gb->nPieces - 1);
- tmpPiece = gb->piece[i];
- gb->piece[i] = gb->piece[j];
- gb->piece[j] = tmpPiece;
- }
-
- HideBlobSet (receptors);
- ThawBlobSet (receptors);
-
- /*
- * Make new image assignments
- */
-
- for (i = 0; i < nPairs; i++)
- {
- SetBRefCon (GetBlobHandle (receptors, i), i);
- SetBRefCon (GetBlobHandle (receptors, i + nPairs), i);
- }
-
- for (b = FirstBlob (receptors); b != nil; b = NextBlob (b))
- GlueGlob (b, b);
- ShuffleBlobSet (receptors);
- EnableBlobSet (receptors);
- pairsLeft = nPairs;
- HiliteControl (nextPlayerBtn, dimHilite);
- SkelDrawButtonOutline (nextPlayerBtn);
- ShowControl (nextPlayerBtn);
- ShowControl (newGameBtn);
-
- ForceRedraw ();
- }
-
-
- void
- ShowAnswer (void)
- {
- short i;
-
- UnglueGlobSet (receptors);
- gameState = waitNewGame;
- pairsLeft = 0;
- i = sb->player;
- sb->player = -1;
- DrawPlayerInfo (i); /* erase frame around last player */
- HiliteControl (nextPlayerBtn, dimHilite);
- SkelEraseButtonOutline (nextPlayerBtn);
- SkelDrawButtonOutline (newGameBtn);
- }
-
-
- /*
- * Undo the current player's choices by covering them back up,
- * and go to the next player. This should only be called after
- * a player has selected two non-matching pieces.
- */
-
- static void
- NextPlayer (void)
- {
- short oldPlayer;
-
- /* cover the pieces back up */
-
- GlueGlob (firstChoice, firstChoice);
- GlueGlob (secondChoice, secondChoice);
-
- /* disable the "Next Player" button */
-
- HiliteControl (nextPlayerBtn, dimHilite);
- SkelDrawButtonOutline (nextPlayerBtn);
-
- /* thaw the blobs so they can be clicked again */
-
- ThawBlobSet (receptors);
-
- oldPlayer = sb->player;
- if (++sb->player >= sb->nPlayers)
- sb->player = 0;
- DrawPlayerInfo (oldPlayer);
- DrawPlayerInfo (sb->player);
- FlashPlayerFrame (sb->player);
-
- gameState = waitFirstChoice;
- }
-
-
- static pascal void
- Mouse (Point pt, long t, short mods)
- {
- BlobHandle b;
- ControlHandle ctl;
- short i;
-
- if (gameState == boardSizeTooBig)
- return;
-
- if (FindControl (pt, gameWind, &ctl))
- {
- if (TrackControl (ctl, pt, nil)) /* button hit? */
- {
- if (ctl == newGameBtn)
- NewGameRound ();
- else
- NextPlayer ();
- }
- }
- else if (FindBlob (pt, receptors, &b) != 0 && BGlob (b) != nil)
- {
- ++movesMade;
-
- UnglueGlob (b);
- if (gameState == waitFirstChoice) /* player's first choice */
- {
- gameState = waitSecondChoice;
- firstChoice = b;
- }
- else /* player's second choice */
- {
- secondChoice = b;
-
- if (GetBRefCon (firstChoice) == GetBRefCon (secondChoice))
- {
- /*
- * It's a match.
- * Leave pieces uncovered, increment player's score.
- * Let same player keep playing.
- */
- --pairsLeft;
- ++sb->score[sb->player];
- DrawPlayerInfo (sb->player);
- if (pairsLeft)
- {
- gameState = waitFirstChoice;
- FlashPlayerFrame (sb->player);
- }
- else
- {
-
- gameState = waitNewGame;
- i = sb->player;
- sb->player = -1;
- DrawPlayerInfo (i); /* erase frame around last player */
- SkelEraseButtonOutline (nextPlayerBtn);
- SkelDrawButtonOutline (newGameBtn);
- }
- }
- else /* not a match; enable "Next Player" button */
- {
- /*
- * It's not a match. Enable the "Next Player" button, which must
- * be clicked to allow the next player to proceed. The blobs are
- * frozen so they can't be clicked.
- */
- HiliteControl (nextPlayerBtn, normalHilite);
- SkelDrawButtonOutline (nextPlayerBtn);
- FreezeBlobSet (receptors);
- gameState = waitNextPlayer;
- }
- }
-
- }
- }
-
-
- static pascal void
- Key (short c, short code, short modifiers)
- {
- if (gameState == boardSizeTooBig)
- return;
-
- if (c == returnKey || c == enterKey) /* interpret carriage return/enter as */
- { /* button click (if button is hilited) */
- if (gameState == waitNewGame)
- {
- if (GetButtonHilite (newGameBtn) == normalHilite)
- {
- SkelFlashButton (newGameBtn);
- NewGameRound ();
- }
- }
- else
- {
- if (GetButtonHilite (nextPlayerBtn) == normalHilite)
- {
- SkelFlashButton (nextPlayerBtn);
- NextPlayer ();
- }
- }
- }
- }
-
-
-
- static pascal void
- Update (Boolean resized)
- {
- short i;
-
- EraseRect (&gameWind->portRect);
-
- if (gameState == boardSizeTooBig)
- {
- MoveTo (10, 30);
- DrawString ("\pBoard size too big for number of pieces available.");
- MoveTo (10, 50);
- DrawString ("\pPlease select a smaller board size.");
- return;
- }
-
- DrawControls (gameWind);
- if (gameState == waitNewGame)
- SkelDrawButtonOutline (newGameBtn);
- else
- SkelDrawButtonOutline (nextPlayerBtn);
- DrawBlobSet (receptors);
-
- DrawScoreBoard ();
- }
-
-
- /*
- * If the "Next Player" button is visible (i.e., board size isn't too big),
- * then hilite it according to whether or not the state is waitNextPlayer.
- * If the window's not active, the button is always dim.
- *
- * "New Game" button is always active then the window is active.
- */
-
- static pascal void
- Activate (Boolean active)
- {
- short hilite;
- Rect r;
-
- if (gameState != boardSizeTooBig)
- {
- if (active)
- hilite = (gameState == waitNextPlayer ? normalHilite : dimHilite);
- else
- hilite = dimHilite;
- if (SkelHiliteControl (nextPlayerBtn, hilite)) /* inval on state change */
- {
- r = (**nextPlayerBtn).contrlRect;
- InsetRect (&r, -4, -4);
- InvalRect (&r);
- }
- hilite = (active ? normalHilite : dimHilite);
- if (SkelHiliteControl (newGameBtn, hilite)) /* inval on state change */
- {
- r = (**newGameBtn).contrlRect;
- InsetRect (&r, -4, -4);
- InvalRect (&r);
- }
- }
- }
-
-
-
- /*
- * Dispose of game window
- */
-
- static pascal void
- DoClobber (void)
- {
- DisposeWindow (gameWind);
- }
-
-
- /*
- * Set up game window
- */
-
- void
- WindInit (void)
- {
- Rect r;
- long result;
-
- SetRect (&r, 0, 0, 487, 255);
- if (SkelQuery (skelQHasColorQD))
- {
- gameWind = NewCWindow (nil, &r, "\pConcentration", false,
- noGrowDocProc, (WindowPtr) -1L, false, 0L);
- }
- else
- {
- gameWind = NewWindow (nil, &r, "\pConcentration", false,
- noGrowDocProc, (WindowPtr) -1L, false, 0L);
- }
-
- SkelPositionWindow (gameWind, skelPositionOnMainDevice,
- FixRatio (1, 2), FixRatio (1, 5));
- SkelWindow (gameWind,
- Mouse, /* mouse clicks */
- Key, /* key clicks */
- Update, /* updates */
- Activate, /* activate/deactivate events */
- nil, /* close window */
- DoClobber, /* dispose of window */
- nil, /* idle proc */
- false); /* irrelevant, since no idle proc */
-
- TextFont (0);
- TextSize (0);
-
- SetRect (&r, 0, 0, 90, 20);
- OffsetRect (&r,
- sbHOffset + (sbWidth - 90) / 2,
- sbVOffset + sbHeight + 15);
- nextPlayerBtn = NewControl (gameWind, &r, "\pNext Player", false, 0, 0, 1,
- pushButProc, 0L);
- OffsetRect (&r, 0, 30);
- newGameBtn = NewControl (gameWind, &r, "\pNew Game", false, 0, 0, 1,
- pushButProc, 0L);
-
- InitBoard (largePiece);
- NewGameRound (); /* selects and shows window */
- }
-