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.