1 #include <math.h>
2 #include <limits.h>
3 #include "platform.h"
4 
5 #ifndef DATADIR
6 #error "The DATADIR macro is undefined."
7 #endif
8 
9 struct brogueConsole currentConsole;
10 
11 char dataDirectory[BROGUE_FILENAME_MAX] = STRINGIFY(DATADIR);
12 boolean serverMode = false;
13 boolean hasGraphics = false;
14 enum graphicsModes graphicsMode = TEXT_GRAPHICS;
15 boolean isCsvFormat = false;
16 
printCommandlineHelp()17 static void printCommandlineHelp() {
18     printf("%s",
19     "--help         -h          print this help message\n"
20     "--version      -V          print the version (i.e., " BROGUE_VERSION_STRING ")\n"
21     "--scores                   dump scores to output and exit immediately\n"
22     "-n                         start a new game, skipping the menu\n"
23     "-s seed                    start a new game with the specified numerical seed\n"
24     "-o filename[.broguesave]   open a save file (extension optional)\n"
25     "-v recording[.broguerec]   view a recording (extension optional)\n"
26 #ifdef BROGUE_WEB
27     "--server-mode              run the game in web-brogue server mode\n"
28 #endif
29 #ifdef BROGUE_SDL
30     "--size N                   starts the game at font size N (1 to 20)\n"
31     "--graphics     -G          enable graphical tiles\n"
32     "--hybrid       -H          enable hybrid graphics\n"
33     "--full-screen  -F          enable full screen\n"
34     "--no-gpu                   disable hardware-accelerated graphics and HiDPI\n"
35 #endif
36 #ifdef BROGUE_CURSES
37     "--term         -t          run in ncurses-based terminal mode\n"
38 #endif
39     "--stealth      -S          display stealth range\n"
40     "--no-effects   -E          disable color effects\n"
41     "--wizard       -W          run in wizard mode, invincible with powerful items\n"
42     "[--csv] --print-seed-catalog [START NUM LEVELS]\n"
43     "                           (optional csv format)\n"
44     "                           prints a catalog of the first LEVELS levels of NUM\n"
45     "                           seeds from seed START (defaults: 1 1000 5)\n"
46     "--data-dir DIRECTORY       specify directory containing game resources (experimental)\n"
47     );
48     return;
49 }
50 
badArgument(const char * arg)51 static void badArgument(const char *arg) {
52     printf("Bad argument: %s\n\n", arg);
53     printCommandlineHelp();
54 }
55 
tryParseUint64(char * str,uint64_t * num)56 boolean tryParseUint64(char *str, uint64_t *num) {
57     unsigned long long n;
58     char buf[100];
59     if (strlen(str)                 // we need some input
60         && sscanf(str, "%llu", &n)  // try to convert to number
61         && sprintf(buf, "%llu", n)  // convert back to string
62         && !strcmp(buf, str)) {     // compare (we need them equal)
63         *num = (uint64_t)n;
64         return true; // success
65     } else {
66         return false; // input was too large or not a decimal number
67     }
68 }
69 
main(int argc,char * argv[])70 int main(int argc, char *argv[])
71 {
72 
73 #if 0
74 #define TOD(x)  ((double) (x) / FP_FACTOR)
75     fixpt y, x1 = 1, x2 = FP_FACTOR * 70 / 100;
76     for (int i=0; i < 10; i++) {
77         y = fp_pow(x2, x1); printf("%.5f ^ %i = %.5f  (%lli)\n", TOD(x2), x1, TOD(y), y);
78         // y = fp_sqrt(x1); printf("sqrt(%.5f) = %.5f  (%lli)\n", TOD(x1), TOD(y), y);
79         x1 += 1;
80     }
81     exit(0);
82 #endif
83 
84 #ifdef BROGUE_SDL
85     currentConsole = sdlConsole;
86 #elif BROGUE_WEB
87     currentConsole = webConsole;
88 #elif BROGUE_CURSES
89     currentConsole = cursesConsole;
90 #endif
91 
92     rogue.nextGame = NG_NOTHING;
93     rogue.nextGamePath[0] = '\0';
94     rogue.nextGameSeed = 0;
95     rogue.wizard = false;
96     rogue.displayAggroRangeMode = false;
97     rogue.trueColorMode = false;
98 
99     enum graphicsModes initialGraphics = TEXT_GRAPHICS;
100 
101     int i;
102     for (i = 1; i < argc; i++) {
103         if (strcmp(argv[i], "--scores") == 0) {
104             // just dump the scores and quit!
105             dumpScores();
106             return 0;
107         }
108 
109         if (strcmp(argv[i], "--seed") == 0 || strcmp(argv[i], "-s") == 0) {
110             // pick a seed!
111             uint64_t seed;
112             if (i + 1 == argc || !tryParseUint64(argv[i + 1], &seed)) {
113                 printf("Invalid seed, please specify a number between 1 and 18446744073709551615\n");
114                 return 1;
115             }
116             if (seed != 0) {
117                 rogue.nextGameSeed = seed;
118                 rogue.nextGame = NG_NEW_GAME_WITH_SEED;
119             }
120             i++;
121             continue;
122         }
123 
124         if (strcmp(argv[i], "-n") == 0) {
125             if (rogue.nextGameSeed == 0) {
126                 rogue.nextGame = NG_NEW_GAME;
127             } else {
128                 rogue.nextGame = NG_NEW_GAME_WITH_SEED;
129             }
130             continue;
131         }
132 
133         if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--open") == 0) {
134             if (i + 1 < argc) {
135                 strncpy(rogue.nextGamePath, argv[i + 1], BROGUE_FILENAME_MAX);
136                 rogue.nextGamePath[BROGUE_FILENAME_MAX - 1] = '\0';
137                 rogue.nextGame = NG_OPEN_GAME;
138 
139                 if (!endswith(rogue.nextGamePath, GAME_SUFFIX)) {
140                     append(rogue.nextGamePath, GAME_SUFFIX, BROGUE_FILENAME_MAX);
141                 }
142 
143                 i++;
144                 continue;
145             }
146         }
147 
148         if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--view") == 0) {
149             if (i + 1 < argc) {
150                 strncpy(rogue.nextGamePath, argv[i + 1], BROGUE_FILENAME_MAX);
151                 rogue.nextGamePath[BROGUE_FILENAME_MAX - 1] = '\0';
152                 rogue.nextGame = NG_VIEW_RECORDING;
153 
154                 if (!endswith(rogue.nextGamePath, RECORDING_SUFFIX)) {
155                     append(rogue.nextGamePath, RECORDING_SUFFIX, BROGUE_FILENAME_MAX);
156                 }
157 
158                 i++;
159                 continue;
160             }
161         }
162 
163         if (strcmp(argv[i], "--print-seed-catalog") == 0) {
164             if (i + 3 < argc) {
165                 uint64_t startingSeed, numberOfSeeds;
166                 // Use converter for the type the next size up, because it returns signed
167                 unsigned int numberOfLevels = atol(argv[i + 3]);
168 
169                 if (tryParseUint64(argv[i+1], &startingSeed) && tryParseUint64(argv[i+2], &numberOfSeeds)
170                         && startingSeed > 0 && numberOfLevels <= 40) {
171                     printSeedCatalog(startingSeed, numberOfSeeds, numberOfLevels, isCsvFormat);
172                     return 0;
173                 }
174             } else {
175                 printSeedCatalog(1, 1000, 5, isCsvFormat);
176                 return 0;
177             }
178         }
179 
180         if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
181             printf("%s\n", BROGUE_VERSION_STRING);
182             return 0;
183         }
184 
185         if (!(strcmp(argv[i], "-?") && strcmp(argv[i], "-h") && strcmp(argv[i], "--help"))) {
186             printCommandlineHelp();
187             return 0;
188         }
189 
190         if (strcmp(argv[i], "-G") == 0 || strcmp(argv[i], "--graphics") == 0) {
191             initialGraphics = TILES_GRAPHICS;  // we call setGraphicsMode later
192             continue;
193         }
194 
195         if (strcmp(argv[i], "-H") == 0 || strcmp(argv[i], "--hybrid") == 0) {
196             initialGraphics = HYBRID_GRAPHICS;  // we call setGraphicsMode later
197             continue;
198         }
199 
200         if (strcmp(argv[i], "--csv") == 0 ) {
201             isCsvFormat = true;  // we call printSeedCatalog later
202             continue;
203         }
204 
205 #ifdef BROGUE_SDL
206         if (strcmp(argv[i], "--size") == 0) {
207             if (i + 1 < argc) {
208                 int size = atoi(argv[i + 1]);
209                 if (size > 0 && size <= 20) {
210                     windowWidth = round(pow(1.1, size) * 620.);
211                     // Height set automatically
212                 };
213 
214                 i++;
215                 continue;
216             }
217         }
218 
219         if (strcmp(argv[i], "-F") == 0 || strcmp(argv[i], "--full-screen") == 0) {
220             fullScreen = true;
221             continue;
222         }
223 
224         if (strcmp(argv[i], "--no-gpu") == 0) {
225             softwareRendering = true;
226             continue;
227         }
228 #endif
229 
230 #ifdef BROGUE_CURSES
231         if (strcmp(argv[i], "--term") == 0 || strcmp(argv[i], "-t") == 0) {
232             currentConsole = cursesConsole;
233             continue;
234         }
235 #endif
236 
237 #ifdef BROGUE_WEB
238         if(strcmp(argv[i], "--server-mode") == 0) {
239             currentConsole = webConsole;
240             rogue.nextGame = NG_NEW_GAME;
241             serverMode = true;
242             continue;
243         }
244 #endif
245 
246         if (strcmp(argv[i], "--stealth") == 0 || strcmp(argv[i], "-S") == 0) {
247             rogue.displayAggroRangeMode = true;
248             continue;
249         }
250 
251         if (strcmp(argv[i], "--no-effects") == 0 || strcmp(argv[i], "-E") == 0) {
252             rogue.trueColorMode = true;
253             continue;
254         }
255 
256         if (strcmp(argv[i], "--wizard") == 0 || strcmp(argv[i], "-W") == 0) {
257             rogue.wizard = true;
258             continue;
259         }
260 
261         if (strcmp(argv[i], "--data-dir") == 0) {
262             if (i + 1 < argc) {
263                 strcpy(dataDirectory, argv[++i]);
264                 continue;
265             }
266         }
267 
268         // maybe it ends with .broguesave or .broguerec, then?
269         if (endswith(argv[i], GAME_SUFFIX)) {
270             strncpy(rogue.nextGamePath, argv[i], BROGUE_FILENAME_MAX);
271             rogue.nextGamePath[BROGUE_FILENAME_MAX - 1] = '\0';
272             rogue.nextGame = NG_OPEN_GAME;
273             continue;
274         }
275 
276         if (endswith(argv[i], RECORDING_SUFFIX)) {
277             strncpy(rogue.nextGamePath, argv[i], BROGUE_FILENAME_MAX);
278             rogue.nextGamePath[BROGUE_FILENAME_MAX - 1] = '\0';
279             rogue.nextGame = NG_VIEW_RECORDING;
280             continue;
281         }
282 
283         badArgument(argv[i]);
284         return 1;
285     }
286 
287     hasGraphics = (currentConsole.setGraphicsMode != NULL);
288     // Now actually set graphics. We do this to ensure there is exactly one
289     // call, whether true or false
290     graphicsMode = setGraphicsMode(initialGraphics);
291 
292     loadKeymap();
293     currentConsole.gameLoop();
294 
295     return 0;
296 }
297 
298