home · contact · privacy
Moved keybindings manipulation stuff into its own library.
[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 #include "keybindings.h"
8
9 void toggle_window (struct WinMeta * win_meta, struct Win * win) {
10 // Toggle display of window win.
11   if (0 != win->curses)
12     suspend_window(win_meta, win);
13   else
14     append_window(win_meta, win); }
15
16 void growshrink_active_window (struct WinMeta * win_meta, char change) {
17 // Grow or shrink active window horizontally or vertically by one cell size.
18   if (0 != win_meta->active) {
19     int height = win_meta->active->height;
20     int width = win_meta->active->width;
21     if      (change == '-')
22       height--;
23     else if (change == '+')
24       height++;
25     else if (change == '_')
26       width--;
27     else if (change == '*')
28       width++;
29     resize_active_window (win_meta, height, width); } }
30
31 struct Map init_map () {
32 // Initialize map with some experimental start values.
33   struct Map map;
34   map.width = 96;
35   map.height = 32;
36   map.offset_x = 0;
37   map.offset_y = 0;
38   map.cells = malloc(map.width * map.height);
39   int x, y, ran;
40   char terrain;
41   for (y = 0; y < map.height; y++)
42     for (x = 0; x < map.width; x++) {
43       terrain = '.';
44       ran = rand();
45       if (   0 == ran % ((x*x) / 3 + 1)
46           || 0 == ran % ((y*y) / 3 + 1)
47           || 0 == ran % ((map.width - x - 1) * (map.width - x - 1) / 3 + 1)
48           || 0 == ran %((map.height - y - 1) * (map.height - y - 1) / 3 + 1))
49         terrain = ' ';
50       map.cells[(y * map.width) + x] = terrain; }
51   return map; }
52
53 void map_scroll (struct Map * map, char dir) {
54 // Scroll map into direction dir if possible by changing the offset.
55   if      ('n' == dir && map->offset_y > 0)
56     map->offset_y--;
57   else if ('s' == dir)
58     map->offset_y++;
59   else if ('w' == dir && map->offset_x > 0)
60     map->offset_x--;
61   else if ('e' == dir)
62     map->offset_x++; }
63
64 void next_turn (struct World * world) {
65 // Increment turn and move enemy.
66   world->turn++;
67   char d = rand() % 5;
68   char ty = world->monster->y;
69   char tx = world->monster->x;
70   if (1 == d)
71     ty++;
72   else if (2 == d)
73     ty--;
74   else if (3 == d)
75     tx++;
76   else if (4 == d)
77     tx--;
78   if (tx == world->player->x && ty == world->player->y)
79     update_log(world, "\nThe monster hits you.");
80   else if (is_passable(world, tx, ty)) {
81     world->monster->y = ty;
82     world->monster->x = tx; } }
83
84 void update_log (struct World * world, char * text) {
85 // Update log with new text to be appended.
86   char * new_text;
87   int len_old = strlen(world->log);
88   int len_new = strlen(text);
89   int len_whole = len_old + len_new + 1;
90   new_text = calloc(len_whole, sizeof(char));
91   memcpy(new_text, world->log, len_old);
92   memcpy(new_text + len_old, text, len_new);
93   free(world->log);
94   world->log = new_text; }
95
96 char is_passable (struct World * world, int x, int y) {
97 // Check if coordinate on (or beyond) map is accessible to movement.
98   char passable = 0;
99   if (0 <= x && x < world->map->width && 0 <= y && y < world->map->height)
100     if ('.' == world->map->cells[y * world->map->width + x])
101       passable = 1;
102   return passable; }
103
104 void move_player (struct World * world, char d) {
105 // Move player in direction d, increment turn counter and update log.
106   static char prev = 0;
107   char success = 0;
108   char * dir;
109   char ty = world->player->y;
110   char tx = world->player->x;
111   if ('s' == d) {
112     dir = "south";
113     ty++; }
114   if ('n' == d) {
115     dir = "north";
116     ty--; }
117   if ('w' == d) {
118     dir = "west";
119     tx--; }
120   if ('e' == d) {
121     dir = "east";
122     tx++; }
123   if (ty == world->monster->y && tx == world->monster->x)
124     success = 2;
125   else if (is_passable(world, tx, ty)) {
126     success = 1;
127     world->player->y = ty;
128     world->player->x = tx; }
129   if (success * d == prev)
130     update_log (world, ".");
131   else {
132     if (2 == success)
133       update_log (world, "\nYou hit the monster.");
134     else {
135       char * msg = calloc(25, sizeof(char));
136       char * msg_content = "You fail to move";
137       if (1 == success)
138         msg_content = "You move";
139       sprintf(msg, "\n%s %s.", msg_content, dir);
140       update_log (world, msg);
141       free(msg); } }
142   prev = success * d;
143   next_turn (world); }
144
145 void player_wait(struct World * world) {
146 // Make player wait one turn.
147   next_turn (world);
148   update_log (world, "\nYou wait."); }
149
150 int main () {
151   struct World world;
152   init_keybindings(&world);
153   world.turn = 0;
154   world.log = calloc(1, sizeof(char));
155   update_log (&world, "Start!");
156   struct Map map = init_map();
157   world.map = &map;
158   struct Player player;
159   player.y = 16;
160   player.x = 16;
161   world.player = &player;
162   struct Monster monster;
163   monster.y = 16;
164   monster.x = 80;
165   world.monster = &monster;
166
167   WINDOW * screen = initscr();
168   noecho();
169   curs_set(0);
170   keypad(screen, TRUE);
171   raw();
172   struct WinMeta win_meta = init_win_meta(screen);
173   struct Win win_keys = init_window(&win_meta, "Keys", &world, draw_keys_win);
174   struct Win win_map = init_window(&win_meta, "Map", &world, draw_map_win);
175   struct Win win_info = init_window(&win_meta, "Info", &world, draw_info_win);
176   struct Win win_log = init_window(&win_meta, "Log", &world, draw_log_win);
177
178   int key;
179   while (1) {
180     draw_all_windows (&win_meta);
181     key = getch();
182     if      (key == get_action_key(world.keybindings, "quit"))
183       break;
184     else if (key == get_action_key(world.keybindings, "scroll pad right"))
185       scroll_pad (&win_meta, '+');
186     else if (key == get_action_key(world.keybindings, "scroll pad left"))
187       scroll_pad (&win_meta, '-');
188     else if (key == get_action_key(world.keybindings, "toggle keys window"))
189       toggle_window(&win_meta, &win_keys);
190     else if (key == get_action_key(world.keybindings, "toggle map window"))
191       toggle_window(&win_meta, &win_map);
192     else if (key == get_action_key(world.keybindings, "toggle info window"))
193       toggle_window(&win_meta, &win_info);
194     else if (key == get_action_key(world.keybindings, "toggle log window"))
195       toggle_window(&win_meta, &win_log);
196     else if (key == get_action_key(world.keybindings, "cycle forwards"))
197       cycle_active_window(&win_meta, 'n');
198     else if (key == get_action_key(world.keybindings, "cycle backwards"))
199       cycle_active_window(&win_meta, 'p');
200     else if (key == get_action_key(world.keybindings, "shift forwards"))
201       shift_active_window(&win_meta, 'f');
202     else if (key == get_action_key(world.keybindings, "shift backwards"))
203       shift_active_window(&win_meta, 'b');
204     else if (key == get_action_key(world.keybindings, "grow horizontally"))
205       growshrink_active_window(&win_meta, '*');
206     else if (key == get_action_key(world.keybindings, "shrink horizontally"))
207       growshrink_active_window(&win_meta, '_');
208     else if (key == get_action_key(world.keybindings, "grow vertically"))
209       growshrink_active_window(&win_meta, '+');
210     else if (key == get_action_key(world.keybindings, "shrink vertically"))
211       growshrink_active_window(&win_meta, '-');
212     else if (key == get_action_key(world.keybindings, "save keys"))
213       save_keybindings(&world);
214     else if (key == get_action_key(world.keybindings, "keys nav up"))
215       keyswin_move_selection (&world, 'u');
216     else if (key == get_action_key(world.keybindings, "keys nav down"))
217       keyswin_move_selection (&world, 'd');
218     else if (key == get_action_key(world.keybindings, "keys mod"))
219       keyswin_mod_key (&world, &win_meta);
220     else if (key == get_action_key(world.keybindings, "map up"))
221       map_scroll (&map, 'n');
222     else if (key == get_action_key(world.keybindings, "map down"))
223       map_scroll (&map, 's');
224     else if (key == get_action_key(world.keybindings, "map right"))
225       map_scroll (&map, 'e');
226     else if (key == get_action_key(world.keybindings, "map left"))
227       map_scroll (&map, 'w');
228     else if (key == get_action_key(world.keybindings, "player down"))
229       move_player(&world, 's');
230     else if (key == get_action_key(world.keybindings, "player up"))
231       move_player(&world, 'n');
232     else if (key == get_action_key(world.keybindings, "player right"))
233       move_player(&world, 'e');
234     else if (key == get_action_key(world.keybindings, "player left"))
235       move_player(&world, 'w');
236     else if (key == get_action_key(world.keybindings, "wait") )
237       player_wait (&world); }
238
239   free(map.cells);
240   for (key = 0; key <= world.keyswindata->max; key++)
241     free(world.keybindings[key].name);
242   free(world.keybindings);
243   free(world.keyswindata);
244   free(world.log);
245
246   endwin();
247   return 0; }