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