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