Annotation of brogue-ce/src/platform/platformdependent.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * platformdependent.c
3: * Brogue
4: *
5: * Created by Brian Walker on 4/13/10.
6: * Copyright 2010. All rights reserved.
7: *
8: * This file is part of Brogue.
9: *
10: * Brogue is free software: you can redistribute it and/or modify
11: * it under the terms of the GNU General Public License as published by
12: * the Free Software Foundation, either version 3 of the License, or
13: * (at your option) any later version.
14: *
15: * Brogue is distributed in the hope that it will be useful,
16: * but WITHOUT ANY WARRANTY; without even the implied warranty of
17: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: * GNU General Public License for more details.
19: *
20: * You should have received a copy of the GNU General Public License
21: * along with Brogue. If not, see <http://www.gnu.org/licenses/>.
22: */
23:
24: #include <ctype.h>
25: #include <stdio.h>
26: #include <string.h>
27: #include <time.h>
28: #include <sys/types.h>
29: #include <sys/stat.h>
30: #include <dirent.h>
31:
32: #include "platform.h"
33:
34: typedef struct brogueScoreEntry {
35: long int score;
36: long int dateNumber; // in seconds
37: char dateText[COLS]; // in the form mm/dd/yy
38: char description[COLS];
39: } brogueScoreEntry;
40:
41: brogueScoreEntry scoreBuffer[HIGH_SCORES_COUNT];
42:
43: unsigned int glyphToUnicode(enum displayGlyph glyph) {
44: if (glyph < 128) return glyph;
45:
46: switch (glyph) {
47: case G_UP_ARROW: return U_UP_ARROW;
48: case G_DOWN_ARROW: return U_DOWN_ARROW;
49: case G_POTION: return '!';
50: case G_GRASS: return '"';
51: case G_WALL: return '#';
52: case G_DEMON: return '&';
53: case G_OPEN_DOOR: return '\'';
54: case G_GOLD: return '*';
55: case G_CLOSED_DOOR: return '+';
56: case G_RUBBLE: return ',';
57: case G_KEY: return '-';
58: case G_BOG: return '~';
59: case G_CHAIN_TOP_LEFT:
60: case G_CHAIN_BOTTOM_RIGHT:
61: return '\\';
62: case G_CHAIN_TOP_RIGHT:
63: case G_CHAIN_BOTTOM_LEFT:
64: return '/';
65: case G_CHAIN_TOP:
66: case G_CHAIN_BOTTOM:
67: return '|';
68: case G_CHAIN_LEFT:
69: case G_CHAIN_RIGHT:
70: return '-';
71: case G_FOOD: return ';';
72: case G_UP_STAIRS: return '<';
73: case G_VENT: return '=';
74: case G_DOWN_STAIRS: return '>';
75: case G_PLAYER: return '@';
76: case G_BOG_MONSTER: return 'B';
77: case G_CENTAUR: return 'C';
78: case G_DRAGON: return 'D';
79: case G_FLAMEDANCER: return 'F';
80: case G_GOLEM: return 'G';
81: case G_TENTACLE_HORROR: return 'H';
82: case G_IFRIT: return 'I';
83: case G_JELLY: return 'J';
84: case G_KRAKEN: return 'K';
85: case G_LICH: return 'L';
86: case G_NAGA: return 'N';
87: case G_OGRE: return 'O';
88: case G_PHANTOM: return 'P';
89: case G_REVENANT: return 'R';
90: case G_SALAMANDER: return 'S';
91: case G_TROLL: return 'T';
92: case G_UNDERWORM: return 'U';
93: case G_VAMPIRE: return 'V';
94: case G_WRAITH: return 'W';
95: case G_ZOMBIE: return 'Z';
96: case G_ARMOR: return '[';
97: case G_STAFF: return '/';
98: case G_WEB: return ':';
99: case G_MOUND: return 'a';
100: case G_BLOAT: return 'b';
101: case G_CENTIPEDE: return 'c';
102: case G_DAR_BLADEMASTER: return 'd';
103: case G_EEL: return 'e';
104: case G_FURY: return 'f';
105: case G_GOBLIN: return 'g';
106: case G_IMP: return 'i';
107: case G_JACKAL: return 'j';
108: case G_KOBOLD: return 'k';
109: case G_MONKEY: return 'm';
110: case G_PIXIE: return 'p';
111: case G_RAT: return 'r';
112: case G_SPIDER: return 's';
113: case G_TOAD: return 't';
114: case G_BAT: return 'v';
115: case G_WISP: return 'w';
116: case G_PHOENIX: return 'P';
117: case G_ALTAR: return '|';
118: case G_LIQUID: return '~';
119: case G_FLOOR: return U_MIDDLE_DOT;
120: case G_CHASM: return U_FOUR_DOTS;
121: case G_TRAP: return U_DIAMOND;
122: case G_FIRE: return U_FLIPPED_V;
123: case G_FOLIAGE: return U_ARIES;
124: case G_AMULET: return U_ANKH;
125: case G_SCROLL: return U_MUSIC_NOTE;
126: case G_RING: return U_CIRCLE;
127: case G_WEAPON: return U_UP_ARROW;
128: case G_GEM: return U_FILLED_CIRCLE;
129: case G_TOTEM: return U_NEUTER;
130: case G_GOOD_MAGIC: return U_FILLED_CIRCLE_BARS;
131: case G_BAD_MAGIC: return U_CIRCLE_BARS;
132: case G_DOORWAY: return U_OMEGA;
133: case G_CHARM: return U_LIGHTNING_BOLT;
134: case G_WALL_TOP: return '#';
135: case G_DAR_PRIESTESS: return 'd';
136: case G_DAR_BATTLEMAGE: return 'd';
137: case G_GOBLIN_MAGIC: return 'g';
138: case G_GOBLIN_CHIEFTAN: return 'g';
139: case G_OGRE_MAGIC: return 'O';
140: case G_GUARDIAN: return U_ESZETT;
141: case G_WINGED_GUARDIAN: return U_ESZETT;
142: case G_EGG: return U_FILLED_CIRCLE;
143: case G_WARDEN: return 'Y';
144: case G_DEWAR: return '&';
145: case G_ANCIENT_SPIRIT: return 'M';
146: case G_LEVER: return '/';
147: case G_LEVER_PULLED: return '\\';
148: case G_BLOODWORT_STALK: return U_ARIES;
149: case G_FLOOR_ALT: return U_MIDDLE_DOT;
150: case G_UNICORN: return U_U_ACUTE;
151: case G_TURRET: return U_FILLED_CIRCLE;
152: case G_WAND: return '~';
153: case G_GRANITE: return '#';
154: case G_CARPET: return U_MIDDLE_DOT;
155: case G_CLOSED_IRON_DOOR: return '+';
156: case G_OPEN_IRON_DOOR: return '\'';
157: case G_TORCH: return '#';
158: case G_CRYSTAL: return '#';
159: case G_PORTCULLIS: return '#';
160: case G_BARRICADE: return '#';
161: case G_STATUE: return U_ESZETT;
162: case G_CRACKED_STATUE: return U_ESZETT;
163: case G_CLOSED_CAGE: return '#';
164: case G_OPEN_CAGE: return '|';
165: case G_PEDESTAL: return '|';
166: case G_CLOSED_COFFIN: return '-';
167: case G_OPEN_COFFIN: return '-';
168: case G_MAGIC_GLYPH: return U_FOUR_DOTS;
169: case G_BRIDGE: return '=';
170: case G_BONES: return ',';
171: case G_ELECTRIC_CRYSTAL: return U_CURRENCY;
172: case G_ASHES: return '\'';
173: case G_BEDROLL: return '=';
174: case G_BLOODWORT_POD: return '*';
175: case G_VINE: return ':';
176: case G_NET: return ':';
177: case G_LICHEN: return '"';
178: case G_PIPES: return '+';
179: case G_SAC_ALTAR: return '|';
180: case G_ORB_ALTAR: return '|';
181:
182: default:
183: brogueAssert(false);
184: return '?';
185: }
186: }
187:
188:
189: void plotChar(enum displayGlyph inputChar,
190: short xLoc, short yLoc,
191: short foreRed, short foreGreen, short foreBlue,
192: short backRed, short backGreen, short backBlue) {
193: currentConsole.plotChar(inputChar, xLoc, yLoc, foreRed, foreGreen, foreBlue, backRed, backGreen, backBlue);
194: }
195:
196: void pausingTimerStartsNow() {
197:
198: }
199:
200: boolean shiftKeyIsDown() {
201: return currentConsole.modifierHeld(0);
202: }
203: boolean controlKeyIsDown() {
204: return currentConsole.modifierHeld(1);
205: }
206:
207: void nextKeyOrMouseEvent(rogueEvent *returnEvent, boolean textInput, boolean colorsDance) {
208: currentConsole.nextKeyOrMouseEvent(returnEvent, textInput, colorsDance);
209: }
210:
211: boolean pauseForMilliseconds(short milliseconds) {
212: return currentConsole.pauseForMilliseconds(milliseconds);
213: }
214:
215: void notifyEvent(short eventId, int data1, int data2, const char *str1, const char *str2) {
216: if (currentConsole.notifyEvent) {
217: currentConsole.notifyEvent(eventId, data1, data2, str1, str2);
218: }
219: }
220:
221: boolean takeScreenshot() {
222: if (currentConsole.takeScreenshot) {
223: return currentConsole.takeScreenshot();
224: } else {
225: return false;
226: }
227: }
228:
229: boolean setGraphicsEnabled(boolean state) {
230: if (currentConsole.setGraphicsEnabled) {
231: return currentConsole.setGraphicsEnabled(state);
232: } else {
233: return false;
234: }
235: }
236:
237: // creates an empty high scores file
238: void initScores() {
239: short i;
240: FILE *scoresFile;
241:
242: scoresFile = fopen("BrogueHighScores.txt", "w");
243: for (i=0; i<HIGH_SCORES_COUNT; i++) {
244: fprintf(scoresFile, "%li\t%li\t%s", (long) 0, (long) 0, "(empty entry)\n");
245: }
246: fclose(scoresFile);
247: }
248:
249: // sorts the entries of the scoreBuffer global variable by score in descending order;
250: // returns the sorted line number of the most recent entry
251: short sortScoreBuffer() {
252: short i, j, highestUnsortedLine, mostRecentSortedLine = 0;
253: long highestUnsortedScore, mostRecentDate;
254: brogueScoreEntry sortedScoreBuffer[HIGH_SCORES_COUNT];
255: boolean lineSorted[HIGH_SCORES_COUNT];
256:
257: mostRecentDate = 0;
258:
259: for (i=0; i<HIGH_SCORES_COUNT; i++) {
260: lineSorted[i] = false;
261: }
262:
263: for (i=0; i<HIGH_SCORES_COUNT; i++) {
264: highestUnsortedLine = 0;
265: highestUnsortedScore = 0;
266: for (j=0; j<HIGH_SCORES_COUNT; j++) {
267: if (!lineSorted[j] && scoreBuffer[j].score >= highestUnsortedScore) {
268: highestUnsortedLine = j;
269: highestUnsortedScore = scoreBuffer[j].score;
270: }
271: }
272: sortedScoreBuffer[i] = scoreBuffer[highestUnsortedLine];
273: lineSorted[highestUnsortedLine] = true;
274: }
275:
276: // copy the sorted list back into scoreBuffer, remember the most recent entry
277: for (i=0; i<HIGH_SCORES_COUNT; i++) {
278: scoreBuffer[i] = sortedScoreBuffer[i];
279: if (scoreBuffer[i].dateNumber > mostRecentDate) {
280: mostRecentDate = scoreBuffer[i].dateNumber;
281: mostRecentSortedLine = i;
282: }
283: }
284: return mostRecentSortedLine;
285: }
286:
287: // loads the BrogueHighScores.txt file into the scoreBuffer global variable
288: // score file format is: score, tab, date in seconds, tab, description, newline.
289: short loadScoreBuffer() {
290: short i;
291: FILE *scoresFile;
292: time_t rawtime;
293: struct tm * timeinfo;
294:
295: scoresFile = fopen("BrogueHighScores.txt", "r");
296:
297: if (scoresFile == NULL) {
298: initScores();
299: scoresFile = fopen("BrogueHighScores.txt", "r");
300: }
301:
302: for (i=0; i<HIGH_SCORES_COUNT; i++) {
303: // load score and also the date in seconds
304: fscanf(scoresFile, "%li\t%li\t", &(scoreBuffer[i].score), &(scoreBuffer[i].dateNumber));
305:
306: // load description
307: fgets(scoreBuffer[i].description, COLS, scoresFile);
308: // strip the newline off the end
309: scoreBuffer[i].description[strlen(scoreBuffer[i].description) - 1] = '\0';
310:
311: // convert date to DATE_FORMAT
312: rawtime = (time_t) scoreBuffer[i].dateNumber;
313: timeinfo = localtime(&rawtime);
314: strftime(scoreBuffer[i].dateText, DCOLS, DATE_FORMAT, timeinfo);
315: }
316: fclose(scoresFile);
317: return sortScoreBuffer();
318: }
319:
320: void loadKeymap() {
321: int i;
322: FILE *f;
323: char buffer[512];
324:
325: f = fopen("keymap.txt", "r");
326:
327: if (f != NULL) {
328: while (fgets(buffer, 512, f) != NULL) {
329: // split it in two (destructively)
330: int mode = 1;
331: char *input_name = NULL, *output_name = NULL;
332: for (i = 0; buffer[i]; i++) {
333: if (isspace(buffer[i])) {
334: buffer[i] = '\0';
335: mode = 1;
336: } else {
337: if (mode) {
338: if (input_name == NULL) input_name = buffer + i;
339: else if (output_name == NULL) output_name = buffer + i;
340: }
341: mode = 0;
342: }
343: }
344: if (input_name != NULL && output_name != NULL) {
345: if (input_name[0] == '#') continue; // must be a comment
346:
347: currentConsole.remap(input_name, output_name);
348: }
349: }
350: fclose(f);
351: }
352: }
353:
354:
355: // saves the scoreBuffer global variable into the BrogueHighScores.txt file,
356: // thus overwriting whatever is already there.
357: // The numerical version of the date is what gets saved; the "mm/dd/yy" version is ignored.
358: // Does NOT do any sorting.
359: void saveScoreBuffer() {
360: short i;
361: FILE *scoresFile;
362:
363: scoresFile = fopen("BrogueHighScores.txt", "w");
364:
365: for (i=0; i<HIGH_SCORES_COUNT; i++) {
366: // save the entry
367: fprintf(scoresFile, "%li\t%li\t%s\n", scoreBuffer[i].score, scoreBuffer[i].dateNumber, scoreBuffer[i].description);
368: }
369:
370: fclose(scoresFile);
371: }
372:
373: void dumpScores() {
374: int i;
375:
376: rogueHighScoresEntry list[HIGH_SCORES_COUNT];
377: getHighScoresList(list);
378:
379: for (i = 0; i < HIGH_SCORES_COUNT; i++) {
380: if (list[i].score > 0) {
381: printf("%d\t%s\t%s\n", (int) list[i].score, list[i].date, list[i].description);
382: }
383: }
384: }
385:
386: short getHighScoresList(rogueHighScoresEntry returnList[HIGH_SCORES_COUNT]) {
387: short i, mostRecentLineNumber;
388:
389: mostRecentLineNumber = loadScoreBuffer();
390:
391: for (i=0; i<HIGH_SCORES_COUNT; i++) {
392: returnList[i].score = scoreBuffer[i].score;
393: strcpy(returnList[i].date, scoreBuffer[i].dateText);
394: strcpy(returnList[i].description, scoreBuffer[i].description);
395: }
396:
397: return mostRecentLineNumber;
398: }
399:
400: boolean saveHighScore(rogueHighScoresEntry theEntry) {
401: short i, lowestScoreIndex = -1;
402: long lowestScore = -1;
403:
404: loadScoreBuffer();
405:
406: for (i=0; i<HIGH_SCORES_COUNT; i++) {
407: if (scoreBuffer[i].score < lowestScore || i == 0) {
408: lowestScore = scoreBuffer[i].score;
409: lowestScoreIndex = i;
410: }
411: }
412:
413: if (lowestScore > theEntry.score) {
414: return false;
415: }
416:
417: scoreBuffer[lowestScoreIndex].score = theEntry.score;
418: scoreBuffer[lowestScoreIndex].dateNumber = (long) time(NULL);
419: strcpy(scoreBuffer[lowestScoreIndex].description, theEntry.description);
420:
421: saveScoreBuffer();
422:
423: return true;
424: }
425:
426: // start of file listing
427:
428: struct filelist {
429: fileEntry *files;
430: char *names;
431:
432: int nfiles, maxfiles;
433: int nextname, maxname;
434: };
435:
436: struct filelist *newFilelist() {
437: struct filelist *list = malloc(sizeof(*list));
438:
439: list->nfiles = 0;
440: list->nextname = 0;
441: list->maxfiles = 64;
442: list->maxname = list->maxfiles * 64;
443:
444: list->files = malloc(sizeof(fileEntry) * list->maxfiles);
445: list->names = malloc(list->maxname);
446:
447: return list;
448: }
449:
450: fileEntry *addfile(struct filelist *list, const char *name) {
451: int len = strlen(name);
452: if (len + list->nextname >= list->maxname) {
453: int newmax = (list->maxname + len) * 2;
454: char *newnames = realloc(list->names, newmax);
455: if (newnames != NULL) {
456: list->names = newnames;
457: list->maxname = newmax;
458: } else {
459: // fail silently
460: return NULL;
461: }
462: }
463:
464: if (list->nfiles >= list->maxfiles) {
465: int newmax = list->maxfiles * 2;
466: fileEntry *newfiles = realloc(list->files, sizeof(fileEntry) * newmax);
467: if (newfiles != NULL) {
468: list->files = newfiles;
469: list->maxfiles = newmax;
470: } else {
471: // fail silently
472: return NULL;
473: }
474: }
475:
476: // add the new file and copy the name into the buffer
477: list->files[list->nfiles].path = ((char *) NULL) + list->nextname; // don't look at them until they are transferred out
478: list->files[list->nfiles].date = (struct tm) {0}; // associate a dummy date (1899-12-31) to avoid random data, it will be correctly populated when using listFiles()
479:
480: strncpy(list->names + list->nextname, name, len + 1);
481:
482: list->nextname += len + 1;
483: list->nfiles += 1;
484:
485: return list->files + (list->nfiles - 1);
486: }
487:
488: void freeFilelist(struct filelist *list) {
489: //if (list->names != NULL) free(list->names);
490: //if (list->files != NULL) free(list->files);
491: free(list);
492: }
493:
494: fileEntry *commitFilelist(struct filelist *list, char **namebuffer) {
495: int i;
496: /*fileEntry *files = malloc(list->nfiles * sizeof(fileEntry) + list->nextname); // enough space for all the names and all the files
497:
498: if (files != NULL) {
499: char *names = (char *) (files + list->nfiles);
500:
501: for (i=0; i < list->nfiles; i++) {
502: files[i] = list->files[i];
503: files[i].path = names + (files[i].path - (char *) NULL);
504: }
505:
506: memcpy(names, list->names, list->nextname);
507: }
508: */
509: for (i=0; i < list->nfiles; i++) {
510: list->files[i].path = list->names + (list->files[i].path - (char *) NULL);
511: }
512: *namebuffer = list->names;
513:
514: return list->files;
515: }
516:
517: fileEntry *listFiles(short *fileCount, char **namebuffer) {
518: struct filelist *list = newFilelist();
519:
520: // windows: FindFirstFile/FindNextFile
521: DIR *dp= opendir ("./");
522:
523: if (dp != NULL) {
524: struct dirent *ep;
525: struct stat statbuf;
526: struct tm *timeinfo;
527:
528: while ((ep = readdir(dp))) {
529: // get statistics about the file (0 on success)
530: if (!stat(ep->d_name, &statbuf)) {
531: fileEntry *file = addfile(list, ep->d_name);
532: if (file != NULL) {
533: // add the modification date to the file entry
534: timeinfo = localtime(&statbuf.st_mtime);
535: file->date = *timeinfo;
536: }
537: }
538: }
539:
540: closedir (dp);
541: }
542: else {
543: *fileCount = 0;
544: return NULL;
545: }
546:
547: fileEntry *files = commitFilelist(list, namebuffer);
548:
549: if (files != NULL) {
550: *fileCount = (short) list->nfiles;
551: } else {
552: *fileCount = 0;
553: }
554:
555: freeFilelist(list);
556:
557: return files;
558: }
559:
560: // end of file listing
561:
562: void initializeLaunchArguments(enum NGCommands *command, char *path, unsigned long *seed) {
563: // we've actually already done this at this point, except for the seed.
564: }
565:
566: boolean isApplicationActive(void) {
567: // FIXME: finish
568: return true;
569: }
570:
CVSweb