This is Pyramid.m in view mode; [Download] [Up]
/* indent:4 tabsize:8 font:fixed-width */ #import "Pyramid.h" #import "PyramidPrefs.h" #import "DiscardCardPileDelegate.h" #import "GameCardPileDelegate.h" #import "StockCardPileDelegate.h" #import "WasteCardPileDelegate.h" #import "localstrings.h" static id _pyramidSharedInstance = nil; @implementation Pyramid + (Pyramid*) sharedInstance /*" Instead of the old method of calling SolGameController when you wanted to message the Pyramid game module, you now call [Pyramid sharedInstance] and direct messages to the returned instance. You can use this to check if the game has been won, among other things. "*/ { return _pyramidSharedInstance; } - initFromBundle:(NSBundle*)aBundle withName:(NSString*)name /*" Extends our superclass method in order to set our shared instance variable. "*/ { [super initFromBundle:aBundle withName:name]; // This is used instead of having a global SolGameController() // function. It is assumed that this method will be called // only once and that our +sharedInstance method will return // the single instance. _pyramidSharedInstance = self; return self; } /*--------------------------------------------------------------------------- | | - startGame: | |---------------------------------------------------------------------------- | | Start a new game. Get confirmation from the user before aborting a | game in progress. | \----------------------------------------------------------------------------*/ - (void) startGame:sender { if (gameInProgress) [self determineScore]; [super startGame:sender]; [self setupGame:YES]; } /*--------------------------------------------------------------------------- | | - restartGame: | |---------------------------------------------------------------------------- | | Restart the game in progress. | \----------------------------------------------------------------------------*/ - (void) restartGame:sender { if (gameInProgress) [self determineScore]; [super restartGame:sender]; [self setupGame:NO]; } /*--------------------------------------------------------------------------- | | - setupGame:(BOOL)redeal | |---------------------------------------------------------------------------- | | Setup a new game. If "redeal" is true, deal a new deck, otherwise | use the same cards as the previous game. | \----------------------------------------------------------------------------*/ - (void) setupGame:(BOOL)redeal { int pileIndex; CardPile* stockCardPile = [stockCardPileView cardPile]; [gameWindow disableFlushWindow]; [self setDealCount:1]; pyramidEmpty = NO; //---------------------------------------------------------------- // Sync pile id's with current game window and set // preferences and delegates //---------------------------------------------------------------- gameCardPiles[0] = gamePileView1; gameCardPiles[1] = gamePileView2; gameCardPiles[2] = gamePileView3; gameCardPiles[3] = gamePileView4; gameCardPiles[4] = gamePileView5; gameCardPiles[5] = gamePileView6; gameCardPiles[6] = gamePileView7; gameCardPiles[7] = gamePileView8; gameCardPiles[8] = gamePileView9; gameCardPiles[9] = gamePileView10; gameCardPiles[10] = gamePileView11; gameCardPiles[11] = gamePileView12; gameCardPiles[12] = gamePileView13; gameCardPiles[13] = gamePileView14; gameCardPiles[14] = gamePileView15; gameCardPiles[15] = gamePileView16; gameCardPiles[16] = gamePileView17; gameCardPiles[17] = gamePileView18; gameCardPiles[18] = gamePileView19; gameCardPiles[19] = gamePileView20; gameCardPiles[20] = gamePileView21; gameCardPiles[21] = gamePileView22; gameCardPiles[22] = gamePileView23; gameCardPiles[23] = gamePileView24; gameCardPiles[24] = gamePileView25; gameCardPiles[25] = gamePileView26; gameCardPiles[26] = gamePileView27; gameCardPiles[27] = gamePileView28; [stockCardPileView setBackgroundColor:desktopColor]; [stockCardPileView setCardSize:cardSize]; [stockCardPileView setDelegate:stockDelegate]; [wasteCardPileView setBackgroundColor:desktopColor]; [wasteCardPileView setCardSize:cardSize]; [wasteCardPileView setDelegate:wasteDelegate]; [discardCardPileViewL setBackgroundColor:desktopColor]; [discardCardPileViewL setCardSize:cardSize]; [discardCardPileViewL setDelegate:discardDelegate]; [discardCardPileViewR setBackgroundColor:desktopColor]; [discardCardPileViewR setCardSize:cardSize]; [discardCardPileViewR setDelegate:discardDelegate]; [stockDelegate setDiscardLeft:discardCardPileViewL discardRight:discardCardPileViewR waste:wasteCardPileView]; [gameDelegate setDiscardLeft:discardCardPileViewL discardRight:discardCardPileViewR]; [wasteDelegate setDiscardLeft:discardCardPileViewL discardRight:discardCardPileViewR]; [gameWindow display]; [gameWindow enableFlushWindow]; [gameWindow flushWindow]; /*----------------------------------------------------------------------- * Initialize the stockCardPileView to have a shuffled deck. *---------------------------------------------------------------------*/ [stockCardPile empty]; if (redeal) { [stockCardPile addDeck]; [stockCardPile shuffle]; // make a copy of the CardPile for restart option if (!prevDeck) { prevDeck = [[CardPile allocWithZone:[self zone]] initForCardSize:cardSize]; } else { [prevDeck empty]; [prevDeck setCardSize:cardSize]; } [prevDeck addCopyOfPile:stockCardPile]; } else { if (prevDeck) { // copy the saved deck back to the game deck [prevDeck setCardSize:cardSize]; [stockCardPile addCopyOfPile:prevDeck]; } else { // this shouldn't happen, but just in case... [stockCardPile empty]; [stockCardPile addDeck]; [stockCardPile shuffle]; } } /*----------------------------------------------------------------------- * Initialize the other piles as empty. *---------------------------------------------------------------------*/ [[wasteCardPileView cardPile] empty]; [[discardCardPileViewL cardPile] empty]; [[discardCardPileViewR cardPile] empty]; [wasteCardPileView display]; [discardCardPileViewL display]; [discardCardPileViewR display]; /*----------------------------------------------------------------------- * Remove the remaining gameCardPileViews from the view * hierarchy so they can be put back in correct order. * As cards are removed from the Pyramid during game play, the * Pyramid cardPileViews are removed from the view hierarchy to * allow access to the piles underneath. *---------------------------------------------------------------------*/ for (pileIndex = 0; pileIndex < 28; pileIndex++) { if ([gameCardPiles[pileIndex] superview]) [gameCardPiles[pileIndex] removeFromSuperview]; // Since throughout the game we keep removing these subviews // from their superview, we have to retain them so they don't // get released in the middle of the game. [gameCardPiles[pileIndex] retain]; } /*----------------------------------------------------------------------- * Set the attributes of the pyramid cardpiles *---------------------------------------------------------------------*/ for (pileIndex = 0; pileIndex < 28; pileIndex++) { [gameCardPiles[pileIndex] setDelegate:gameDelegate]; [gameCardPiles[pileIndex] setBackgroundColor:desktopColor]; [gameCardPiles[pileIndex] setCardSize:cardSize]; [gameCardPiles[pileIndex] setDelegate:gameDelegate]; [gameCardPiles[pileIndex] setDrawOutline:NO]; [gameCardPiles[pileIndex] resetBacking:self]; if (pileIndex > 0) [gameCardPiles[pileIndex] setCoversOthers:YES]; } /*----------------------------------------------------------------------- * Initialize and deal cards to the 28 "game piles" *---------------------------------------------------------------------*/ for (pileIndex = 0; pileIndex < 28; pileIndex++) { CardPile* userPile; Card* tempCard; /*------------------------------------------------------------------- * Reinsert the game pile view in the proper hierachy. * The views are unlinked during game play. *-----------------------------------------------------------------*/ [[stockCardPileView superview] addSubview:gameCardPiles[pileIndex]]; /*------------------------------------------------------------------- * Deal the cards. *-----------------------------------------------------------------*/ userPile = [gameCardPiles[pileIndex] cardPile]; [userPile empty]; tempCard = [stockCardPile topCard]; [tempCard retain]; [stockCardPile removeCard:tempCard]; [userPile insertCard:tempCard at:CS_TOP]; [tempCard release]; [[userPile topCard] flip]; } /*----------------------------------------------------------------------- * Update all views, then display the window. *---------------------------------------------------------------------*/ [gameWindow display]; [gameWindow makeKeyAndOrderFront:self]; } /*--------------------------------------------------------------------------- | | - endGame:sender | |---------------------------------------------------------------------------- | | End the game in progress. Discard the game window. | \----------------------------------------------------------------------------*/ - (void) endGame:sender { if (gameInProgress) { [self determineScore]; gameInProgress = NO; } // close the game window [super endGame:sender]; } /*--------------------------------------------------------------------------- | | - win | |---------------------------------------------------------------------------- | | Called when the game has been won. This is where you can insert fancy | winning routines, or just call the default (boring) routine. | \----------------------------------------------------------------------------*/ - (void) win { [super win]; // replace this with something wonderful } /*--------------------------------------------------------------------------- | | - checkForWin | |---------------------------------------------------------------------------- | | Called to check the state of the game. Always override (unless your | game is impossible to win). This is ugly because it handles winning | and keeping track of the score. | \----------------------------------------------------------------------------*/ - (void) checkForWin { int i, j; int total; NSArray *viewList = [[gameWindow contentView] subviews]; BOOL didMatch; total = [viewList count]; /*----------------------------------------------------------------------- * * Points for clearing the pyramid... * *---------------------------------------------------------------------*/ for (j = 0, didMatch = NO; j < total && !pyramidEmpty && !didMatch; j++) { CardPileView* theView = [viewList objectAtIndex:j]; for (i = 0; i < 28 && !didMatch; i++) { if (theView == gameCardPiles[i]) didMatch = YES; } } if (!didMatch && !pyramidEmpty) { switch ([self dealCount]) { case 1: [(PyramidPrefs*)prefs setPyramidScore:[(PyramidPrefs*)prefs pyramidScore] + 50]; break; case 2: [(PyramidPrefs*)prefs setPyramidScore:[(PyramidPrefs*)prefs pyramidScore] + 35]; break; case 3: [(PyramidPrefs*)prefs setPyramidScore:[(PyramidPrefs*)prefs pyramidScore] + 20]; break; default: break; } pyramidEmpty = YES; } /*----------------------------------------------------------------------- * * Cleared everything; you win. * *---------------------------------------------------------------------*/ if ([[discardCardPileViewL cardPile] cardCount] + [[discardCardPileViewR cardPile] cardCount] == 52) { [self win]; gameInProgress = NO; } /*----------------------------------------------------------------------- * * If the stock pile is empty and we have used both redeals AND the * pyramid is empty, then it's time to count the remaining cards. * *---------------------------------------------------------------------*/ if (pyramidEmpty && [[stockCardPileView cardPile] cardCount] == 0 && [self dealCount] == 3) { [self determineScore]; gameInProgress = NO; } gameInProgress = YES; } /*--------------------------------------------------------------------------- | | - (int)dealCount | | returns: (int) the number of deals so far (1, 2, 3, ...) | |---------------------------------------------------------------------------- | | The deal count is incremented everytime the deck is flipped. | \----------------------------------------------------------------------------*/ - (int) dealCount { return dealCount; } /*--------------------------------------------------------------------------- | | - setDealCount:(int)count | |---------------------------------------------------------------------------- | | Set the deal count. This is the number of passes through the stock. \----------------------------------------------------------------------------*/ - (void) setDealCount:(int)count { dealCount = count; } /*--------------------------------------------------------------------------- | | - incDealCount | |---------------------------------------------------------------------------- | | Add one to the deal count. | \----------------------------------------------------------------------------*/ - (void) incDealCount { dealCount++; } /*--------------------------------------------------------------------------- | | - determineScore | |---------------------------------------------------------------------------- | | Subtract the remaining cards from the current score. | \----------------------------------------------------------------------------*/ - (void) determineScore { int i; int total = 0; for (i = 0; i < 28; i++) { total += [[gameCardPiles[i] cardPile] cardCount]; } total += [[stockCardPileView cardPile] cardCount]; total += [[wasteCardPileView cardPile] cardCount]; [(PyramidPrefs*)prefs setPyramidScore:[(PyramidPrefs*)prefs pyramidScore] - total]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.