home · contact · privacy
Fixed bug that led to endless loop in nearest_enemy_dir().
[plomrogue] / src / main.c
index 3d6c0d38f5054db6dcac826b2c871a4ac02841cc..c9e468bbe3aab0d339792f61d66983d0bb6c42b6 100644 (file)
-#include "main.h"
-#include <stdlib.h>
-#include <ncurses.h>
-#include <time.h>
-#include <unistd.h>
-#include "windows.h"
-#include "draw_wins.h"
-#include "keybindings.h"
-#include "readwrite.h"
-#include "map_objects.h"
-#include "map_object_actions.h"
-#include "map.h"
-#include "misc.h"
-
-int main (int argc, char *argv[]) {
-  struct World world;
-
-  // Read in startup options (i.e. replay option and replay start turn).
-  int opt;
-  uint32_t start_turn;
-  world.interactive = 1;
-  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); } }
-
-  // Initialize log, player, monsters and items.
-  world.log = calloc(1, sizeof(char));
-  update_log (&world, " ");
-  struct Player player;
-  player.hitpoints = 5;
-  world.player = &player;
-  world.monster = 0;
-  world.item = 0;
-  struct MonsterDef monster_def_A;
-  monster_def_A.map_obj_def.id = 1;
-  monster_def_A.map_obj_def.mapchar = 'a';
-  monster_def_A.map_obj_def.desc = "ANT";
-  monster_def_A.hitpoints_start = 1;
-  struct MonsterDef monster_def_B;
-  monster_def_B.map_obj_def.id = 2;
-  monster_def_B.map_obj_def.mapchar = 'z';
-  monster_def_B.map_obj_def.desc = "ZOMBIE";
-  monster_def_B.hitpoints_start = 3;
-  struct MonsterDef monster_def_C;
-  monster_def_C.map_obj_def.id = 3;
-  monster_def_C.map_obj_def.mapchar = 'S';
-  monster_def_C.map_obj_def.desc = "SHOGGOTH";
-  monster_def_C.hitpoints_start = 9;
-  world.monster_def = &monster_def_A;
-  monster_def_A.map_obj_def.next = (struct MapObjDef *) &monster_def_B;
-  monster_def_B.map_obj_def.next = (struct MapObjDef *) &monster_def_C;
-  monster_def_C.map_obj_def.next = NULL;
-  struct ItemDef item_def_A;
-  item_def_A.map_obj_def.id = 4;
-  item_def_A.map_obj_def.mapchar = '#';
-  struct ItemDef item_def_B;
-  item_def_B.map_obj_def.id = 5;
-  item_def_B.map_obj_def.mapchar = '%';
-  world.item_def = &item_def_A;
-  item_def_A.map_obj_def.next = (struct MapObjDef *) &item_def_B;
-  item_def_B.map_obj_def.next = NULL;
-
-  // For interactive mode, try to load world state from savefile.
-  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.pos.y = read_uint16_bigendian(file) - 1;
-    player.pos.x = read_uint16_bigendian(file) - 1;
-    player.hitpoints = fgetc(file);
-    read_map_objects (&world.monster, file, sizeof(struct Monster), read_map_objects_monsterdata);
-    read_map_objects (&world.item,    file, sizeof(struct Item),    readwrite_map_objects_dummy);
-    fclose(file); }
-
-  // For non-interactive mode, try to load world state from record file.
-  else {
-    world.turn = 1;
-    if (0 == world.interactive) {
-      file = fopen("record", "r");
-      world.seed = read_uint32_bigendian(file); }
-
-    // For interactive-mode in newly started world, generate a start seed from the current time.
-    else {
-      file = fopen("record", "w");
-      world.seed = time(NULL);
-      write_uint32_bigendian(world.seed, file);
-      fclose(file); } }
-
-  // Generate map from seed and, if newly generated world, start positions of actors.
-  rrand(1, world.seed);
-  struct Map map = init_map();
-  world.map = &map;
-  if (1 == world.turn) {
-    player.pos = find_passable_pos(&map);
-    void * foo = build_map_objects (&world, &world.monster, 1, 1 + rrand(0,0) % 27, sizeof(struct Monster),
-                                    build_map_objects_monsterdata);
-    foo = build_map_objects (&world, foo, 2, 1 + rrand(0,0) % 9, sizeof(struct Monster),
-                             build_map_objects_monsterdata);
-    build_map_objects (&world, foo, 3, 1 + rrand(0,0) % 3, sizeof(struct Monster),
-                       build_map_objects_monsterdata);
-    foo = build_map_objects (&world, &world.item, 4, 1 + rrand(0,0) % 3, sizeof(struct Item),
-                             build_map_objects_itemdata);
-    build_map_objects (&world, foo, 5, 1 + rrand(0,0) % 3, sizeof(struct Item), build_map_objects_itemdata); }
-
-  // Initialize window system and windows.
-  WINDOW * screen = initscr();
-  noecho();
-  curs_set(0);
-  keypad(screen, TRUE);
-  raw();
-  init_keybindings(&world);
-  struct WinMeta win_meta = init_win_meta(screen);
-  struct Win win_keys = init_win(&win_meta, "Keys", &world, draw_keys_win);
-  struct Win win_map = init_win(&win_meta, "Map", &world, draw_map_win);
-  struct Win win_info = init_win(&win_meta, "Info", &world, draw_info_win);
-  struct Win win_log = init_win(&win_meta, "Log", &world, draw_log_win);
-  win_keys.frame.size.x = 29;
-  win_map.frame.size.x = win_meta.pad.size.x - win_keys.frame.size.x - win_log.frame.size.x - 2;
-  win_info.frame.size.y = 2;
-  win_log.frame.size.y = win_meta.pad.size.y - (2 + win_info.frame.size.y);
-  toggle_window(&win_meta, &win_keys);
-  toggle_window(&win_meta, &win_map);
-  toggle_window(&win_meta, &win_info);
-  toggle_window(&win_meta, &win_log);
-
-  // Replay mode.
-  int key;
-  unsigned char quit_called = 0;
-  unsigned char await_actions = 1;
-  if (0 == world.interactive) {
-    int action;
-    while (1) {
-      if (start_turn == world.turn)
-        start_turn = 0;
-      if (0 == start_turn) {
-        draw_all_wins (&win_meta);
-        key = getch(); }
-      if (1 == await_actions &&
-          (world.turn < start_turn || key == get_action_key(world.keybindings, "wait / next turn")) ) {
-        action = getc(file);
-        if (EOF == action) {
-          start_turn = 0;
-          await_actions = 0; }
-        else if (0 == action)
-          player_wait (&world);
-        else if (NORTH == action)
-          move_player(&world, NORTH);
-        else if (EAST  == action)
-          move_player(&world, EAST);
-        else if (SOUTH == action)
-          move_player(&world, SOUTH);
-        else if (WEST == action)
-          move_player(&world, WEST); }
-      else
-        quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
-        if (1 == quit_called)
-          break; } }
-
-  // Interactive mode.
-  else {
-    uint32_t last_turn = 0;
-    while (1) {
-      if (last_turn != world.turn) {
-        save_game(&world);
-        last_turn = world.turn; }
-      if (1 == await_actions && 0 == player.hitpoints)
-        await_actions = 0;
-      draw_all_wins (&win_meta);
-      key = getch();
-      if      (1 == await_actions && key == get_action_key(world.keybindings, "player up"))
-        move_player(&world, NORTH);
-      else if (1 == await_actions && key == get_action_key(world.keybindings, "player right"))
-        move_player(&world, EAST);
-      else if (1 == await_actions && key == get_action_key(world.keybindings, "player down"))
-        move_player(&world, SOUTH);
-      else if (1 == await_actions && key == get_action_key(world.keybindings, "player left"))
-        move_player(&world, WEST);
-      else if (1 == await_actions && key == get_action_key(world.keybindings, "wait / next turn"))
-        player_wait (&world);
-      else
-        quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
-        if (1 == quit_called)
-          break; } }
-
-  // Clean up and exit.
-  free(map.cells);
-  for (key = 0; key <= world.keyswindata->max; key++)
-    free(world.keybindings[key].name);
-  free(world.keybindings);
-  free(world.keyswindata);
-  free(world.log);
-  endwin();
-  return 0; }
+/* main.c */
+
+#include "main.h" /* for world global */
+#include <stdlib.h> /* for atoi(), exit(), EXIT_FAILURE */
+#include <stdio.h> /* for FILE typedef, F_OK */
+#include <ncurses.h> /* for noecho(), curs_set(), keypad(), raw() */
+#include <time.h> /* for time() */
+#include <unistd.h> /* for getopt(), optarg */
+#include <stdint.h> /* for uint32_t */
+#include "windows.h" /* for structs WinMeta, Win, init_win_meta(),
+                      * draw_all_wins()
+                      */
+#include "readwrite.h" /* for try_fgetc(), read_uint32_bigendian(),
+                        * write_uint32_bigendian(), try_fopen(), try_fclose(),
+                        * try_fclose_unlink_rename(), try_fgetc_noeof(),
+                        */
+#include "map_objects.h" /* for structs MapObj, init_map_object_defs(),
+                          * add_map_objects(), get_player()
+                          */
+#include "map.h" /* for struct Map, init_map() */
+#include "misc.h" /* for update_log(), save_game(), try_calloc(), load_game(),
+                   * check_tempfile(), check_files_xor(), load_interface_conf(),
+                   * rrand()
+                   */
+#include "wincontrol.h" /* get_win_by_id(), get_winconf_by_win() */
+#include "rexit.h" /* for exit_game() */
+#include "command_db.h" /* for init_command_db(), is_command_id_shortdsc() */
+#include "control.h" /* for control_by_id(), player_control(),
+                      * get_available_keycode_to_action()
+                      */
+#include "map_object_actions.h" /* for init_map_object_actions() */
+
+
+
+int main(int argc, char *argv[])
+{
+    char * f_name = "main()";
+    world.turn = 0;        /* Turns to 1 when map and objects are initalized. */
+
+    /* Initialize commands and map object actions. */
+    init_command_db();
+    set_cleanup_flag(CLEANUP_COMMAND_DB);
+    init_map_object_actions();
+    set_cleanup_flag(CLEANUP_MAP_OBJECT_ACTS);
+
+    /* Check for corrupted savefile / recordfile savings. */
+    char * recordfile = "record";
+    char * savefile = "savefile";
+    char * recordfile_tmp = "record_tmp";
+    char * savefile_tmp   = "savefile_tmp";
+    check_files_xor(savefile, recordfile);
+    check_tempfile(recordfile_tmp);
+    check_tempfile(savefile_tmp);
+    check_tempfile("config/windows/Win_tmp_k");
+    check_tempfile("config/windows/Win_tmp_m");
+    check_tempfile("config/windows/Win_tmp_i");
+    check_tempfile("config/windows/Win_tmp_l");
+    check_tempfile("config/windows/toggle_order_tmp");
+
+    /* Read in startup options (i.e. replay option and replay start turn). */
+    int opt;
+    uint32_t start_turn;
+    world.interactive = 1;
+    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);
+            }
+        }
+    }
+
+    /* Initialize log and map object definitions. */
+    world.score = 0;
+    world.log = try_calloc(1, sizeof(char), f_name);
+    set_cleanup_flag(CLEANUP_LOG);
+    update_log(" ");
+    init_map_object_defs("config/defs");
+    set_cleanup_flag(CLEANUP_MAP_OBJECT_DEFS);
+    world.map_obj_count = 0;
+
+    /* For interactive mode, try to load world state from savefile. */
+    FILE * file;
+    if (1 == world.interactive && 0 == access(savefile, F_OK))
+    {
+        load_game();
+        set_cleanup_flag(CLEANUP_MAP_OBJECTS);
+    }
+
+    /* For non-interactive mode, try to load world state from record file. */
+    else
+    {
+        if (0 == world.interactive)
+        {
+            file = try_fopen(recordfile, "r", f_name);
+            world.seed = read_uint32_bigendian(file);
+        }
+
+        /* For interactive-mode in newly started world, generate a start seed
+         * from the current time.
+         */
+        else
+        {
+            world.seed = time(NULL);
+            file = try_fopen(recordfile_tmp, "w", f_name);
+            write_uint32_bigendian(world.seed, file);
+            try_fclose_unlink_rename(file, recordfile_tmp, recordfile, f_name);
+        }
+        world.mapseed = world.seed;
+    }
+
+    /* Generate map from seed and, if newly generated world, start positions of
+     * actors.
+     */
+    uint32_t restore_seed = world.seed;
+    world.seed = world.mapseed;
+    struct Map map = init_map();
+    world.map = &map;
+    set_cleanup_flag(CLEANUP_MAP);
+    if (0 == world.turn)
+    {
+        world.map_objs = NULL;
+        add_map_objects(0, 1);
+        add_map_objects(1, 1 + rrand() % 27);
+        add_map_objects(2, 1 + rrand() % 9);
+        add_map_objects(3, 1 + rrand() % 3);
+        add_map_objects(4, 1 + rrand() % 3);
+        add_map_objects(5, 1 + rrand() % 3);
+        set_cleanup_flag(CLEANUP_MAP_OBJECTS);
+        world.turn = 1;
+    }
+    world.seed = restore_seed;
+
+    /* Initialize window system and windows. */
+    init_win_meta();
+    set_cleanup_flag(CLEANUP_NCURSES);
+    noecho();
+    curs_set(0);
+    keypad(world.wmeta->screen, TRUE);
+    raw();
+    load_interface_conf();
+    set_cleanup_flag(CLEANUP_INTERFACE);
+
+    /* Focus map on player. */
+    struct MapObj * player = get_player();
+    struct Win * win_map = get_win_by_id('m');
+    win_map->center = player->pos;
+
+    /* Initialize player's inventory selection index to start position. */
+    world.inventory_sel = 0;
+
+    /* Replay mode. */
+    int key;
+    struct WinConf * wc;
+    if (0 == world.interactive)
+    {
+        int action = 0;
+        if (0 != start_turn)
+        {
+            while (world.turn != start_turn)
+            {
+                action = try_fgetc(file, f_name);
+                if (EOF == action)
+                {
+                    break;
+                }
+                if (   is_command_id_shortdsc(action, "drop")
+                    || is_command_id_shortdsc(action, "use"))
+                {
+                    world.inventory_sel = try_fgetc_noeof(file, f_name);
+                }
+                player_control_by_id(action);
+            }
+        }
+        while (1)
+        {
+            draw_all_wins();
+            key = getch();
+            wc = get_winconf_by_win(world.wmeta->active);
+            if  (   (1 == wc->view && wingeom_control(key))
+                 || (2 == wc->view && winkeyb_control(key)))
+            {
+                continue;
+            }
+            if (   EOF != action
+                && key == get_available_keycode_to_action("wait"))
+            {
+                action = try_fgetc(file, f_name);
+                if (EOF != action)
+                {
+                    if (   is_command_id_shortdsc(action, "drop")
+                        || is_command_id_shortdsc(action, "use"))
+                    {
+                        world.inventory_sel = try_fgetc_noeof(file, f_name);
+                    }
+                    player_control_by_id(action);
+                }
+            }
+            else if (meta_control(key))
+            {
+                try_fclose(file, f_name);
+                exit_game();
+            }
+        }
+    }
+
+    /* Interactive mode. */
+    else
+    {
+        while (1)
+        {
+            save_game();
+            draw_all_wins();
+            key = getch();
+            wc = get_winconf_by_win(world.wmeta->active);
+            if  (   (1 == wc->view && wingeom_control(key))
+                 || (2 == wc->view && winkeyb_control(key))
+                 || (0 != player->lifepoints && player_control_by_key(key)))
+            {
+                continue;
+            }
+            if (meta_control(key))
+            {
+                exit_game();
+            }
+        }
+    }
+}