1 /*
2  * enigma/main.c - main program for Enigma.
3  *
4  * Copyright 2000 Simon Tatham. All rights reserved.
5  *
6  * Enigma is licensed under the MIT licence. See the file LICENCE for
7  * details.
8  *
9  * - we are all amf -
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "enigma.h"
17 
main(int argc,char ** argv)18 int main(int argc, char **argv) {
19     char user[64];
20 
21 #ifdef _WIN32
22     /* chdir to the executable location in case SAVEDIR and LEVELDIR
23      * are relative locations */
24     char startdir[MAX_PATH];
25     char *p, *q;
26 
27     GetModuleFileName(GetModuleHandle(NULL), startdir, sizeof(startdir));
28     p = strrchr(startdir, '\\');
29     if ((q = strrchr(p ? p+1 : startdir, '/')))
30 	p = q;
31     if (p) {
32 	p[0] = '\0';
33 	chdir(startdir);
34     }
35 #endif
36 
37     screen_init();
38     if (setjmp(fatal_error_jmp_buf) == 0) {
39 	char *setname = DEFAULTSET;
40 	levelset *set;
41 	level *l;
42 	gamestate *gs;
43 	progress p;
44 	int i, action, n, saveslot = 0;
45 	gamestate *saves[10];
46 
47 	get_user(user, sizeof(user));
48 
49 	/*
50 	 * Pick up argv[1] in case it describes an alternate level
51 	 * set.
52 	 */
53 	if (argc > 1)
54 	    setname = argv[1];
55 
56 	set = levelset_load(setname);
57 	p = progress_load(set, user);
58 	for (i = 0; i < 10; i++)
59 	    saves[i] = savepos_load(set, user, i);
60 
61 	while (1) {
62 	    action = screen_main_menu(set, saves, p.levnum+1, p.levnum);
63 	    if (action > 0) {
64 		l = set->levels[action-1];
65 		gs = init_game(l);
66 		gs->levnum = action;
67 		saveslot = 0;
68 	    } else if (action == -100) {
69 		break;		       /* direct quit from main menu */
70 	    } else if (action <= -10) {
71 		/* delete a saved position */
72 		n = -action-10;
73 		if (saves[n])
74 		    gamestate_free(saves[n]);
75 		saves[n] = NULL;
76 		savepos_del(set, user, n);
77 		gs = NULL;
78 	    } else {
79 		/* load a saved position */
80 		n = -action;
81 		if (!saves[n])   /* don't segfault */
82 		    continue;
83 		gs = gamestate_copy(saves[n]);
84 		l = set->levels[gs->levnum-1];
85 		saveslot = n;
86 	    }
87 	    if (gs) {
88 		screen_level_init();
89 		while (1) {
90 		    gamestate *newgs;
91 		    int k;
92 		    char *msg;
93 
94 		    if (gs->status == PLAYING) {
95 			msg = NULL;
96 		    } else if (gs->status == DIED) {
97 			msg = "GAME OVER";
98 		    } else if (gs->status == COMPLETED) {
99 			msg = "LEVEL COMPLETE";
100 		    } else {
101 			msg = "!INTERNAL ERROR!";
102 		    }
103 		    screen_level_display(gs, msg);
104 		    k = screen_level_getmove(gs->status == PLAYING);
105 		    if (gs->status == PLAYING &&
106 			(k == 'h' || k == 'j' || k == 'l' || k == 'k' ||
107 			 k == 'x')) {
108 			newgs = make_move(gs, k);
109 			gamestate_free(gs);
110 			gs = newgs;
111 		    } else if (k == 'w') {
112 			char *fname = screen_ask_movefile(1);
113 			if (!fname)
114 			    continue;
115 			sequence_save(fname, gs);
116 		    } else if (gs->status == PLAYING && k == 's') {
117 			n = screen_saveslot_ask('s', saves, saveslot);
118 			if (n >= 0) {
119 			    saveslot = n;
120 			    saves[saveslot] = gamestate_copy(gs);
121 			    savepos_save(set, user, saveslot, gs);
122 			}
123 		    } else if (k == 'r') {
124 			n = screen_saveslot_ask('r', saves, saveslot);
125 			if (n >= 0 && saves[n]) {
126 			    saveslot = n;
127 			    gamestate_free(gs);
128 			    gs = gamestate_copy(saves[saveslot]);
129 			    l = set->levels[gs->levnum-1];
130 			}
131 		    } else if (gs->status == PLAYING && k == 'm') {
132 			char *fname;
133 			char *sequence;
134 			gamestate **movie;
135 			int nframes = 0;
136 			int frame;
137 			char msg[80];
138 			int km;
139 
140 			fname = screen_ask_movefile(0);
141 			if (!fname)
142 			    continue;
143 			sequence = sequence_load(fname);
144 			if (!sequence) {
145 			    screen_error_box("Unable to load move sequence");
146 			    continue;
147 			}
148 			sfree(fname);
149 			movie = smalloc(sizeof(*movie) * (strlen(sequence)+1));
150 			movie[0] = gamestate_copy(gs);
151 			frame = 0;
152 			while (sequence[frame]) {
153 			    movie[frame+1] = make_move(movie[frame],
154 						       sequence[frame]);
155 			    frame++;
156 			    nframes = frame;
157 			    if (movie[frame]->status != PLAYING)
158 				break;
159 			}
160 			sfree(sequence);
161 			frame = 0;
162 			while (1) {
163 			    char *status;
164 			    status = "";
165 			    if (movie[frame]->status == DIED)
166 				status = " - GAME OVER";
167 			    if (movie[frame]->status == COMPLETED)
168 				status = " - LEVEL COMPLETE";
169 			    sprintf(msg, "MOVIE MODE - %3d / %3d%s",
170 				    frame, nframes, status);
171 			    screen_level_display(movie[frame], msg);
172 			    km = screen_movie_getmove();
173 			    if (km == 'f' && frame < nframes) {
174 				frame++;
175 			    } else if (km == 'b' && frame > 0) {
176 				frame--;
177 			    } else if (km == '+') {
178 				frame += 10;
179 				if (frame > nframes) frame = nframes;
180 			    } else if (km == '-') {
181 				frame -= 10;
182 				if (frame < 0) frame = 0;
183 			    } else if (km == '>') {
184 				frame = nframes;
185 			    } else if (km == '<') {
186 				frame = 0;
187 			    } else if (km == 'q') {
188 				break;
189 			    }
190 			}
191 			gamestate_free(gs);
192 			gs = movie[nframes];
193 			for (i = 0; i < nframes; i++)
194 			    gamestate_free(movie[i]);
195 			sfree(movie);
196 		    } else if (gs->status != PLAYING || k == 'q') {
197 			/*
198 			 * (Any key quits this loop when not in
199 			 * PLAYING state; only `q' quits it in
200 			 * PLAYING state.)
201 			 */
202 			break;
203 		    }
204 		}
205 		if (gs->status == COMPLETED) {
206 		    if (p.levnum < gs->levnum) {
207 			p.levnum = gs->levnum;
208 			p.date = time(NULL);
209 			progress_save(set, user, p);
210 			if (p.levnum == set->nlevels) {
211 			    screen_completed_game();
212 			}
213 		    }
214 		}
215 		screen_level_finish();
216 	    }
217 	}
218     } else {
219 	screen_finish();
220 	if (!fatal_error_string)
221 	    fprintf(stderr, "Fatal error and out of memory!\n");
222 	else {
223 	    fprintf(stderr, "Fatal error: %s\n", fatal_error_string);
224 	    free(fatal_error_string);
225 	}
226 	exit(2);
227     }
228     screen_finish();
229     return 0;
230 }
231