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