Skip to content
Snippets Groups Projects
rlg327.cpp 5.61 KiB
Newer Older
#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);
}