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