This is CardManager.m in view mode; [Download] [Up]
// CardManager.m // Part of Risk by Mike Ferris #import "CardManager.h" #import <objc/List.h> #import <appkit/Application.h> #import <appkit/Button.h> #import <appkit/ButtonCell.h> #import <appkit/Matrix.h> #import <appkit/publicWraps.h> #import <appkit/Panel.h> #import "Random.h" #import "Card.h" #import "LanguageApp.h" #import "GameSetup.h" #import "MapView.h" #import "Country.h" #import "DeckInspector.h" #define CARDFILE "Card.data" #define CARDBACKFILE "Cards/CardBack.tiff" @implementation CardManager + initialize { if (self == [CardManager class]) { [self setVersion:1]; } return self; } - init { NXTypedStream *ts; [super init]; deckInspector = nil; rng = [[Random allocFromZone:[self zone]] init]; deck = [[List allocFromZone:[self zone]] init]; discards = [[List allocFromZone:[self zone]] init]; playerHand[0] = [[List allocFromZone:[self zone]] init]; playerHand[1] = [[List allocFromZone:[self zone]] init]; playerHand[2] = [[List allocFromZone:[self zone]] init]; playerHand[3] = [[List allocFromZone:[self zone]] init]; playerHand[4] = [[List allocFromZone:[self zone]] init]; playerHand[5] = [[List allocFromZone:[self zone]] init]; cardsPlayed = [[List allocFromZone:[self zone]] init]; cardBack = [[Card allocFromZone:[self zone]] initCountry:-1 type:NIL_TYPE imageFile:CARDBACKFILE]; // fill card list ts = NXOpenTypedStreamForFile([NXApp applicationFile:CARDFILE], NX_READONLY); cardList = NXReadObject(ts); NXCloseTypedStream(ts); setsTurnedIn=0; return self; } - appDidInit:sender { return self; } - free { int i; [cardList free]; [cardBack free]; [discards free]; for (i=0;i<6;i++) { [playerHand[i] free]; } [rng free]; [deck freeObjects]; [deck free]; return [super free]; } // low-level list manipulators - shuffle:list // shuffle the list given into a random order { id listcopy; listcopy = [list copy]; [list empty]; [self shuffle:listcopy into:list]; [listcopy free]; return self; } - shuffle:list1 into:list2 // shuffle the list given into the second list. // in other words: copy list1 into list2 in a random order // if there are cards in list2 already, they stay at the beginning // new cards are added to the end. { // loop takes a random item out of list1 and appends it to list2 while ([list1 count]>0) { [list2 addObject:[list1 removeObjectAt:[rng randMax:[list1 count]-1]]]; } return self; } - reset { int i; id listcopy; setsTurnedIn=0; listcopy = [cardList copy]; [self shuffle:listcopy into:deck]; [listcopy free]; [discards empty]; for (i=0;i<6;i++) { [playerHand[i] empty]; } if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } return self; } // methods for manipulating player's hands - playerDrawsCard:(int)p { if ([deck count]<3) { [self shuffle:discards into:deck]; } [playerHand[p] addObject:[deck removeObjectAt:0]]; if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } return self; } - playersHand:(int)p { return playerHand[p]; } - (int)numCardsForPlayer:(int)p { return [playerHand[p] count]; } - (BOOL)canMakeSetCard1:(Card *)c1 card2:(Card *)c2 card3:(Card *)c3 { if ((c1==nil) || (c2==nil) || (c3==nil)) { return NO; } else { // any jokers? then YES if (([c1 type] == NIL_TYPE) || ([c2 type] == NIL_TYPE) || ([c3 type] == NIL_TYPE)) { return YES; } else if (([c1 type] == [c2 type]) && ([c1 type] == [c3 type])) { return YES; } else if (([c1 type] != [c2 type]) && ([c1 type] != [c3 type]) && ([c2 type] != [c3 type])) { return YES; } return NO; } return NO; } - (BOOL)canPlayThree:cl // given a list with three elements return YES if they can be played // otherwise NO { if ([cl count] < 3) { return NO; } else if ([cl count] == 3) { return [self canMakeSetCard1:[cl objectAt:0] card2:[cl objectAt:1] card3:[cl objectAt:2]]; } return NO; } - (BOOL)canPlayFrom:cl // returns YES if three of the cards can be played. NO otherwise { if ([cl count] < 3) { return NO; } else if ([cl count] == 3) { return [self canPlayThree:cl]; } else if ([cl count] >= 5) { return YES; } else { // there are 4 cards so run permutations if ([self canMakeSetCard1:[cl objectAt:0] card2:[cl objectAt:1] card3:[cl objectAt:2]]) { return YES; } else if ([self canMakeSetCard1:[cl objectAt:0] card2:[cl objectAt:2] card3:[cl objectAt:3]]) { return YES; } else if ([self canMakeSetCard1:[cl objectAt:0] card2:[cl objectAt:1] card3:[cl objectAt:3]]) { return YES; } else if ([self canMakeSetCard1:[cl objectAt:1] card2:[cl objectAt:2] card3:[cl objectAt:3]]) { return YES; } else { return NO; } } return NO; } - (BOOL)canPlayerPlay:(int)p { return [self canPlayFrom:playerHand[p]]; } - player:(int)p1 takesCardsOf:(int)p2 { while ([playerHand[p2] count] > 0) { [playerHand[p1] addObject:[playerHand[p2] removeObjectAt:0]]; if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } } return self; } - (int)player:(int)p playsCards:cl { id theCard, theCountry; id countryList = [theMapView countryList]; int armiesToGive, i; if ([cl count] != 3) { // has to be exactly three cards return -1; } if ([self canPlayThree:cl]) { for (i=0;i<3;i++) { theCard = [cl objectAt:i]; if ([theCard countryNum]>=0) { theCountry = [countryList objectAt:[theCard countryNum]]; if ([theCountry player]==p) { [theCountry addArmies:2]; [theMapView displayCountry:theCountry]; } } [discards addObject:[playerHand[p] removeObject:theCard]]; } armiesToGive = [theGameSetup armiesForCardSet:setsTurnedIn]; setsTurnedIn++; if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } return armiesToGive; } else { return -1; } } // high-level interface routines - setupPanel:(BOOL)canPlay forPlayer:(int)p { int c=[playerHand[p] count]; int i; id tempCell, theCard; id countryList=[theMapView countryList]; currentPlayer = p; currentSetsTurnedIn = 0; [cardsPlayed empty]; if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } // set up the done and cancel all buttons and the force & amassed fields [doneButton setEnabled:NO]; [cancelButton setEnabled:YES]; [amassedTextField setIntValue:0]; currentForceNum=0; if ((c>=5) && (canPlay)) { [forceTextField setStringValue:"You must turn in cards"]; [cancelButton setEnabled:NO]; currentForceNum++; } else { [forceTextField setStringValue:""]; } if (c>=8) { currentForceNum++; } // set the play matrix playMatrixCount=0; for (i=0;i<3;i++) { tempCell=[playMatrix cellAt:0 :i]; [tempCell setImage:nil]; currentSet[i]=nil; currentIndices[i]=-1; [[playStarMatrix cellAt:0 :i] setImage:nil]; } if (canPlay) { [playMatrix setEnabled:YES]; } else { [playMatrix setEnabled:NO]; } [playMatrix display]; [playStarMatrix setEnabled:NO]; [playStarMatrix display]; // set the play box, turn in button, and worth text field [turnInButton setEnabled:NO]; [worthTextField setIntValue:[theGameSetup armiesForCardSet:setsTurnedIn+1]]; // set the handMatrix for (i=0;i<9;i++) { tempCell=[handMatrix cellAt:0 :i]; // if we're still in the buttons less than num of player's cards // set the image if (i<c) { theCard = [playerHand[p] objectAt:i]; [tempCell setImage:[theCard image]]; if ([theCard countryNum] >= 0) { if ([[countryList objectAt:[theCard countryNum]] player] == p) { [[handStarMatrix cellAt:0 :i] setIcon:"LittleStar"]; } else { [[handStarMatrix cellAt:0 :i] setImage:nil]; } } else { [[handStarMatrix cellAt:0 :i] setImage:nil]; } } else { [tempCell setImage:nil]; [[handStarMatrix cellAt:0 :i] setImage:nil]; } } if (canPlay) { [handMatrix setEnabled:YES]; } else { [handMatrix setEnabled:NO]; } [handMatrix display]; [handStarMatrix setEnabled:NO]; [handStarMatrix display]; return self; } - (int)runCardPanel:(BOOL)canPlay forPlayer:(int)p // returns number of armies turned in { int retVal, armiesToGive=0; id theCard, theCountry; id countryList=[theMapView countryList]; // first set up the panel [self setupPanel:canPlay forPlayer:p]; // now run it retVal = [NXApp runModalFor:theCardPanel]; [theCardPanel orderOut:self]; if (retVal==0) { // done button pressed. turn in the sets and give the armies while ([cardsPlayed count]>0) { theCard = [cardsPlayed removeObjectAt:0]; if ([theCard countryNum]>=0) { theCountry = [countryList objectAt:[theCard countryNum]]; if ([theCountry player]==p) { [theCountry addArmies:2]; [theMapView displayCountry:theCountry]; } } [discards addObject:theCard]; [playerHand[p] removeObject:theCard]; if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } } armiesToGive = [amassedTextField intValue]; setsTurnedIn+=currentSetsTurnedIn; return armiesToGive; } else if (retVal == 1) { // cancel pressed, clean up and do nothing [cardsPlayed empty]; return 0; } else { NXRunAlertPanel("Debug", "Error: unexpected return value.", "OK", NULL, NULL); return 0; } if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } return 0; } - handAction:sender { int index = [[sender selectedCell] tag]; // if there is room in the box and they didn't click on an empty cell if ((playMatrixCount<3) && (index < [playerHand[currentPlayer] count])) { if ([[handMatrix cellAt:0 :index] image]==[cardBack image]) { return nil; } if (playMatrixCount==2) { // check to see if this one will make a third if (![self canMakeSetCard1:currentSet[0] card2:currentSet[1] card3:[playerHand[currentPlayer] objectAt:index]]) { NXBeep(); return nil; } } // turn the card over [[handMatrix cellAt:0 :index] setImage:[cardBack image]]; // record which card it is currentSet[playMatrixCount]=[playerHand[currentPlayer] objectAt:index]; currentIndices[playMatrixCount]=index; // put it down below [[playMatrix cellAt:0 :playMatrixCount] setImage: [currentSet[playMatrixCount] image]]; [[playStarMatrix cellAt:0 :playMatrixCount] setImage: [[handStarMatrix cellAt:0 :index] image]]; playMatrixCount++; } [handMatrix display]; [playMatrix display]; [handStarMatrix display]; [playStarMatrix display]; if (playMatrixCount==3) { [turnInButton setEnabled:YES]; } return self; } - playAction:sender { int index = [[sender selectedCell] tag]; int i; // put it back up above if (index < playMatrixCount) { [[handMatrix cellAt:0 :currentIndices[index]] setImage: [currentSet[index] image]]; // move the others back a step for (i=index;i<playMatrixCount-1;i++) { [[playMatrix cellAt:0 :i] setImage: [[playMatrix cellAt:0 :i+1] image]]; [[playStarMatrix cellAt:0 :i] setImage: [[playStarMatrix cellAt:0 :i+1] image]]; currentSet[i] = currentSet[i+1]; currentIndices[i] = currentIndices[i+1]; } [[playMatrix cellAt:0 :playMatrixCount-1] setImage:nil]; [[playStarMatrix cellAt:0 :playMatrixCount-1] setImage:nil]; currentSet[playMatrixCount-1] = nil; currentIndices[playMatrixCount-1] = -1; playMatrixCount--; } [handMatrix display]; [playMatrix display]; [handStarMatrix display]; [playStarMatrix display]; if (playMatrixCount<3) { [turnInButton setEnabled:NO]; } return self; } - stopAction:sender { [NXApp stopModal:[sender tag]]; return self; } - turnInAction:sender { int i; if (playMatrixCount==3) { for (i=0;i<3;i++) { [cardsPlayed addObject:currentSet[i]]; currentSet[i]=nil; currentIndices[i]=-1; [[playMatrix cellAt:0 :i] setImage:nil]; [[playStarMatrix cellAt:0 :i] setImage:nil]; } playMatrixCount=0; [playMatrix display]; [playStarMatrix display]; [amassedTextField setIntValue:[amassedTextField intValue] + [theGameSetup armiesForCardSet:setsTurnedIn+currentSetsTurnedIn+1]]; currentSetsTurnedIn++; if (currentSetsTurnedIn>=currentForceNum) { [doneButton setEnabled:YES]; } } [worthTextField setIntValue:[theGameSetup armiesForCardSet:setsTurnedIn+currentSetsTurnedIn+1]]; if ((deckInspector != nil) && ([deckInspector panelOnScreen])) { [deckInspector displayAllDecks]; } return self; } - setDeckInspector:anObject { deckInspector = anObject; [deckInspector setCardList:cardList deck:deck discards:discards player1:playerHand[0] player2:playerHand[1] player3:playerHand[2] player4:playerHand[3] player5:playerHand[4] player6:playerHand[5] cardsPlayed:cardsPlayed]; [deckInspector displayAllDecks]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.