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