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.