#include <ncurses.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <string.h> #include "character.h" #include "dungeon.h" #include "draw_dungeon.h" #include "distance_map.h" #include "display_result.h" #include "line_of_sight.h" #include "movement_logic.h" #include "monster_list.h" #include "save_load.h" #include "util.h" void regen_dungeon(dungeon_t *d, heap_t *h, int nummon) { heap_delete(h); free_dungeon(d); init_dungeon(d); gen_random_dungeon(d); gen_monsters(d, nummon); init_turn_heap(d, h); calc_line_of_sight(d, d->pc_sight, d->player_pos.x, d->player_pos.y); } int main(int argc, char* argv[]) { int i; args_t args; parse_args(argc, argv, &args); srand(args.seed); dungeon_t d; init_dungeon(&d); if (args.load) { load_dungeon(&d); } else { gen_random_dungeon(&d); } gen_monsters(&d, args.nummon); if (args.save) { save_dungeon(&d); } init_screen(); display_message("Using seed: %d", args.seed); heap_t h; init_turn_heap(&d, &h); int game_won = 0; // Initialize line of sight calc_line_of_sight(&d, d.pc_sight, d.player_pos.x, d.player_pos.y); while(1) { character_t *c = heap_remove_min(&h); int clear_message = 1; // If the character is not alive, then free its memory if (!c->alive) { if (c->player) { free(c->player); free(c); game_won = 0; break; } else { free(c->monster); free(c); if (h.size == 1) { // Only one character left and the game isn't over, the player must have won game_won = 1; break; } else { continue; } } } // The character decides where to move next position_t next_move; if (c->monster) { next_move = monster_move(&d, c); } else { draw_dungeon(&d); refresh_screen(); int key; int handled_move = 0; while(!handled_move) { key = getch(); if (key == 'Q' || key == 'q') { game_won = -1; break; } next_move = c->pos; if (key == '7' || key == 'y') { next_move.x--; next_move.y--; handled_move = 1; } if (key == '8' || key == 'k') { next_move.y--; handled_move = 1; } if (key == '9' || key == 'u') { next_move.y--; next_move.x++; handled_move = 1; } if (key == '6' || key == 'l') { next_move.x++; handled_move = 1; } if (key == '3' || key == 'n') { next_move.x++; next_move.y++; handled_move = 1; } if (key == '2' || key == 'j') { next_move.y++; handled_move = 1; } if (key == '1' || key == 'b') { next_move.x--; next_move.y++; handled_move = 1; } if (key == '4' || key == 'h') { next_move.x--; handled_move = 1; } if (key == '5' || key == ' ' || key == '.') { handled_move = 1; } if (key == 'm') { if(display_monster_list(&d)) { game_won = -1; break; } draw_dungeon(&d); refresh_screen(); } if (key == '>') { for (i = 0; i < d.downstair_count; i++) { if (d.downstair_list[i].x == d.player_pos.x && d.downstair_list[i].y == d.player_pos.y) { regen_dungeon(&d, &h, args.nummon); handled_move = 2; draw_dungeon(&d); refresh_screen(); } } if (!handled_move) { display_message("%s", "Can't go downstairs there!"); refresh_screen(); } } if (key == '<') { for (i = 0; i < d.upstair_count; i++) { if (d.upstair_list[i].x == d.player_pos.x && d.upstair_list[i].y == d.player_pos.y) { regen_dungeon(&d, &h, args.nummon); handled_move = 2; draw_dungeon(&d); refresh_screen(); } } if (!handled_move) { display_message("%s", "Can't go upstairs there!"); refresh_screen(); } } } if (handled_move == 2) { continue; } } if (game_won == -1) { break; } // If we killed another character by moving there if (d.characters[next_move.y][next_move.x] && d.characters[next_move.y][next_move.x] != c) { d.characters[next_move.y][next_move.x]->alive = 0; } // Check for rock and tunneling if (d.hardness[next_move.y][next_move.x] && d.hardness[next_move.y][next_move.x] < 255 && has_characteristic(c, TUNNEL)) { if (d.hardness[next_move.y][next_move.x] > 85) { d.hardness[next_move.y][next_move.x] -= 85; } else { d.hardness[next_move.y][next_move.x] = 0; } // Update the line of sight calc_line_of_sight(&d, d.pc_sight, d.player_pos.x, d.player_pos.y); } // If the space we want to move to has hardness zero, move there if (d.hardness[next_move.y][next_move.x] == 0) { d.characters[c->pos.y][c->pos.x] = NULL; d.characters[next_move.y][next_move.x] = c; c->pos.x = next_move.x; c->pos.y = next_move.y; if (c->player) { d.player_pos.x = next_move.x; d.player_pos.y = next_move.y; } } else if (c->player) { display_message("%s", "Ouch, that was a wall."); clear_message = 0; } // Update the character's turn and reinsert into heap c->next_turn = c->next_turn + (1000 / c->speed); heap_insert(&h, c); // If the player moved, update line of sight, redraw, and sleep for the timestep if (c->player) { calc_line_of_sight(&d, d.pc_sight, d.player_pos.x, d.player_pos.y); if (clear_message) { display_message(""); } } } if (game_won == 1) { display_win(); } else if (game_won == 0) { display_lose(); } destroy_screen(); heap_delete(&h); free_dungeon(&d); }