home · contact · privacy
c22e0c252b040b46adaf226270d403db1abdb6eb
[plomrogue] / src / main.c
1 #include "main.h"
2 #include <stdlib.h>
3 #include <ncurses.h>
4 #include <time.h>
5 #include <unistd.h>
6 #include "windows.h"
7 #include "draw_wins.h"
8 #include "keybindings.h"
9 #include "readwrite.h"
10 #include "map_objects.h"
11 #include "map.h"
12 #include "misc.h"
13
14 int main (int argc, char *argv[]) {
15   struct World world;
16
17   // Read in startup options (i.e. replay option and replay start turn).
18   int opt;
19   uint32_t start_turn;
20   world.interactive = 1;
21   while ((opt = getopt(argc, argv, "s::")) != -1) {
22     switch (opt) {
23       case 's':
24         world.interactive = 0;
25         start_turn = 0;
26         if (optarg)
27           start_turn = atoi(optarg);
28         break;
29       default:
30         exit(EXIT_FAILURE); } }
31
32   // Initialize log, player, monsters and items.
33   world.log = calloc(1, sizeof(char));
34   update_log (&world, " ");
35   struct Player player;
36   player.hitpoints = 5;
37   world.player = &player;
38   world.monster = 0;
39   world.item = 0;
40
41   // For interactive mode, try to load world state from savefile.
42   FILE * file;
43   if (1 == world.interactive && 0 == access("savefile", F_OK)) {
44     file = fopen("savefile", "r");
45     world.seed = read_uint32_bigendian(file);
46     world.turn = read_uint32_bigendian(file);
47     player.pos.y = read_uint16_bigendian(file) - 1;
48     player.pos.x = read_uint16_bigendian(file) - 1;
49     player.hitpoints = fgetc(file);
50     read_map_objects (&world.monster, file, sizeof(struct Monster), read_map_objects_monsterdata);
51     read_map_objects (&world.item,    file, sizeof(struct Item),    readwrite_map_objects_dummy);
52     fclose(file); }
53
54   // For non-interactive mode, try to load world state from record file.
55   else {
56     world.turn = 1;
57     if (0 == world.interactive) {
58       file = fopen("record", "r");
59       world.seed = read_uint32_bigendian(file); }
60
61     // For interactive-mode in newly started world, generate a start seed from the current time.
62     else {
63       file = fopen("record", "w");
64       world.seed = time(NULL);
65       write_uint32_bigendian(world.seed, file);
66       fclose(file); } }
67
68   // Generate map from seed and, if newly generated world, start positions of actors.
69   rrand(1, world.seed);
70   struct Map map = init_map();
71   world.map = &map;
72   if (1 == world.turn) {
73     player.pos = find_passable_pos(&map);
74     unsigned char n_monsters = rrand(0, 0) % 16;
75     unsigned char n_items    = rrand(0, 0) % 48;
76     build_map_objects (&world.monster, n_monsters, sizeof(struct Monster), build_map_objects_monsterdata, &map);
77     build_map_objects (&world.item,    n_items,    sizeof(struct Item),    build_map_objects_itemdata,    &map); }
78
79   // Initialize window system and windows.
80   WINDOW * screen = initscr();
81   noecho();
82   curs_set(0);
83   keypad(screen, TRUE);
84   raw();
85   init_keybindings(&world);
86   struct WinMeta win_meta = init_win_meta(screen);
87   struct Win win_keys = init_win(&win_meta, "Keys", &world, draw_keys_win);
88   struct Win win_map = init_win(&win_meta, "Map", &world, draw_map_win);
89   struct Win win_info = init_win(&win_meta, "Info", &world, draw_info_win);
90   struct Win win_log = init_win(&win_meta, "Log", &world, draw_log_win);
91   win_keys.frame.size.x = 29;
92   win_map.frame.size.x = win_meta.pad.size.x - win_keys.frame.size.x - win_log.frame.size.x - 2;
93   win_info.frame.size.y = 2;
94   win_log.frame.size.y = win_meta.pad.size.y - (2 + win_info.frame.size.y);
95   toggle_window(&win_meta, &win_keys);
96   toggle_window(&win_meta, &win_map);
97   toggle_window(&win_meta, &win_info);
98   toggle_window(&win_meta, &win_log);
99
100   // Replay mode.
101   int key;
102   unsigned char quit_called = 0;
103   unsigned char await_actions = 1;
104   if (0 == world.interactive) {
105     int action;
106     while (1) {
107       if (start_turn == world.turn)
108         start_turn = 0;
109       if (0 == start_turn) {
110         draw_all_wins (&win_meta);
111         key = getch(); }
112       if (1 == await_actions &&
113           (world.turn < start_turn || key == get_action_key(world.keybindings, "wait / next turn")) ) {
114         action = getc(file);
115         if (EOF == action) {
116           start_turn = 0;
117           await_actions = 0; }
118         else if (0 == action)
119           player_wait (&world);
120         else if (NORTH == action)
121           move_player(&world, NORTH);
122         else if (EAST  == action)
123           move_player(&world, EAST);
124         else if (SOUTH == action)
125           move_player(&world, SOUTH);
126         else if (WEST == action)
127           move_player(&world, WEST); }
128       else
129         quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
130         if (1 == quit_called)
131           break; } }
132
133   // Interactive mode.
134   else {
135     uint32_t last_turn = 0;
136     while (1) {
137       if (last_turn != world.turn) {
138         save_game(&world);
139         last_turn = world.turn; }
140       if (1 == await_actions && 0 == player.hitpoints)
141         await_actions = 0;
142       draw_all_wins (&win_meta);
143       key = getch();
144       if      (1 == await_actions && key == get_action_key(world.keybindings, "player up"))
145         move_player(&world, NORTH);
146       else if (1 == await_actions && key == get_action_key(world.keybindings, "player right"))
147         move_player(&world, EAST);
148       else if (1 == await_actions && key == get_action_key(world.keybindings, "player down"))
149         move_player(&world, SOUTH);
150       else if (1 == await_actions && key == get_action_key(world.keybindings, "player left"))
151         move_player(&world, WEST);
152       else if (1 == await_actions && key == get_action_key(world.keybindings, "wait / next turn"))
153         player_wait (&world);
154       else
155         quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
156         if (1 == quit_called)
157           break; } }
158
159   // Clean up and exit.
160   free(map.cells);
161   for (key = 0; key <= world.keyswindata->max; key++)
162     free(world.keybindings[key].name);
163   free(world.keybindings);
164   free(world.keyswindata);
165   free(world.log);
166   endwin();
167   return 0; }