This is GameSetup.m in view mode; [Download] [Up]
// GameSetup.m
// Part of Risk by Mike Ferris
#import "GameSetup.h"
#import "RiskController.h"
#import "Mover.h"
#import "ComputerPlayer.h"
#import "CardManager.h"
#import "DefaultManager.h"
#import "MapView.h"
#import <appkit/NXColorWell.h>
#import <appkit/Form.h>
#import <appkit/Matrix.h>
#import <appkit/ButtonCell.h>
#import "LanguageApp.h"
#import <appkit/Panel.h>
#import <appkit/Matrix.h>
#import <appkit/Text.h>
#import <appkit/NXImage.h>
#import <appkit/ScrollView.h>
#import <objc/Storage.h>
#import <appkit/PopUpList.h>
#import <objc/objc-load.h>
#import <stdlib.h> /* for getenv() */
#import <strings.h> /* for index() */
#import <sys/file.h> /* for access() */
#import <sys/param.h> /* for MAXPATHLEN */
#import <sys/dir.h> /* for opendir(), etc. */
@implementation GameSetup
+ initialize
{
if (self == [GameSetup class]) {
[self setVersion:1];
}
return self;
}
- appDidInit:sender
{
int i;
compPlayersExist = NO;
[setupPanel setFloatingPanel:YES];
[self initCPMenus];
for (i=0;i<6;i++) {
names[i]=NULL;
computerPlayers[i]=nil;
}
[self defaultSetup:self];
[self setCurrentFromPanel:self];
newGame = YES;
return self;
}
- free
{
int i;
for (i=0;i<6;i++) {
if (names[i]) free(names[i]);
}
return [super free];
}
- newGame:sender
{
newGame = YES;
[radio1 setEnabled:YES];
[radio2 setEnabled:YES];
[radio3 setEnabled:YES];
[radio4 setEnabled:YES];
[radio5 setEnabled:YES];
[radio6 setEnabled:YES];
[popup1 setEnabled:YES];
[popup2 setEnabled:YES];
[popup3 setEnabled:YES];
[popup4 setEnabled:YES];
[popup5 setEnabled:YES];
[popup6 setEnabled:YES];
[countryRadio setEnabled:YES];
[armyRadio setEnabled:YES];
[cardRadio setEnabled:YES];
[fortifyRadio setEnabled:YES];
if (compPlayersExist) {
[aboutMatrix setEnabled:YES];
} else {
[aboutMatrix setEnabled:NO];
}
[setupPanel makeKeyAndOrderFront:self];
return self;
}
- changeSettings:sender
{
newGame = NO;
[radio1 setEnabled:NO];
[radio2 setEnabled:NO];
[radio3 setEnabled:NO];
[radio4 setEnabled:NO];
[radio5 setEnabled:NO];
[radio6 setEnabled:NO];
[popup1 setEnabled:NO];
[popup2 setEnabled:NO];
[popup3 setEnabled:NO];
[popup4 setEnabled:NO];
[popup5 setEnabled:NO];
[popup6 setEnabled:NO];
[countryRadio setEnabled:YES];
[armyRadio setEnabled:YES];
[cardRadio setEnabled:NO];
[fortifyRadio setEnabled:YES];
[setupPanel makeKeyAndOrderFront:self];
if (compPlayersExist) {
[aboutMatrix setEnabled:YES];
} else {
[aboutMatrix setEnabled:NO];
}
return self;
}
- doneSetupAction:sender
{
int ret, numPlaying=0;
ret = [[sender selectedCell] tag];
if (ret == 1) {
// OK button. Accept values.
numPlaying = (([radio1 selectedCol] == S_NOTPLAYING)?0:1) +
(([radio2 selectedCol] == S_NOTPLAYING)?0:1) +
(([radio3 selectedCol] == S_NOTPLAYING)?0:1) +
(([radio4 selectedCol] == S_NOTPLAYING)?0:1) +
(([radio5 selectedCol] == S_NOTPLAYING)?0:1) +
(([radio6 selectedCol] == S_NOTPLAYING)?0:1);
if (numPlaying<=1) {
NXRunAlertPanel("Warning", "At least two players have to play.",
"OK", NULL, NULL);
} else {
[self setCurrentFromPanel:self];
[setupPanel orderOut:self];
[self writeDefaults];
if (newGame) {
[theMover startNewGame];
newGame = NO;
} else {
[theMover settingsChanged];
}
}
} else {
// Cancel button. revert.
[self revertToCurrent:self];
[setupPanel orderOut:self];
}
return self;
}
- setCurrentFromPanel:sender
{
const char *temp;
int i;
const char *classname = NULL;
id cpClass;
// names
for (i=0;i<6;i++) {
temp = [nameForm stringValueAt:i];
if (names[i]!=NULL) {
free(names[i]);
}
names[i]=(char *)malloc(strlen(temp)+1);
strcpy(names[i], temp);
}
// colors
colors[0] = [well1 color];
colors[1] = [well2 color];
colors[2] = [well3 color];
colors[3] = [well4 color];
colors[4] = [well5 color];
colors[5] = [well6 color];
if (newGame) {
// strategies
strategies[0] = [radio1 selectedCol];
strategies[1] = [radio2 selectedCol];
strategies[2] = [radio3 selectedCol];
strategies[3] = [radio4 selectedCol];
strategies[4] = [radio5 selectedCol];
strategies[5] = [radio6 selectedCol];
for (i=0;i<6;i++) {
if (computerPlayers[i] != nil) {
[computerPlayers[i] free];
}
if (strategies[i]==S_COMPUTER) {
if (!compPlayersExist) {
strategies[i]=S_HUMAN;
continue;
}
switch (i) {
case 0:
classname = [popup1 title];
break;
case 1:
classname = [popup2 title];
break;
case 2:
classname = [popup3 title];
break;
case 3:
classname = [popup4 title];
break;
case 4:
classname = [popup5 title];
break;
case 5:
classname = [popup6 title];
break;
default:
break;
}
cpClass = objc_getClass(classname);
computerPlayers[i] = [[cpClass allocFromZone:[self zone]]
initPlayerNum:i mover:theMover
gameSetup:self mapView:theMapView
cardManager:theCardManager];
}
}
// card values
cardRedemption = [cardRadio selectedRow];
}
// chosen or randomly selected countries
countryDistribution = [countryRadio selectedRow];
// initial armies per round
switch ([armyRadio selectedRow]) {
case A_BYONES:
initialArmyPlacement=1;
break;
case A_BYTHREES:
initialArmyPlacement=3;
break;
case A_BYFIVES:
initialArmyPlacement=5;
break;
default:
break;
}
// fortify rule
fortifyRule = [fortifyRadio selectedRow];
[self revertToCurrent:self]; // in case changes were made
return self;
}
- revertToCurrent:sender
{
int i;
for (i=0;i<6;i++) {
[nameForm setStringValue:names[i] at:i];
}
[well1 setColor:colors[0]];
[well2 setColor:colors[1]];
[well3 setColor:colors[2]];
[well4 setColor:colors[3]];
[well5 setColor:colors[4]];
[well6 setColor:colors[5]];
[radio1 selectCellAt:0:strategies[0]];
[radio2 selectCellAt:0:strategies[1]];
[radio3 selectCellAt:0:strategies[2]];
[radio4 selectCellAt:0:strategies[3]];
[radio5 selectCellAt:0:strategies[4]];
[radio6 selectCellAt:0:strategies[5]];
[cardRadio selectCellAt:cardRedemption:0];
[countryRadio selectCellAt:countryDistribution:0];
switch (initialArmyPlacement) {
case 1:
[armyRadio selectCellAt:A_BYONES:0];
break;
case 3:
[armyRadio selectCellAt:A_BYTHREES:0];
break;
case 5:
[armyRadio selectCellAt:A_BYFIVES:0];
break;
default:
break;
}
[fortifyRadio selectCellAt:fortifyRule:0];
return self;
}
- defaultSetup:sender
{
const char *tempStr;
float x[18];
int trash, options[4];
NXColor tempColor;
char name1[20], name2[20], name3[20], name4[20], name5[20], name6[20];
// set the color wells from the default manager
tempStr = [theDefaultManager playerColors];
trash = sscanf(tempStr, "%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, "
"%f, %f, %f, %f, %f, %f",
&(x[0]), &(x[1]), &(x[2]),
&(x[3]), &(x[4]), &(x[5]),
&(x[6]), &(x[7]), &(x[8]),
&(x[9]), &(x[10]), &(x[11]),
&(x[12]), &(x[13]), &(x[14]),
&(x[15]), &(x[16]), &(x[17]));
tempColor = NXConvertRGBToColor(x[0], x[1], x[2]);
[well1 setColor:tempColor];
tempColor = NXConvertRGBToColor(x[3], x[4], x[5]);
[well2 setColor:tempColor];
tempColor = NXConvertRGBToColor(x[6], x[7], x[8]);
[well3 setColor:tempColor];
tempColor = NXConvertRGBToColor(x[9], x[10], x[11]);
[well4 setColor:tempColor];
tempColor = NXConvertRGBToColor(x[12], x[13], x[14]);
[well5 setColor:tempColor];
tempColor = NXConvertRGBToColor(x[15], x[16], x[17]);
[well6 setColor:tempColor];
// set the names from the default manager
tempStr = [theDefaultManager playerNames];
trash = sscanf(tempStr, "%[^,], %[^,], %[^,], %[^,], %[^,], %[^,]",
name1, name2, name3, name4, name5, name6);
[nameForm setStringValue:name1 at:0];
[nameForm setStringValue:name2 at:1];
[nameForm setStringValue:name3 at:2];
[nameForm setStringValue:name4 at:3];
[nameForm setStringValue:name5 at:4];
[nameForm setStringValue:name6 at:5];
// set the options from the default manager
tempStr = [theDefaultManager setupOptions];
trash = sscanf(tempStr, "%d, %d, %d, %d", &(options[0]), &(options[1]),
&(options[2]), &(options[3]));
[countryRadio selectCellAt:options[0]:0];
[armyRadio selectCellAt:options[1]:0];
[cardRadio selectCellAt:options[2]:0];
[fortifyRadio selectCellAt:options[3]:0];
// set the radio buttons absolutely
[radio1 selectCellAt:0:0];
[radio2 selectCellAt:0:0];
[radio3 selectCellAt:0:0];
[radio4 selectCellAt:0:0];
[radio5 selectCellAt:0:0];
[radio6 selectCellAt:0:0];
return self;
}
- writeDefaults
{
char str[1000]="", buf[100];
float r, g, b;
int temp;
// first do the colors
NXConvertColorToRGB(colors[0], &r, &g, &b);
sprintf(buf, "%f, %f, %f, ", r, g, b); strcat(str, buf);
NXConvertColorToRGB(colors[1], &r, &g, &b);
sprintf(buf, "%f, %f, %f, ", r, g, b); strcat(str, buf);
NXConvertColorToRGB(colors[2], &r, &g, &b);
sprintf(buf, "%f, %f, %f, ", r, g, b); strcat(str, buf);
NXConvertColorToRGB(colors[3], &r, &g, &b);
sprintf(buf, "%f, %f, %f, ", r, g, b); strcat(str, buf);
NXConvertColorToRGB(colors[4], &r, &g, &b);
sprintf(buf, "%f, %f, %f, ", r, g, b); strcat(str, buf);
NXConvertColorToRGB(colors[5], &r, &g, &b);
sprintf(buf, "%f, %f, %f", r, g, b); strcat(str, buf);
[theDefaultManager setPlayerColors:str];
strcpy(str, "");
// now the names
sprintf(str, "%s, %s, %s, %s, %s, %s", names[0], names[1],
names[2], names[3], names[4], names[5]);
[theDefaultManager setPlayerNames:str];
strcpy(str, "");
// finally the options
switch (initialArmyPlacement) {
case 1:
temp=0;
break;
case 3:
temp=1;
break;
case 5:
temp=2;
break;
default:
temp=0;
break;
}
sprintf(str, "%d, %d, %d, %d", countryDistribution, temp,
cardRedemption, fortifyRule);
[theDefaultManager setSetupOptions:str];
return self;
}
- (int)numberOfPlayers
{
return (((strategies[0] == S_NOTPLAYING)?0:1) +
((strategies[1] == S_NOTPLAYING)?0:1) +
((strategies[2] == S_NOTPLAYING)?0:1) +
((strategies[3] == S_NOTPLAYING)?0:1) +
((strategies[4] == S_NOTPLAYING)?0:1) +
((strategies[5] == S_NOTPLAYING)?0:1));
}
- (NXColor)colorOfPlayer:(int)playerNum
{
return colors[playerNum];
}
- (int)strategyOfPlayer:(int)playerNum
{
return strategies[playerNum];
}
- (const char *)nameOfPlayer:(int)playerNum
{
return names[playerNum];
}
- (int)armiesForCardSet:(int)cardSetNum
{
if (cardSetNum==1) {
return 4;
}
switch(cardRedemption) {
case C_CONST:
return 5;
break;
case C_BYONES:
return cardSetNum+3;
break;
case C_BYFIVES:
if (cardSetNum<6) {
return (cardSetNum+1)*2;
} else {
return (cardSetNum-3)*5;
}
break;
}
return 0;
}
- (int)countryDistribution { return countryDistribution; }
- (int)initialArmyPlacement { return initialArmyPlacement; }
- (int)initialPlaceArmiesForPlayer:(int)p
{
if (strategies[p] == S_NOTPLAYING) {
return 0;
}
switch ([self numberOfPlayers]) {
case 2:
return 60-[theMapView numCountriesForPlayer:p];
break;
case 3:
return 36-[theMapView numCountriesForPlayer:p];
break;
case 4:
return 30-[theMapView numCountriesForPlayer:p];
break;
case 5:
return 25-[theMapView numCountriesForPlayer:p];
break;
case 6:
return 21-[theMapView numCountriesForPlayer:p];
break;
default:
return 0;
}
}
- (int)fortifyRule { return fortifyRule; }
- computerPlayerForPlayer:(int)p
{
if ((p>=0) && (p<=5)) {
return computerPlayers[p];
} else {
return nil;
}
}
- playerConquered:(int)loser
{
strategies[loser]=S_NOTPLAYING;
[self revertToCurrent:self];
return self;
}
- strategyPopupAction:sender
{
return self;
}
- computeInitialArmies:sender
{
int numPlayers=0;
numPlayers += (([radio1 selectedCol]==S_NOTPLAYING)?0:1);
numPlayers += (([radio2 selectedCol]==S_NOTPLAYING)?0:1);
numPlayers += (([radio3 selectedCol]==S_NOTPLAYING)?0:1);
numPlayers += (([radio4 selectedCol]==S_NOTPLAYING)?0:1);
numPlayers += (([radio5 selectedCol]==S_NOTPLAYING)?0:1);
numPlayers += (([radio6 selectedCol]==S_NOTPLAYING)?0:1);
switch (numPlayers) {
case 2:
[armiesTextField setIntValue:60];
break;
case 3:
[armiesTextField setIntValue:35];
break;
case 4:
[armiesTextField setIntValue:30];
break;
case 5:
[armiesTextField setIntValue:25];
break;
case 6:
[armiesTextField setIntValue:20];
break;
default:
[armiesTextField setStringValue:"--"];
}
return self;
}
- aboutAction:sender
{
int tag = [[sender selectedCell] tag];
id theRadio=nil, thePopup=nil;
char str[100];
id image=nil;
NXStream *stream;
switch (tag) {
case 0:
theRadio=radio1;
thePopup=popup1;
break;
case 1:
theRadio=radio2;
thePopup=popup2;
break;
case 2:
theRadio=radio3;
thePopup=popup3;
break;
case 3:
theRadio=radio4;
thePopup=popup4;
break;
case 4:
theRadio=radio5;
thePopup=popup5;
break;
case 5:
theRadio=radio6;
thePopup=popup6;
break;
}
switch ([theRadio selectedCol]) {
case 0:
// not playing
[aboutIconButton setImage:nil];
sprintf(str, "%d Not Playing", tag +1);
[aboutNameField setStringValue:str];
sprintf(str, "%s/NotPlaying.rtf", [NXApp applicationDirectory]);
stream = NXMapFile(str, NX_READONLY);
if (stream!=NULL) {
[[aboutScroll docView] readRichText:stream];
NXCloseMemory(stream, NX_FREEBUFFER);
} else {
[[aboutScroll docView] setText:""];
}
[aboutScroll display];
break;
case 1:
// human player
[aboutIconButton setIcon:"Human"];
sprintf(str, "%d Human Player", tag +1);
[aboutNameField setStringValue:str];
sprintf(str, "%s/Human.rtf", [NXApp applicationDirectory]);
stream = NXMapFile(str, NX_READONLY);
if (stream!=NULL) {
[[aboutScroll docView] readRichText:stream];
NXCloseMemory(stream, NX_FREEBUFFER);
} else {
[[aboutScroll docView] setText:""];
}
[aboutScroll display];
break;
case 2:
// computer player
if (compPlayersExist) {
sprintf(str, "%s/%s.cp/%s.tiff", [NXApp applicationDirectory],
[thePopup title], [thePopup title]);
image = [[NXImage allocFromZone:[self zone]] initFromFile:str];
if (image != nil) {
[aboutIconButton setImage:image];
}
sprintf(str, "%d %s.cp", tag +1, [thePopup title]);
[aboutNameField setStringValue:str];
sprintf(str, "%s/%s.cp/%s.rtf", [NXApp applicationDirectory],
[thePopup title], [thePopup title]);
stream = NXMapFile(str, NX_READONLY);
if (stream!=NULL) {
[[aboutScroll docView] readRichText:stream];
NXCloseMemory(stream, NX_FREEBUFFER);
} else {
[[aboutScroll docView] setText:""];
}
} else {
[aboutIconButton setImage:nil];
sprintf(str, "%d No Computer Players", tag +1);
[aboutNameField setStringValue:str];
[[aboutScroll docView] setText:""];
}
[aboutScroll display];
break;
}
[aboutPanel makeKeyAndOrderFront:self];
[NXApp runModalFor:aboutPanel];
[aboutPanel orderOut:self];
if (image != nil) {
[image free];
}
return self;
}
- aboutStopAction:sender
{
[NXApp stopModal];
return self;
}
#define MAX_CPNAME_SIZE 31
// load all the computer players. computer player directories reside in the
// app package. They are named with the name of the class and a ".cp"
// extension. Inside the Classname.cp directory there is at least a
// Classname.o file containing the subclass of ComputerPlayer which implements
// the computer player. It may also contain other files needed by the
// computer player implementation.
- initCPMenus
{
id cpNameStorage = [[Storage allocFromZone:[self zone]] initCount:0
elementSize:MAX_CPNAME_SIZE
description:"[MAX_CPNAME_SIZEc]"];
id tempStorage = [[Storage allocFromZone:[self zone]] initCount:0
elementSize:MAXPATHLEN
description:"[MAXPATHLENc]"];
BOOL keepTrying=YES;
DIR *dir;
struct direct *de;
NXStream *nxstderr;
char path[MAXPATHLEN], temp[MAXPATHLEN];
char *filenames[] = {path, NULL};
int i, numstrings;
NXAtom dirname;
nxstderr = NXOpenFile(2, NX_WRITEONLY);
dirname = [NXApp applicationDirectory];
dir = opendir(dirname);
if (dir == NULL) {
return self;
}
while ((de = readdir(dir)) != NULL)
{
BOOL ok;
// Ignore '.'-files (not really necessary, I guess)
if (de->d_name[0] == '.')
continue;
// Check that the file has the right extension
if (de->d_namlen < 4 ||
strcmp(&de->d_name[de->d_namlen-3], ".cp") != 0)
continue;
// refuse to load if the name matches a module already loaded
numstrings = [cpNameStorage count];
ok = YES;
strcpy(path, de->d_name);
*(rindex(path, '.')) = '\0';
for (i=0; i< numstrings; i++)
{
if (!strcmp(path, [cpNameStorage elementAt:i]))
{
ok = NO;
break;
}
}
if (!ok) continue;
// OK, all is well -- go load the little bugger
sprintf(temp, "%s.o", path);
sprintf(path, "%s/%s/%s", dirname, de->d_name, temp);
if (objc_loadModules(filenames, nxstderr, NULL, NULL, NULL) == 1) {
// Ugh, failed. Put the class name in tempStorage in case
// it can't be loaded because it's a subclass of another
// CP who hasn't been loaded yet.
[tempStorage addElement:path];
} else {
// it loaded so add it to the list.
// Smash out the '.' in ".../FooView.o"
*(rindex(path, '.')) = '\0';
[cpNameStorage addElement: rindex(path, '/') + 1];
}
}
closedir(dir);
// now loop and keep trying to load the ones in tempStorage. Keep trying
// as long as at least one of the failed ones succeeds each time through
// the loop
while (keepTrying) {
keepTrying=NO;
for (i=[tempStorage count]-1; i>=0; i--) {
strcpy(path, (char *)[tempStorage elementAt:i]);
if (objc_loadModules(filenames, nxstderr, NULL, NULL, NULL)!=1) {
// it loaded so add it to the list.
// Smash out the '.' in ".../FooView.o"
*(rindex(path, '.')) = '\0';
[cpNameStorage addElement: rindex(path, '/') + 1];
// since one loaded successfully, set the flag
keepTrying=YES;
// and delete it from the tempStorage
[tempStorage removeElementAt:i];
}
}
}
NXClose(nxstderr);
// now cpNameStorage contains a list of all the menu strings.
// we must add them to the menus in the panel.
numstrings = [cpNameStorage count];
if (numstrings > 0) {
[[[popup1 target] removeItemAt:0] free];
[[[popup2 target] removeItemAt:0] free];
[[[popup3 target] removeItemAt:0] free];
[[[popup4 target] removeItemAt:0] free];
[[[popup5 target] removeItemAt:0] free];
[[[popup6 target] removeItemAt:0] free];
[popup1 setTitle:[cpNameStorage elementAt:0]];
[popup2 setTitle:[cpNameStorage elementAt:0]];
[popup3 setTitle:[cpNameStorage elementAt:0]];
[popup4 setTitle:[cpNameStorage elementAt:0]];
[popup5 setTitle:[cpNameStorage elementAt:0]];
[popup6 setTitle:[cpNameStorage elementAt:0]];
compPlayersExist = YES;
}
for (i=0;i<numstrings;i++) {
[[popup1 target] addItem:[cpNameStorage elementAt:i]];
[[popup2 target] addItem:[cpNameStorage elementAt:i]];
[[popup3 target] addItem:[cpNameStorage elementAt:i]];
[[popup4 target] addItem:[cpNameStorage elementAt:i]];
[[popup5 target] addItem:[cpNameStorage elementAt:i]];
[[popup6 target] addItem:[cpNameStorage elementAt:i]];
}
[cpNameStorage free];
[tempStorage free];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.