X-Git-Url: https://plomlompom.com/repos/?a=blobdiff_plain;f=src%2Fmisc.c;h=50fee6407854469819a691ccb8826943f55fd08a;hb=550d22ec0c3f530f5d317746f3f7e75251a1de4b;hp=692198d2d6a581e3cb6109bdfbf771fd1e665770;hpb=d951e2631a19500f1bb8c29f9e029a9d9fb29ae7;p=plomrogue diff --git a/src/misc.c b/src/misc.c index 692198d..50fee64 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1,152 +1,224 @@ +/* misc.c */ + #include "misc.h" -#include -#include -#include "windows.h" -#include "keybindings.h" -#include "readwrite.h" -#include "objects_on_map.h" -#include "map.h" -#include "main.h" - -uint16_t rrand(char use_seed, uint32_t new_seed) { -// Pseudo-random number generator (LGC algorithm). Use instead of rand() to ensure portable predictability. - static uint32_t seed; - if (0 != use_seed) - seed = new_seed; - seed = ((seed * 1103515245) + 12345) % 2147483648; // Values as recommended by POSIX.1-2001 (see rand(3)). - return (seed / 65536); } // Ignore least significant 16 bits (they are less random). - -void update_log (struct World * world, char * text) { -// Update log by appending text, or by appending a "." if text is the same as the last one. - static char * last_msg; - if (0 == last_msg) - last_msg = calloc(1, sizeof(char)); - char * new_text; - uint16_t len_old = strlen(world->log); - if (0 == strcmp(last_msg, text)) { - uint16_t len_whole = len_old + 1; - new_text = calloc(len_whole + 1, sizeof(char)); - memcpy(new_text, world->log, len_old); - memcpy(new_text + len_old, ".", 1); } - else { - uint16_t len_new = strlen(text); - uint16_t len_whole = len_old + len_new + 1; - new_text = calloc(len_whole, sizeof(char)); - memcpy(new_text, world->log, len_old); - memcpy(new_text + len_old, text, len_new); - last_msg = calloc(len_new + 1, sizeof(char)); - memcpy(last_msg, text, len_new); } - free(world->log); - world->log = new_text; } - -uint16_t center_offset (uint16_t pos, uint16_t mapsize, uint16_t framesize) { -// Return the offset for display of a map inside a frame centered on pos. - uint16_t offset = 0; - if (mapsize > framesize) { - if (pos > framesize / 2) { - if (pos < mapsize - (framesize / 2)) - offset = pos - (framesize / 2); - else - offset = mapsize - framesize; } } - return offset; } - -void turn_over (struct World * world, char action) { -// Record action in game record file, increment turn and move enemy. - if (1 == world->interactive) { - FILE * file = fopen("record", "a"); - fputc(action, file); - fclose(file); } - world->turn++; - rrand(1, world->seed * world->turn); - struct Monster * monster; - for (monster = world->monster; monster != 0; monster = monster->cmo.next) - move_monster(world, monster); } - -void save_game(struct World * world) { -// Save game data to game file. - FILE * file = fopen("savefile", "w"); - write_uint32_bigendian(world->seed, file); - write_uint32_bigendian(world->turn, file); - write_uint16_bigendian(world->player->pos.y + 1, file); - write_uint16_bigendian(world->player->pos.x + 1, file); - fputc(world->player->hitpoints, file); - write_map_objects (world->monster, file, write_map_objects_monsterdata); - write_map_objects (world->item, file, readwrite_map_objects_dummy); - fclose(file); } - -void toggle_window (struct WinMeta * win_meta, struct Win * win) { -// Toggle display of window win. - if (0 != win->frame.curses_win) - suspend_win(win_meta, win); - else - append_win(win_meta, win); } - -void scroll_pad (struct WinMeta * win_meta, char dir) { -// Try to scroll pad left or right. - if ('+' == dir) - reset_pad_offset(win_meta, win_meta->pad_offset + 1); - else if ('-' == dir) - reset_pad_offset(win_meta, win_meta->pad_offset - 1); } - -void growshrink_active_window (struct WinMeta * win_meta, char change) { -// Grow or shrink active window horizontally or vertically by one cell size. - if (0 != win_meta->active) { - struct yx_uint16 size = win_meta->active->frame.size; - if (change == '-') size.y--; - else if (change == '+') size.y++; - else if (change == '_') size.x--; - else if (change == '*') size.x++; - resize_active_win (win_meta, size); } } - -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, NORTH, win_map->frame.size); - else if (key == get_action_key(world->keybindings, "map down")) - map_scroll (world->map, SOUTH, win_map->frame.size); - else if (key == get_action_key(world->keybindings, "map right")) - map_scroll (world->map, EAST, win_map->frame.size); - else if (key == get_action_key(world->keybindings, "map left")) - map_scroll (world->map, WEST, win_map->frame.size); - else if (key == get_action_key(world->keybindings, "map center player")) - map_center_player (world->map, world->player, win_map->frame.size); - return 0; } +#include /* for errno */ +#include /* for unlink(), acess() */ +#include /* for size_t, calloc(), free() */ +#include /* for strlen(), strcmp(), memcpy() */ +#include /* for uint8_t, uint16_t */ +#include "readwrite.h" /* for [read/write]_uint[8/16/32][_bigendian](), + * try_fopen(), try_fclose() + */ +#include "map_objects.h" /* for struct Monster, write_map_objects(), */ +#include "map_object_actions.h" /* for is_passable(), move_monster() */ +#include "map.h" /* for Map struct */ +#include "main.h" /* for World struct */ +#include "yx_uint16.h" /* for yx_uint16 struct */ +#include "rrand.h" /* for rrand(), rrand_seed() */ +#include "rexit.h" /* for exit_err() */ + + + +extern char * trouble_msg(struct World * w, char * parent, char * child) +{ + char * p1 = "Trouble in "; + char * p2 = " with "; + char * p3 = "."; + uint16_t size = strlen(p1) + strlen(parent) + strlen(p2) + strlen(child) + + strlen(p3) + 1; + char * msg = malloc(size); + exit_err(NULL == msg, w, "malloc() in trouble_msg() failed."); + sprintf(msg, "%s%s%s%s%s", p1, parent, p2, child, p3); + return msg; +} + + + +extern void * try_malloc(size_t size, struct World * w, char * f) +{ + char * msg = trouble_msg(w, f, "malloc()"); + void * p = malloc(size); + exit_err(NULL == p, w, msg); + free(msg); + return p; +} + + + +extern void * try_calloc(size_t size1, size_t size2, struct World * w, char * f) +{ + char * msg = trouble_msg(w, f, "calloc()"); + void * p = calloc(size1, size2); + exit_err(NULL == p, w, msg); + free(msg); + return p; +} + + + +extern void check_files_xor(char * p1, char * p2, struct World * w) +{ + char * msg1 = "A file '"; + char * msg2 = "' exists, but no file '"; + char * msg3 = "'. If everything was in order, both or noe would exist. " + "The game won't start until this is corrected."; + uint16_t size = strlen(msg1) + strlen(p1) + strlen(msg2) + strlen(p2) + + strlen(msg3); + char msg[size]; + if (!access(p1, F_OK) && access(p2, F_OK)) + { + sprintf(msg, "%s%s%s%s%s", msg1, p1, msg2, p2, msg3); + errno = 0; + exit_err(1, w, msg); + } + else if (access(p1, F_OK) && !access(p2, F_OK)) + { + sprintf(msg, "%s%s%s%s%s", msg1, p2, msg2, p1, msg3); + errno = 0; + exit_err(1, w, msg); + } +} + + + +extern void check_tempfile(char * path, struct World * w) +{ + char * msg1 = "A file '"; + char * msg2 = "' exists, probably from a corrupted previous file saving " + "process. To avoid corruption of game files, the game won't " + "start until it is removed or renamed."; + uint16_t size = strlen(msg1) + strlen(path) + strlen(msg2); + char msg[size]; + sprintf(msg, "%s%s%s", msg1, path, msg2); + exit_err(!access(path, F_OK), w, msg); +} + + + +extern void update_log(struct World * world, char * text) +{ + char * f_name = "update_log()"; + static char * last_msg; /* TODO: valgrind is dissatisfied */ + if (0 == last_msg) /* with this calloc'd pointer not */ + { /* being freed. Rectify this? */ + last_msg = try_calloc(1, sizeof(char), world, f_name); + } + char * new_text; + uint16_t len_old = strlen(world->log); + if (0 == strcmp(last_msg, text)) + { + uint16_t len_whole = len_old + 1; + new_text = try_calloc(len_whole + 1, sizeof(char), world, f_name); + memcpy(new_text, world->log, len_old); + memcpy(new_text + len_old, ".", 1); + } + else + { + uint16_t len_new = strlen(text); + uint16_t len_whole = len_old + len_new + 1; + new_text = try_calloc(len_whole, sizeof(char), world, f_name); + memcpy(new_text, world->log, len_old); + memcpy(new_text + len_old, text, len_new); + last_msg = try_calloc(len_new + 1, sizeof(char), world, f_name); + memcpy(last_msg, text, len_new); + } + free(world->log); + world->log = new_text; +} + + + +extern uint16_t center_offset(uint16_t pos, uint16_t mapsize, + uint16_t framesize) +{ + uint16_t offset = 0; + if (mapsize > framesize) + { + if (pos > framesize / 2) + { + if (pos < mapsize - (framesize / 2)) + { + offset = pos - (framesize / 2); + } + else + { + offset = mapsize - framesize; + } + } + } + return offset; +} + + + +extern void turn_over(struct World * world, char action) +{ + char * f_name = "turn_over()"; + char * err_write = "Trouble in turn_over() with write_uint8() " + "writing to opened file 'record_tmp'."; + + char * recordfile_tmp = "record_tmp"; + char * recordfile = "record"; + if (1 == world->interactive) + { + FILE * file_old = try_fopen(recordfile, "r", world, f_name); + FILE * file_new = try_fopen(recordfile_tmp, "w", world, f_name); + char c = fgetc(file_old); + while (EOF != c) + { + exit_err(write_uint8(c, file_new), world, err_write); + c = fgetc(file_old); + } + try_fclose(file_old, world, f_name); + exit_err(write_uint8(action, file_new), world, err_write); + try_fclose_unlink_rename(file_new, recordfile_tmp, recordfile, + world, f_name); + } + world->turn++; + rrand_seed(world->seed * world->turn); + struct Monster * monster; + for (monster = world->monster; + monster != 0; + monster = monster->map_obj.next) + { + move_monster(world, monster); + } +} + + + +extern void save_game(struct World * world) +{ + char * f_name = "save_game()"; + char * err_write = "Trouble in save_game() " + "writing to opened file 'savefile_tmp'."; + + char * savefile_tmp = "savefile_tmp"; + char * savefile = "savefile"; + FILE * file = try_fopen(savefile_tmp, "w", world, f_name); + if ( write_uint32_bigendian(world->seed, file) + || write_uint32_bigendian(world->turn, file) + || write_uint16_bigendian(world->score, file) + || write_uint16_bigendian(world->player->pos.y + 1, file) + || write_uint16_bigendian(world->player->pos.x + 1, file) + || write_uint8(world->player->hitpoints, file) + || write_map_objects(world, world->monster, file) + || write_map_objects(world, world->item, file)) + { + exit_err(1, world, err_write); + } + try_fclose_unlink_rename(file, savefile_tmp, savefile, world, f_name); +} + + + +extern struct yx_uint16 find_passable_pos(struct Map * map) +{ + struct yx_uint16 pos; + for (pos.y = pos.x = 0; 0 == is_passable(map, pos);) + { + pos.y = rrand() % map->size.y; + pos.x = rrand() % map->size.x; + } + return pos; +}