home · contact · privacy
Finished applying new code formatting and documentation rules on main module.
[plomrogue] / src / main.c
1 /* main.c */
2
3 #include "main.h"
4 #include <stdlib.h> /* for atoi(), exit(), EXIT_FAILURE, calloc() */
5 #include <stdio.h> /* for FILE typedef, F_OK */
6 #include <ncurses.h> /* for initscr(), noecho(), curs_set(), keypad(), raw() */
7 #include <time.h> /* for time() */
8 #include <unistd.h> /* for getopt(), optarg */
9 #include "windows.h" /* for structs WinMeta, Win, init_win(), init_win_meta(),
10                       * draw_all_wins()
11                       */
12 #include "draw_wins.h" /* for draw_keys_win(), draw_map_win(), draw_info_win(),
13                         * draw_log_win()
14                         */
15 #include "keybindings.h" /* for initkeybindings(), get_action_key() */
16 #include "readwrite.h" /* for read_uint16_bigendian, read_uint32_bigendian,
17                         * write_uint32_bigendian
18                         */
19 #include "map_objects.h" /* for structs Monster, Item, Player,
20                           * init_map_object_defs(), read_map_objects(),
21                           * read_map_objects_monsterdata,
22                           * read_map_objects_itemdata, build_map_objects()
23                           */
24 #include "map_object_actions.h" /* for player_wait(), move_player() */
25 #include "map.h" /* for struct Map, init_map() */
26 #include "misc.h" /* for rrand(), update_log(), toggle_window(), exit_game(),
27                    * find_passable_pos(), meta_keys(), save_game()
28                    */
29 #include "yx_uint16.h" /* for dir enum */
30
31 int main(int argc, char *argv[])
32 {
33     struct World world;
34
35     /* Read in startup options (i.e. replay option and replay start turn). */
36     int opt;
37     uint32_t start_turn;
38     world.interactive = 1;
39     while ((opt = getopt(argc, argv, "s::")) != -1)
40     {
41         switch (opt)
42         {
43             case 's':
44                 world.interactive = 0;
45                 start_turn = 0;
46                 if (optarg)
47                     start_turn = atoi(optarg);
48                  break;
49             default:
50                 exit(EXIT_FAILURE);
51         }
52     }
53
54     /* Initialize log, player, monster/item definitions and monsters/items. */
55     world.log = calloc(1, sizeof(char));
56     update_log (&world, " ");
57     struct Player player;
58     player.hitpoints = 5;
59     world.player = &player;
60     world.monster = 0;
61     world.item = 0;
62     init_map_object_defs(&world, "defs");
63
64     /* For interactive mode, try to load world state from savefile. */
65     FILE * file;
66     if (1 == world.interactive && 0 == access("savefile", F_OK))
67     {
68         file = fopen("savefile", "r");
69         world.seed = read_uint32_bigendian(file);
70         world.turn = read_uint32_bigendian(file);
71         player.pos.y = read_uint16_bigendian(file) - 1;
72         player.pos.x = read_uint16_bigendian(file) - 1;
73         player.hitpoints = fgetc(file);
74         read_map_objects(&world.monster, file, sizeof(struct Monster),
75                           read_map_objects_monsterdata);
76         read_map_objects(&world.item,    file, sizeof(struct Item), NULL);
77         fclose(file);
78     }
79
80     /* For non-interactive mode, try to load world state from record file. */
81     else
82     {
83         world.turn = 1;
84         if (0 == world.interactive)
85         {
86             file = fopen("record", "r");
87             world.seed = read_uint32_bigendian(file);
88         }
89
90       /* For interactive-mode in newly started world, generate a start seed
91        * from the current time.
92        */
93       else
94       {
95           file = fopen("record", "w");
96           world.seed = time(NULL);
97           write_uint32_bigendian(world.seed, file);
98           fclose(file);
99       }
100   }
101
102     /* Generate map from seed and, if newly generated world, start positions of
103      * actors.
104      */
105     rrand(1, world.seed);
106     struct Map map = init_map();
107     world.map = &map;
108     if (1 == world.turn)
109     {
110         player.pos = find_passable_pos(&map);
111         void * foo = build_map_objects(&world, &world.monster,
112                                        0, 1 + rrand(0,0) % 27,
113                                        sizeof(struct Monster),
114                                        build_map_objects_monsterdata);
115         foo = build_map_objects(&world, foo, 1, 1 + rrand(0,0) % 9,
116                                 sizeof(struct Monster),
117                                 build_map_objects_monsterdata);
118         build_map_objects(&world, foo, 2, 1 + rrand(0,0) % 3,
119                           sizeof(struct Monster),
120                           build_map_objects_monsterdata);
121         foo = build_map_objects(&world, &world.item, 3, 1 + rrand(0,0) % 3,
122                                 sizeof(struct Item),
123                                 build_map_objects_itemdata);
124         build_map_objects(&world, foo, 4, 1 + rrand(0,0) % 3,
125                           sizeof(struct Item), build_map_objects_itemdata);
126     }
127
128     /* Initialize window system and windows. */
129     WINDOW * screen = initscr();
130     noecho();
131     curs_set(0);
132     keypad(screen, TRUE);
133     raw();
134     init_keybindings(&world);
135     struct WinMeta win_meta = init_win_meta(screen);
136     struct Win win_keys = init_win(&win_meta, "Keys", &world, draw_keys_win);
137     struct Win win_map = init_win(&win_meta, "Map", &world, draw_map_win);
138     struct Win win_info = init_win(&win_meta, "Info", &world, draw_info_win);
139     struct Win win_log = init_win(&win_meta, "Log", &world, draw_log_win);
140     win_keys.frame.size.x = 29;
141     win_map.frame.size.x = win_meta.pad.size.x - win_keys.frame.size.x
142                            - win_log.frame.size.x - 2;
143     win_info.frame.size.y = 2;
144     win_log.frame.size.y = win_meta.pad.size.y - (2 + win_info.frame.size.y);
145     toggle_window(&win_meta, &win_keys);
146     toggle_window(&win_meta, &win_map);
147     toggle_window(&win_meta, &win_info);
148     toggle_window(&win_meta, &win_log);
149
150     /* Replay mode. */
151     int key;
152     unsigned char quit_called = 0;
153     unsigned char await_actions = 1;
154     if (0 == world.interactive)
155     {
156         int action;
157         while (1)
158         {
159             if (start_turn == world.turn)
160             {
161                 start_turn = 0;
162             }
163             if (0 == start_turn)
164             {
165                 draw_all_wins (&win_meta);
166                key = getch();
167             }
168             if (1 == await_actions
169                 && (world.turn < start_turn
170                     || key == get_action_key(world.keybindings,
171                                              "wait / next turn")) )
172             {
173                 action = getc(file);
174                 if (EOF == action)
175                 {
176                     start_turn = 0;
177                     await_actions = 0;
178                 }
179                 else if (0 == action)
180                 {
181                     player_wait (&world);
182                 }
183                 else if (NORTH == action)
184                 {
185                     move_player(&world, NORTH);
186                 }
187                 else if (EAST  == action)
188                 {
189                     move_player(&world, EAST);
190                 }
191                 else if (SOUTH == action)
192                 {
193                     move_player(&world, SOUTH);
194                 }
195                 else if (WEST == action)
196                 {
197                     move_player(&world, WEST);
198                 }
199             }
200             else
201             {
202                 quit_called = meta_keys(key, &world, &win_meta, &win_keys,
203                                              &win_map, &win_info, &win_log);
204                 if (1 == quit_called)
205                 {
206                     exit_game(&world, &map);
207                 }
208             }
209         }
210     }
211
212     /* Interactive mode. */
213     else
214     {
215         uint32_t last_turn = 0;
216         while (1)
217         {
218             if (last_turn != world.turn)
219             {
220                 save_game(&world);
221                 last_turn = world.turn;
222             }
223             if (1 == await_actions && 0 == player.hitpoints)
224             {
225                 await_actions = 0;
226             }
227             draw_all_wins (&win_meta);
228             key = getch();
229             if      (1 == await_actions
230                      && key == get_action_key(world.keybindings,
231                                               "player up"))
232             {
233                 move_player(&world, NORTH);
234             }
235             else if (1 == await_actions
236                      && key == get_action_key(world.keybindings,
237                                               "player right"))
238             {
239                 move_player(&world, EAST);
240             }
241             else if (1 == await_actions
242                      && key == get_action_key(world.keybindings,
243                                               "player down"))
244             {
245                 move_player(&world, SOUTH);
246             }
247             else if (1 == await_actions
248                      && key == get_action_key(world.keybindings,
249                                               "player left"))
250             {
251                 move_player(&world, WEST);
252             }
253             else if (1 == await_actions
254                      && key == get_action_key(world.keybindings,
255                                               "wait / next turn"))
256             {
257                 player_wait (&world);
258             }
259             else
260             {
261                 quit_called = meta_keys(key, &world, &win_meta, &win_keys,
262                                              &win_map, &win_info, &win_log);
263                 if (1 == quit_called)
264                 {
265                     exit_game(&world, &map);
266                 }
267             }
268         }
269     }
270 }