+ free(world->log);
+ world->log = new_text; }
+
+char is_passable (struct Map * map, uint16_t y, uint16_t x) {
+// Check if coordinate on (or beyond) map is accessible to movement.
+ char passable = 0;
+ if (0 <= x && x < map->width && 0 <= y && y < map->height)
+ if ('.' == map->cells[y * map->width + x])
+ passable = 1;
+ return passable; }
+
+void record_action (char action) {
+// Append action to game record file.
+ FILE * file = fopen("record", "a");
+ fputc(action, file);
+ fclose(file); }
+
+void move_player (struct World * world, char d) {
+// Move player in direction d, increment turn counter and update log.
+ static char prev = 0;
+ char success = 0;
+ char * dir;
+ uint16_t ty = world->player->y;
+ uint16_t tx = world->player->x;
+ if ('s' == d) {
+ dir = "south";
+ ty++; }
+ if ('n' == d) {
+ dir = "north";
+ ty--; }
+ if ('w' == d) {
+ dir = "west";
+ tx--; }
+ if ('e' == d) {
+ dir = "east";
+ tx++; }
+ if (ty == world->monster->y && tx == world->monster->x)
+ success = 2;
+ else if (is_passable(world->map, ty, tx)) {
+ success = 1;
+ world->player->y = ty;
+ world->player->x = tx; }
+ if (success * d == prev)
+ update_log (world, ".");
+ else {
+ if (2 == success)
+ update_log (world, "\nYou hit the monster.");
+ else {
+ char * msg = calloc(25, sizeof(char));
+ char * msg_content = "You fail to move";
+ if (1 == success)
+ msg_content = "You move";
+ sprintf(msg, "\n%s %s.", msg_content, dir);
+ update_log (world, msg);
+ free(msg); } }
+ prev = success * d;
+ if (1 == world->interactive)
+ record_action(d);
+ next_turn (world); }
+
+void player_wait (struct World * world) {
+// Make player wait one turn.
+ if (1 == world->interactive)
+ record_action(0);
+ next_turn (world);
+ update_log (world, "\nYou wait."); }
+
+unsigned char meta_keys(int key, struct World * world, struct WinMeta * win_meta, struct Win * win_keys,
+ struct Win * win_map, struct Win * win_info, struct Win * win_log) {
+// Call some meta program / window management actions dependent on key. Return 1 to signal quitting.
+ if (key == get_action_key(world->keybindings, "quit"))
+ return 1;
+ else if (key == get_action_key(world->keybindings, "scroll pad right"))
+ scroll_pad (win_meta, '+');
+ else if (key == get_action_key(world->keybindings, "scroll pad left"))
+ scroll_pad (win_meta, '-');
+ else if (key == get_action_key(world->keybindings, "toggle keys window"))
+ toggle_window(win_meta, win_keys);
+ else if (key == get_action_key(world->keybindings, "toggle map window"))
+ toggle_window(win_meta, win_map);
+ else if (key == get_action_key(world->keybindings, "toggle info window"))
+ toggle_window(win_meta, win_info);
+ else if (key == get_action_key(world->keybindings, "toggle log window"))
+ toggle_window(win_meta, win_log);
+ else if (key == get_action_key(world->keybindings, "cycle forwards"))
+ cycle_active_win(win_meta, 'n');
+ else if (key == get_action_key(world->keybindings, "cycle backwards"))
+ cycle_active_win(win_meta, 'p');
+ else if (key == get_action_key(world->keybindings, "shift forwards"))
+ shift_active_win(win_meta, 'f');
+ else if (key == get_action_key(world->keybindings, "shift backwards"))
+ shift_active_win(win_meta, 'b');
+ else if (key == get_action_key(world->keybindings, "grow horizontally"))
+ growshrink_active_window(win_meta, '*');
+ else if (key == get_action_key(world->keybindings, "shrink horizontally"))
+ growshrink_active_window(win_meta, '_');
+ else if (key == get_action_key(world->keybindings, "grow vertically"))
+ growshrink_active_window(win_meta, '+');
+ else if (key == get_action_key(world->keybindings, "shrink vertically"))
+ growshrink_active_window(win_meta, '-');
+ else if (key == get_action_key(world->keybindings, "save keys"))
+ save_keybindings(world);
+ else if (key == get_action_key(world->keybindings, "keys nav up"))
+ keyswin_move_selection (world, 'u');
+ else if (key == get_action_key(world->keybindings, "keys nav down"))
+ keyswin_move_selection (world, 'd');
+ else if (key == get_action_key(world->keybindings, "keys mod"))
+ keyswin_mod_key (world, win_meta);
+ else if (key == get_action_key(world->keybindings, "map up"))
+ map_scroll (world->map, 'n');
+ else if (key == get_action_key(world->keybindings, "map down"))
+ map_scroll (world->map, 's');
+ else if (key == get_action_key(world->keybindings, "map right"))
+ map_scroll (world->map, 'e');
+ else if (key == get_action_key(world->keybindings, "map left"))
+ map_scroll (world->map, 'w');
+ return 0; }
+
+int main (int argc, char *argv[]) {
+ struct World world;
+ world.interactive = 1;
+ int opt;
+ uint32_t start_turn;
+ while ((opt = getopt(argc, argv, "s::")) != -1) {
+ switch (opt) {
+ case 's':
+ world.interactive = 0;
+ start_turn = 0;
+ if (optarg)
+ start_turn = atoi(optarg);
+ break;
+ default:
+ exit(EXIT_FAILURE); } }
+
+ world.log = calloc(1, sizeof(char));
+ update_log (&world, " ");
+ struct Player player;
+ world.player = &player;
+ struct Monster monster;
+ world.monster = &monster;
+ FILE * file;
+ if (1 == world.interactive && 0 == access("savefile", F_OK)) {
+ file = fopen("savefile", "r");
+ world.seed = read_uint32_bigendian(file);
+ world.turn = read_uint32_bigendian(file);
+ player.y = read_uint16_bigendian(file);
+ player.x = read_uint16_bigendian(file);
+ monster.y = read_uint16_bigendian(file);
+ monster.x = read_uint16_bigendian(file);
+ fclose(file); }
+ else {
+ world.turn = 1;
+ if (0 == world.interactive) {
+ file = fopen("record", "r");
+ world.seed = read_uint32_bigendian(file); }
+ else {
+ file = fopen("record", "w");
+ world.seed = time(NULL);
+ write_uint32_bigendian(world.seed, file);
+ fclose(file); } }
+ rrand(1, world.seed);
+ struct Map map = init_map();
+ world.map = ↦
+ if (1 == world.turn) {
+ for (player.y = player.x = 0; 0 == is_passable(&map, player.y, player.x);) {
+ player.y = rrand(0, 0) % map.height;
+ player.x = rrand(0, 0) % map.width; }
+ for (monster.y = monster.x = 0; 0 == is_passable(&map, monster.y, monster.x);) {
+ monster.y = rrand(0, 0) % map.height;
+ monster.x = rrand(0, 0) % map.width; } }