10 #include "roguelike.h"
11 #include "keybindings.h"
13 uint16_t rrand(char use_seed, uint32_t new_seed) {
14 // Pseudo-random number generator (LGC algorithm). Use instead of rand() to ensure portable predictability.
18 seed = ((seed * 1103515245) + 12345) % 2147483648; // Values as recommended by POSIX.1-2001 (see rand(3)).
19 return (seed / 65536); } // Ignore least significant 16 bits (they are less random).
21 uint16_t read_uint16_bigendian(FILE * file) {
22 // Read uint16 from file in big-endian order.
23 const uint16_t nchar = UCHAR_MAX + 1;
24 unsigned char a = fgetc(file);
25 unsigned char b = fgetc(file);
26 return (a * nchar) + b; }
28 void write_uint16_bigendian(uint16_t x, FILE * file) {
29 // Write uint16 to file in beg-endian order.
30 const uint16_t nchar = UCHAR_MAX + 1;
31 unsigned char a = x / nchar;
32 unsigned char b = x % nchar;
36 uint32_t read_uint32_bigendian(FILE * file) {
37 // Read uint32 from file in big-endian order.
38 const uint16_t nchar = UCHAR_MAX + 1;
39 unsigned char a = fgetc(file);
40 unsigned char b = fgetc(file);
41 unsigned char c = fgetc(file);
42 unsigned char d = fgetc(file);
43 return (a * nchar * nchar * nchar) + (b * nchar * nchar) + (c * nchar) + d; }
45 void write_uint32_bigendian(uint32_t x, FILE * file) {
46 // Write uint32 to file in beg-endian order.
47 const uint16_t nchar = UCHAR_MAX + 1;
48 unsigned char a = x / (nchar * nchar * nchar);
49 unsigned char b = (x - (a * nchar * nchar * nchar)) / (nchar * nchar);
50 unsigned char c = (x - ((a * nchar * nchar * nchar) + (b * nchar * nchar))) / nchar;
51 unsigned char d = x % nchar;
57 void load_game(struct World * world) {
58 // Load game data from game file.
59 FILE * file = fopen("savefile", "r");
60 world->seed = read_uint32_bigendian(file);
61 world->turn = read_uint32_bigendian(file);
62 world->player->y = read_uint16_bigendian(file);
63 world->player->x = read_uint16_bigendian(file);
64 world->monster->y = read_uint16_bigendian(file);
65 world->monster->x = read_uint16_bigendian(file);
68 void save_game(struct World * world) {
69 // Save game data to game file.
70 FILE * file = fopen("savefile", "w");
71 write_uint32_bigendian(world->seed, file);
72 write_uint32_bigendian(world->turn, file);
73 write_uint16_bigendian(world->player->y, file);
74 write_uint16_bigendian(world->player->x, file);
75 write_uint16_bigendian(world->monster->y, file);
76 write_uint16_bigendian(world->monster->x, file);
79 void toggle_window (struct WinMeta * win_meta, struct Win * win) {
80 // Toggle display of window win.
82 suspend_window(win_meta, win);
84 append_window(win_meta, win); }
86 void growshrink_active_window (struct WinMeta * win_meta, char change) {
87 // Grow or shrink active window horizontally or vertically by one cell size.
88 if (0 != win_meta->active) {
89 uint16_t height = win_meta->active->height;
90 uint16_t width = win_meta->active->width;
93 else if (change == '+')
95 else if (change == '_')
97 else if (change == '*')
99 resize_active_window (win_meta, height, width); } }
101 struct Map init_map () {
102 // Initialize map with some experimental start values.
108 map.cells = malloc(map.width * map.height);
111 for (y = 0; y < map.height; y++)
112 for (x = 0; x < map.width; x++) {
115 if ( 0 == ran % ((x*x) / 3 + 1)
116 || 0 == ran % ((y*y) / 3 + 1)
117 || 0 == ran % ((map.width - x - 1) * (map.width - x - 1) / 3 + 1)
118 || 0 == ran %((map.height - y - 1) * (map.height - y - 1) / 3 + 1))
120 map.cells[(y * map.width) + x] = terrain; }
123 void map_scroll (struct Map * map, char dir) {
124 // Scroll map into direction dir if possible by changing the offset.
125 if ('n' == dir && map->offset_y > 0)
129 else if ('w' == dir && map->offset_x > 0)
134 void next_turn (struct World * world) {
135 // Increment turn and move enemy.
137 rrand(1, world->seed * world->turn);
138 char d = rrand(0, 0) % 5;
139 uint16_t ty = world->monster->y;
140 uint16_t tx = world->monster->x;
149 if (tx == world->player->x && ty == world->player->y)
150 update_log(world, "\nThe monster hits you.");
151 else if (is_passable(world, tx, ty)) {
152 world->monster->y = ty;
153 world->monster->x = tx; } }
155 void update_log (struct World * world, char * text) {
156 // Update log with new text to be appended.
158 uint16_t len_old = strlen(world->log);
159 uint16_t len_new = strlen(text);
160 uint16_t len_whole = len_old + len_new + 1;
161 new_text = calloc(len_whole, sizeof(char));
162 memcpy(new_text, world->log, len_old);
163 memcpy(new_text + len_old, text, len_new);
165 world->log = new_text; }
167 char is_passable (struct World * world, uint16_t x, uint16_t y) {
168 // Check if coordinate on (or beyond) map is accessible to movement.
170 if (0 <= x && x < world->map->width && 0 <= y && y < world->map->height)
171 if ('.' == world->map->cells[y * world->map->width + x])
175 void move_player (struct World * world, char d) {
176 // Move player in direction d, increment turn counter and update log.
177 static char prev = 0;
180 uint16_t ty = world->player->y;
181 uint16_t tx = world->player->x;
194 if (ty == world->monster->y && tx == world->monster->x)
196 else if (is_passable(world, tx, ty)) {
198 world->player->y = ty;
199 world->player->x = tx; }
200 if (success * d == prev)
201 update_log (world, ".");
204 update_log (world, "\nYou hit the monster.");
206 char * msg = calloc(25, sizeof(char));
207 char * msg_content = "You fail to move";
209 msg_content = "You move";
210 sprintf(msg, "\n%s %s.", msg_content, dir);
211 update_log (world, msg);
216 void player_wait (struct World * world) {
217 // Make player wait one turn.
219 update_log (world, "\nYou wait."); }
221 int main (int argc, char *argv[]) {
223 init_keybindings(&world);
225 world.log = calloc(1, sizeof(char));
226 update_log (&world, " ");
227 struct Player player;
228 world.player = &player;
229 struct Monster monster;
230 world.monster = &monster;
231 if (0 == access("savefile", F_OK))
238 world.seed = time(NULL);
240 rrand(1, world.seed);
241 struct Map map = init_map();
244 WINDOW * screen = initscr();
247 keypad(screen, TRUE);
249 struct WinMeta win_meta = init_win_meta(screen);
250 struct Win win_keys = init_window(&win_meta, "Keys", &world, draw_keys_win);
251 struct Win win_map = init_window(&win_meta, "Map", &world, draw_map_win);
252 struct Win win_info = init_window(&win_meta, "Info", &world, draw_info_win);
253 struct Win win_log = init_window(&win_meta, "Log", &world, draw_log_win);
255 win_map.width = win_meta.width - win_keys.width - win_log.width - 2;
257 win_log.height = win_meta.height - 3;
258 toggle_window(&win_meta, &win_keys);
259 toggle_window(&win_meta, &win_map);
260 toggle_window(&win_meta, &win_info);
261 toggle_window(&win_meta, &win_log);
264 uint32_t last_turn = 0;
266 if (last_turn != world.turn) {
268 last_turn = world.turn; }
269 draw_all_windows (&win_meta);
271 if (key == get_action_key(world.keybindings, "quit"))
273 else if (key == get_action_key(world.keybindings, "scroll pad right"))
274 scroll_pad (&win_meta, '+');
275 else if (key == get_action_key(world.keybindings, "scroll pad left"))
276 scroll_pad (&win_meta, '-');
277 else if (key == get_action_key(world.keybindings, "toggle keys window"))
278 toggle_window(&win_meta, &win_keys);
279 else if (key == get_action_key(world.keybindings, "toggle map window"))
280 toggle_window(&win_meta, &win_map);
281 else if (key == get_action_key(world.keybindings, "toggle info window"))
282 toggle_window(&win_meta, &win_info);
283 else if (key == get_action_key(world.keybindings, "toggle log window"))
284 toggle_window(&win_meta, &win_log);
285 else if (key == get_action_key(world.keybindings, "cycle forwards"))
286 cycle_active_window(&win_meta, 'n');
287 else if (key == get_action_key(world.keybindings, "cycle backwards"))
288 cycle_active_window(&win_meta, 'p');
289 else if (key == get_action_key(world.keybindings, "shift forwards"))
290 shift_active_window(&win_meta, 'f');
291 else if (key == get_action_key(world.keybindings, "shift backwards"))
292 shift_active_window(&win_meta, 'b');
293 else if (key == get_action_key(world.keybindings, "grow horizontally"))
294 growshrink_active_window(&win_meta, '*');
295 else if (key == get_action_key(world.keybindings, "shrink horizontally"))
296 growshrink_active_window(&win_meta, '_');
297 else if (key == get_action_key(world.keybindings, "grow vertically"))
298 growshrink_active_window(&win_meta, '+');
299 else if (key == get_action_key(world.keybindings, "shrink vertically"))
300 growshrink_active_window(&win_meta, '-');
301 else if (key == get_action_key(world.keybindings, "save keys"))
302 save_keybindings(&world);
303 else if (key == get_action_key(world.keybindings, "keys nav up"))
304 keyswin_move_selection (&world, 'u');
305 else if (key == get_action_key(world.keybindings, "keys nav down"))
306 keyswin_move_selection (&world, 'd');
307 else if (key == get_action_key(world.keybindings, "keys mod"))
308 keyswin_mod_key (&world, &win_meta);
309 else if (key == get_action_key(world.keybindings, "map up"))
310 map_scroll (&map, 'n');
311 else if (key == get_action_key(world.keybindings, "map down"))
312 map_scroll (&map, 's');
313 else if (key == get_action_key(world.keybindings, "map right"))
314 map_scroll (&map, 'e');
315 else if (key == get_action_key(world.keybindings, "map left"))
316 map_scroll (&map, 'w');
317 else if (key == get_action_key(world.keybindings, "player down"))
318 move_player(&world, 's');
319 else if (key == get_action_key(world.keybindings, "player up"))
320 move_player(&world, 'n');
321 else if (key == get_action_key(world.keybindings, "player right"))
322 move_player(&world, 'e');
323 else if (key == get_action_key(world.keybindings, "player left"))
324 move_player(&world, 'w');
325 else if (key == get_action_key(world.keybindings, "wait") )
326 player_wait (&world); }
329 for (key = 0; key <= world.keyswindata->max; key++)
330 free(world.keybindings[key].name);
331 free(world.keybindings);
332 free(world.keyswindata);