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 seed integer from seed 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 seed integer to seed 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 struct Player player;
224 world.player = &player;
225 struct Monster monster;
226 world.monster = &monster;
227 if (0 == access("savefile", F_OK))
234 world.seed = time(NULL);
236 rrand(1, world.seed);
238 init_keybindings(&world);
239 world.log = calloc(1, sizeof(char));
240 update_log (&world, "Start!");
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);
256 uint32_t last_turn = 0;
258 if (last_turn != world.turn) {
260 last_turn = world.turn; }
261 draw_all_windows (&win_meta);
263 if (key == get_action_key(world.keybindings, "quit"))
265 else if (key == get_action_key(world.keybindings, "scroll pad right"))
266 scroll_pad (&win_meta, '+');
267 else if (key == get_action_key(world.keybindings, "scroll pad left"))
268 scroll_pad (&win_meta, '-');
269 else if (key == get_action_key(world.keybindings, "toggle keys window"))
270 toggle_window(&win_meta, &win_keys);
271 else if (key == get_action_key(world.keybindings, "toggle map window"))
272 toggle_window(&win_meta, &win_map);
273 else if (key == get_action_key(world.keybindings, "toggle info window"))
274 toggle_window(&win_meta, &win_info);
275 else if (key == get_action_key(world.keybindings, "toggle log window"))
276 toggle_window(&win_meta, &win_log);
277 else if (key == get_action_key(world.keybindings, "cycle forwards"))
278 cycle_active_window(&win_meta, 'n');
279 else if (key == get_action_key(world.keybindings, "cycle backwards"))
280 cycle_active_window(&win_meta, 'p');
281 else if (key == get_action_key(world.keybindings, "shift forwards"))
282 shift_active_window(&win_meta, 'f');
283 else if (key == get_action_key(world.keybindings, "shift backwards"))
284 shift_active_window(&win_meta, 'b');
285 else if (key == get_action_key(world.keybindings, "grow horizontally"))
286 growshrink_active_window(&win_meta, '*');
287 else if (key == get_action_key(world.keybindings, "shrink horizontally"))
288 growshrink_active_window(&win_meta, '_');
289 else if (key == get_action_key(world.keybindings, "grow vertically"))
290 growshrink_active_window(&win_meta, '+');
291 else if (key == get_action_key(world.keybindings, "shrink vertically"))
292 growshrink_active_window(&win_meta, '-');
293 else if (key == get_action_key(world.keybindings, "save keys"))
294 save_keybindings(&world);
295 else if (key == get_action_key(world.keybindings, "keys nav up"))
296 keyswin_move_selection (&world, 'u');
297 else if (key == get_action_key(world.keybindings, "keys nav down"))
298 keyswin_move_selection (&world, 'd');
299 else if (key == get_action_key(world.keybindings, "keys mod"))
300 keyswin_mod_key (&world, &win_meta);
301 else if (key == get_action_key(world.keybindings, "map up"))
302 map_scroll (&map, 'n');
303 else if (key == get_action_key(world.keybindings, "map down"))
304 map_scroll (&map, 's');
305 else if (key == get_action_key(world.keybindings, "map right"))
306 map_scroll (&map, 'e');
307 else if (key == get_action_key(world.keybindings, "map left"))
308 map_scroll (&map, 'w');
309 else if (key == get_action_key(world.keybindings, "player down"))
310 move_player(&world, 's');
311 else if (key == get_action_key(world.keybindings, "player up"))
312 move_player(&world, 'n');
313 else if (key == get_action_key(world.keybindings, "player right"))
314 move_player(&world, 'e');
315 else if (key == get_action_key(world.keybindings, "player left"))
316 move_player(&world, 'w');
317 else if (key == get_action_key(world.keybindings, "wait") )
318 player_wait (&world); }
321 for (key = 0; key <= world.keyswindata->max; key++)
322 free(world.keybindings[key].name);
323 free(world.keybindings);
324 free(world.keyswindata);