home · contact · privacy
Moved draw_*_win() into its own library. Removed some unneeded libray includes.
[plomrogue] / roguelike.c
1 #include <ncurses.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include "windows.h"
5 #include "draw_wins.h"
6 #include "roguelike.h"
7
8 void toggle_window (struct WinMeta * win_meta, struct Win * win) {
9 // Toggle display of window win.
10   if (0 != win->curses)
11     suspend_window(win_meta, win);
12   else
13     append_window(win_meta, win); }
14
15 void growshrink_active_window (struct WinMeta * win_meta, char change) {
16 // Grow or shrink active window horizontally or vertically by one cell size.
17   if (0 != win_meta->active) {
18     int height = win_meta->active->height;
19     int width = win_meta->active->width;
20     if      (change == '-')
21       height--;
22     else if (change == '+')
23       height++;
24     else if (change == '_')
25       width--;
26     else if (change == '*')
27       width++;
28     resize_active_window (win_meta, height, width); } }
29
30 void init_keybindings(struct World * world) {
31 // Initialize keybindings from file "keybindings".
32   FILE * file = fopen("keybindings", "r");
33   int lines = 0;
34   int c = 0;
35   int linemax = 0;
36   int c_count = 0;
37   while (EOF != c) {
38     c_count++;
39     c = getc(file);
40     if ('\n' == c) {
41       if (c_count > linemax)
42         linemax = c_count + 1;
43       c_count = 0;
44       lines++; } }
45   struct KeyBinding * keybindings = malloc(lines * sizeof(struct KeyBinding));
46   fseek(file, 0, SEEK_SET);
47   char * command = malloc(linemax);
48   int commcount = 0;
49   char * cmdptr;
50   while (fgets(command, linemax, file)) {
51     keybindings[commcount].key = atoi(command);
52     cmdptr = strchr(command, ' ') + 1;
53     keybindings[commcount].name = malloc(strlen(cmdptr));
54     memcpy(keybindings[commcount].name, cmdptr, strlen(cmdptr) - 1);
55     keybindings[commcount].name[strlen(cmdptr) - 1] = '\0';
56     commcount++; }
57   free(command);
58   fclose(file);
59   struct KeysWinData * keyswindata = malloc(sizeof(struct KeysWinData));
60   keyswindata->max = lines - 1;
61   keyswindata->select = 0;
62   keyswindata->edit = 0;
63   world->keybindings = keybindings;
64   world->keyswindata = keyswindata; }
65
66 struct Map init_map () {
67 // Initialize map with some experimental start values.
68   struct Map map;
69   map.width = 96;
70   map.height = 32;
71   map.offset_x = 0;
72   map.offset_y = 0;
73   map.cells = malloc(map.width * map.height);
74   int x, y, ran;
75   char terrain;
76   for (y = 0; y < map.height; y++)
77     for (x = 0; x < map.width; x++) {
78       terrain = '.';
79       ran = rand();
80       if (   0 == ran % ((x*x) / 3 + 1)
81           || 0 == ran % ((y*y) / 3 + 1)
82           || 0 == ran % ((map.width - x - 1) * (map.width - x - 1) / 3 + 1)
83           || 0 == ran %((map.height - y - 1) * (map.height - y - 1) / 3 + 1))
84         terrain = ' ';
85       map.cells[(y * map.width) + x] = terrain; }
86   return map; }
87
88 void map_scroll (struct Map * map, char dir) {
89 // Scroll map into direction dir if possible by changing the offset.
90   if      ('n' == dir && map->offset_y > 0)
91     map->offset_y--;
92   else if ('s' == dir)
93     map->offset_y++;
94   else if ('w' == dir && map->offset_x > 0)
95     map->offset_x--;
96   else if ('e' == dir)
97     map->offset_x++; }
98
99 void next_turn (struct World * world) {
100 // Increment turn and move enemy.
101   world->turn++;
102   char d = rand() % 5;
103   char ty = world->monster->y;
104   char tx = world->monster->x;
105   if (1 == d)
106     ty++;
107   else if (2 == d)
108     ty--;
109   else if (3 == d)
110     tx++;
111   else if (4 == d)
112     tx--;
113   if (tx == world->player->x && ty == world->player->y)
114     update_log(world, "\nThe monster hits you.");
115   else if (is_passable(world, tx, ty)) {
116     world->monster->y = ty;
117     world->monster->x = tx; } }
118
119 void update_log (struct World * world, char * text) {
120 // Update log with new text to be appended.
121   char * new_text;
122   int len_old = strlen(world->log);
123   int len_new = strlen(text);
124   int len_whole = len_old + len_new + 1;
125   new_text = calloc(len_whole, sizeof(char));
126   memcpy(new_text, world->log, len_old);
127   memcpy(new_text + len_old, text, len_new);
128   free(world->log);
129   world->log = new_text; }
130
131 void save_keybindings(struct World * world) {
132 // Write keybindings to keybindings file.
133   struct KeysWinData * keyswindata = (struct KeysWinData *) world->keyswindata;
134   struct KeyBinding * keybindings = world->keybindings;
135   FILE * file = fopen("keybindings", "w");
136   int linemax = 0;
137   int i;
138   for (i = 0; i <= keyswindata->max; i++)
139     if (strlen(keybindings[i].name) > linemax)
140       linemax = strlen(keybindings[i].name);
141   linemax = linemax + 6;                                // + 6 = + 3 digits + whitespace + newline + null byte
142   char * line = malloc(linemax);
143   for (i = 0; i <= keyswindata->max; i++) {
144     snprintf(line, linemax, "%d %s\n", keybindings[i].key, keybindings[i].name);
145     fwrite(line, sizeof(char), strlen(line), file); }
146   free(line);
147   fclose(file); }
148
149 int get_action_key (struct KeyBinding * keybindings, char * name) {
150 // Return key matching name in keybindings.
151   int i = 0;
152   while (strcmp(keybindings[i].name, name) )
153     i++;
154   return keybindings[i].key; }
155
156 char * get_keyname(int keycode) {
157 // Translate some keycodes to readable names of max 9 chars.
158   char * keyname;
159   keyname = malloc(15);
160   if (32 < keycode && keycode < 127)
161     sprintf(keyname, "%c", keycode);
162   else if (keycode == 9)
163     sprintf(keyname, "TAB");
164   else if (keycode == 10)
165     sprintf(keyname, "RETURN");
166   else if (keycode == 27)
167     sprintf(keyname, "ESCAPE");
168   else if (keycode == 32)
169     sprintf(keyname, "SPACE");
170   else if (keycode == KEY_UP)
171     sprintf(keyname, "UP");
172   else if (keycode == KEY_DOWN)
173     sprintf(keyname, "DOWN");
174   else if (keycode == KEY_LEFT)
175     sprintf(keyname, "LEFT");
176   else if (keycode == KEY_RIGHT)
177     sprintf(keyname, "RIGHT");
178   else if (keycode == KEY_HOME)
179     sprintf(keyname, "HOME");
180   else if (keycode == KEY_BACKSPACE)
181     sprintf(keyname, "BACKSPACE");
182   else if (keycode >= KEY_F0 && keycode <= KEY_F(63)) {
183     int f = keycode - KEY_F0;
184     sprintf(keyname, "F%d", f); }
185   else if (keycode == KEY_DC)
186     sprintf(keyname, "DELETE");
187   else if (keycode == KEY_IC)
188     sprintf(keyname, "INSERT");
189   else if (keycode == KEY_NPAGE)
190     sprintf(keyname, "NEXT PAGE");
191   else if (keycode == KEY_PPAGE)
192     sprintf(keyname, "PREV PAGE");
193   else if (keycode == KEY_END)
194     sprintf(keyname, "END");
195   else
196     sprintf(keyname, "(unknown)");
197   return keyname;  }
198
199 void keyswin_mod_key (struct World * world, struct WinMeta * win_meta) {
200 // In keybindings window, mark selection modifiable, modify key. Ensure max of three digits in key code field.
201   world->keyswindata->edit = 1;
202   draw_all_windows (win_meta);
203   int key = getch();
204   if (key < 1000)
205     world->keybindings[world->keyswindata->select].key = key;
206   world->keyswindata->edit = 0; }
207
208 void keyswin_move_selection (struct World * world, char dir) {
209 // In keybindings window, move selection upwards or downwards (if within limits of list length).
210   if ('u' == dir && world->keyswindata->select > 0)
211     world->keyswindata->select--;
212   else if ('d' == dir && world->keyswindata->select < world->keyswindata->max)
213     world->keyswindata->select++; }
214
215 char is_passable (struct World * world, int x, int y) {
216 // Check if coordinate on (or beyond) map is accessible to movement.
217   char passable = 0;
218   if (0 <= x && x < world->map->width && 0 <= y && y < world->map->height)
219     if ('.' == world->map->cells[y * world->map->width + x])
220       passable = 1;
221   return passable; }
222
223 void move_player (struct World * world, char d) {
224 // Move player in direction d, increment turn counter and update log.
225   static char prev = 0;
226   char success = 0;
227   char * dir;
228   char ty = world->player->y;
229   char tx = world->player->x;
230   if ('s' == d) {
231     dir = "south";
232     ty++; }
233   if ('n' == d) {
234     dir = "north";
235     ty--; }
236   if ('w' == d) {
237     dir = "west";
238     tx--; }
239   if ('e' == d) {
240     dir = "east";
241     tx++; }
242   if (ty == world->monster->y && tx == world->monster->x)
243     success = 2;
244   else if (is_passable(world, tx, ty)) {
245     success = 1;
246     world->player->y = ty;
247     world->player->x = tx; }
248   if (success * d == prev)
249     update_log (world, ".");
250   else {
251     if (2 == success)
252       update_log (world, "\nYou hit the monster.");
253     else {
254       char * msg = calloc(25, sizeof(char));
255       char * msg_content = "You fail to move";
256       if (1 == success)
257         msg_content = "You move";
258       sprintf(msg, "\n%s %s.", msg_content, dir);
259       update_log (world, msg);
260       free(msg); } }
261   prev = success * d;
262   next_turn (world); }
263
264 void player_wait(struct World * world) {
265 // Make player wait one turn.
266   next_turn (world);
267   update_log (world, "\nYou wait."); }
268
269 int main () {
270   struct World world;
271   init_keybindings(&world);
272   world.turn = 0;
273   world.log = calloc(1, sizeof(char));
274   update_log (&world, "Start!");
275   struct Map map = init_map();
276   world.map = &map;
277   struct Player player;
278   player.y = 16;
279   player.x = 16;
280   world.player = &player;
281   struct Monster monster;
282   monster.y = 16;
283   monster.x = 80;
284   world.monster = &monster;
285
286   WINDOW * screen = initscr();
287   noecho();
288   curs_set(0);
289   keypad(screen, TRUE);
290   raw();
291   struct WinMeta win_meta = init_win_meta(screen);
292   struct Win win_keys = init_window(&win_meta, "Keys", &world, draw_keys_win);
293   struct Win win_map = init_window(&win_meta, "Map", &world, draw_map_win);
294   struct Win win_info = init_window(&win_meta, "Info", &world, draw_info_win);
295   struct Win win_log = init_window(&win_meta, "Log", &world, draw_log_win);
296
297   int key;
298   while (1) {
299     draw_all_windows (&win_meta);
300     key = getch();
301     if      (key == get_action_key(world.keybindings, "quit"))
302       break;
303     else if (key == get_action_key(world.keybindings, "scroll pad right"))
304       scroll_pad (&win_meta, '+');
305     else if (key == get_action_key(world.keybindings, "scroll pad left"))
306       scroll_pad (&win_meta, '-');
307     else if (key == get_action_key(world.keybindings, "toggle keys window"))
308       toggle_window(&win_meta, &win_keys);
309     else if (key == get_action_key(world.keybindings, "toggle map window"))
310       toggle_window(&win_meta, &win_map);
311     else if (key == get_action_key(world.keybindings, "toggle info window"))
312       toggle_window(&win_meta, &win_info);
313     else if (key == get_action_key(world.keybindings, "toggle log window"))
314       toggle_window(&win_meta, &win_log);
315     else if (key == get_action_key(world.keybindings, "cycle forwards"))
316       cycle_active_window(&win_meta, 'n');
317     else if (key == get_action_key(world.keybindings, "cycle backwards"))
318       cycle_active_window(&win_meta, 'p');
319     else if (key == get_action_key(world.keybindings, "shift forwards"))
320       shift_active_window(&win_meta, 'f');
321     else if (key == get_action_key(world.keybindings, "shift backwards"))
322       shift_active_window(&win_meta, 'b');
323     else if (key == get_action_key(world.keybindings, "grow horizontally"))
324       growshrink_active_window(&win_meta, '*');
325     else if (key == get_action_key(world.keybindings, "shrink horizontally"))
326       growshrink_active_window(&win_meta, '_');
327     else if (key == get_action_key(world.keybindings, "grow vertically"))
328       growshrink_active_window(&win_meta, '+');
329     else if (key == get_action_key(world.keybindings, "shrink vertically"))
330       growshrink_active_window(&win_meta, '-');
331     else if (key == get_action_key(world.keybindings, "save keys"))
332       save_keybindings(&world);
333     else if (key == get_action_key(world.keybindings, "keys nav up"))
334       keyswin_move_selection (&world, 'u');
335     else if (key == get_action_key(world.keybindings, "keys nav down"))
336       keyswin_move_selection (&world, 'd');
337     else if (key == get_action_key(world.keybindings, "keys mod"))
338       keyswin_mod_key (&world, &win_meta);
339     else if (key == get_action_key(world.keybindings, "map up"))
340       map_scroll (&map, 'n');
341     else if (key == get_action_key(world.keybindings, "map down"))
342       map_scroll (&map, 's');
343     else if (key == get_action_key(world.keybindings, "map right"))
344       map_scroll (&map, 'e');
345     else if (key == get_action_key(world.keybindings, "map left"))
346       map_scroll (&map, 'w');
347     else if (key == get_action_key(world.keybindings, "player down"))
348       move_player(&world, 's');
349     else if (key == get_action_key(world.keybindings, "player up"))
350       move_player(&world, 'n');
351     else if (key == get_action_key(world.keybindings, "player right"))
352       move_player(&world, 'e');
353     else if (key == get_action_key(world.keybindings, "player left"))
354       move_player(&world, 'w');
355     else if (key == get_action_key(world.keybindings, "wait") )
356       player_wait (&world); }
357
358   free(map.cells);
359   for (key = 0; key <= world.keyswindata->max; key++)
360     free(world.keybindings[key].name);
361   free(world.keybindings);
362   free(world.keyswindata);
363   free(world.log);
364
365   endwin();
366   return 0; }