#include #include #include #include #include #include #include #define level_width_limit (120) #define level_height_limit ( 60) #define members ( 6) #define items ( 36) #define random(from, to) (rand () % (to - from + 1) + from) enum { normal = '0', bold = '1', italic = '2', blink = '5', reverse = '7' }; enum { grey = '0', red = '1', green = '2', yellow = '3', blue = '4', pink = '5', cyan = '6', white = '7' }; enum { cut = 1, blunt = 2, pierce = 4, range = 8, magic = 16 }; enum { health, mana, stamina, experience, points }; enum { strength, dexterity, agility, intelligence, attributes }; enum { fighting, blocking, shooting, spellcasting, evoking, trading, healing, lockpicking, skills }; enum { warrior, mage, thief, priest, archer, alchemist, warlock, merchant, classes }; static struct { char clip, style, colour, symbol; } const tiles [] = { { 1, normal, white, ' ' }, { 0, bold, grey, '.' }, { 1, bold, grey, '#' } }; static struct { char * name, damage, condition, value, spell, type, style, colour, symbol; } const weapons [] = { { "Bone Dagger", 1, 11, 5, 0, cut, bold, yellow, '!' }, { "Iron Dagger", 1, 19, 7, 0, cut, bold, yellow, '!' }, { "Steel Dagger", 1, 23, 11, 0, cut, bold, yellow, '!' }, { "Silver Dagger", 2, 29, 13, 0, cut, bold, yellow, '!' }, { "Bone Sword", 3, 23, 11, 0, cut, bold, yellow, '!' }, { "Iron Sword", 5, 31, 29, 0, cut, bold, yellow, '!' }, { "Steel Sword", 5, 37, 31, 0, cut, bold, yellow, '!' }, { "Silver Sword", 7, 43, 37, 0, cut, bold, yellow, '!' }, { "Bone Greatsword", 7, 41, 23, 0, blunt | cut, bold, yellow, '!' }, { "Iron Greatsword", 11, 47, 71, 0, blunt | cut, bold, yellow, '!' }, { "Steel Greatsword", 13, 53, 73, 0, blunt | cut, bold, yellow, '!' }, { "Silver Greatsword", 17, 59, 79, 0, blunt | cut, bold, yellow, '!' } }; static struct { char * name, resistance, condition, value, spell, type, style, colour, symbol; } const armours [] = { { "Wanderer Robe", 0, 11, 11, 0, cut, bold, green, ']' }, { "Priest Robe", 0, 13, 7, 0, cut, bold, green, ']' }, { "Commoner Clothes", 0, 5, 5, 0, blunt, bold, green, ']' }, { "Nobleman Clothes", 0, 7, 31, 0, magic, bold, green, ']' }, { "Assassin Clothes", 1, 11, 13, 0, blunt, bold, green, ']' }, { "Adventurer Clothes", 1, 13, 17, 0, cut, bold, green, ']' }, { "Thief Clothes", 1, 11, 11, 0, blunt, bold, green, ']' }, { "Merchant Clothes", 1, 11, 13, 0, pierce, bold, green, ']' }, { "Fur Armour", 2, 19, 23, 0, blunt | pierce, bold, green, ']' }, { "Leather Armour", 2, 23, 31, 0, blunt, bold, green, ']' }, { "Chainmail Armour", 3, 31, 41, 0, blunt | cut, bold, green, ']' }, { "Mithril Armour", 7, 83, 97, 0, blunt | cut | pierce, bold, green, ']' }, { "Bone Armour", 3, 29, 37, 0, blunt | pierce, bold, green, ']' }, { "Iron Armour", 5, 53, 61, 0, blunt | cut, bold, green, ']' }, { "Steel Armour", 5, 67, 71, 0, blunt | cut, bold, green, ']' }, { "Silver Armour", 5, 71, 89, 0, blunt | cut | pierce, bold, green, ']' } }; static struct { char x, y, coins, inventory [items], weapon [members], armour [members], point [members] [points], attribute [members] [attributes], skill [members], class [members]; } player; static struct termios old_terminal; static struct termios new_terminal; static int signal; static int screen_width; static int screen_height; static char * screen; static int level_width; static int level_height; static char * level; static void screen_put (char style, char colour, char symbol, int x, int y) { char format [] = "\033[ ;3 m \033[0m"; format [2] = style; format [5] = colour; format [7] = symbol; strncpy (& screen [(y * screen_width + x) * 12 + 3], format, sizeof (format) - 1); } static void screen_print (char style, char colour, char * text, int x, int y, int limit) { int i; for (i = 0; (text [i] != '\0') && (i < limit); ++i) { screen_put (style, colour, text [i], x + i, y); } } static void initialize_screen (void) { struct winsize screen_dimension; ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension); screen_width = (int) screen_dimension.ws_col; screen_height = (int) screen_dimension.ws_row; tcgetattr (STDIN_FILENO, & old_terminal); new_terminal = old_terminal; new_terminal.c_cc [VMIN] = (unsigned char) 0; new_terminal.c_cc [VTIME] = (unsigned char) 1; new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); new_terminal.c_oflag &= (unsigned int) ~(OPOST); new_terminal.c_cflag |= (unsigned int) (CS8); new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG); tcsetattr (STDIN_FILENO, TCSAFLUSH, & new_terminal); screen = calloc ((unsigned long int) (12 * screen_width * screen_height + 4), sizeof (* screen)); strcpy (screen, "\033[H"); } static void deinitialize_screen (void) { free (screen); write (STDOUT_FILENO, "\033[2J\033[H", 7); tcsetattr (STDIN_FILENO, TCSAFLUSH, & old_terminal); } static void synchronize_screen (void) { int new_screen_width, new_screen_height; struct winsize screen_dimension; ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension); new_screen_width = (int) screen_dimension.ws_col; new_screen_height = (int) screen_dimension.ws_row; if ((screen_width != new_screen_width) || (screen_height != new_screen_height)) { screen_width = new_screen_width; screen_height = new_screen_height; free (screen); screen = calloc ((unsigned long int) (12 * screen_width * screen_height + 4), sizeof (* screen)); } write (STDOUT_FILENO, screen, (unsigned long int) (12 * screen_width * screen_height + 4)); signal = 0; read (STDIN_FILENO, & signal, sizeof (signal)); switch (signal) { case 'k': { player.y -= 1; } break; case 'j': { player.y += 1; } break; case 'h': { player.x -= 1; } break; case 'l': { player.x += 1; } break; case 'y': { player.x -= 1; player.y -= 1; } break; case 'u': { player.x += 1; player.y -= 1; } break; case 'b': { player.x -= 1; player.y += 1; } break; case 'n': { player.x += 1; player.y += 1; } break; default: break; } player.x = (char) ((player.x > level_width) ? (level_width) : ((player.x < 0) ? 0 : player.x)); player.y = (char) ((player.y > level_height) ? (level_height) : ((player.y < 0) ? 0 : player.y)); } static void generate_party (void) { int i, j; player.x = 0; player.y = 0; player.coins = 0; for (i = 0; i < items; ++i) { player.inventory [i] = 0; } for (i = 0; i < members; ++i) { player.weapon [i] = random (0, 3); player.armour [i] = random (0, 3); for (j = 0; j < points; ++j) { player.point [i] [j] = random (12, 24); } for (j = 0; j < attributes; ++j) { player.attribute [i] [j] = random (1, 4); } player.skill [i] = rand () % skills; player.class [i] = rand () % classes; } } static void generate_level (void) { int room, i, j, x, y, width, height; level_width = random (level_width_limit / 2, level_width_limit); level_height = random (level_height_limit / 2, level_height_limit); level = calloc ((unsigned long int) (level_width * level_height), sizeof (* level)); for (room = random (6, 18); room > 1; --room) { width = random (level_width / 6, level_width / 2); height = random (level_height / 6, level_height / 2); x = random (1, level_width - width - 1); y = random (1, level_height - height - 1); for (i = 1; i < height - 1; ++i) { for (j = 1; j < width - 1; ++j) { level [(i + y) * level_width + (j + x)] = 1; } } for (i = 0; i < height; ++i) { level [(i + y) * level_width + x] = 2; level [(i + y) * level_width + x + width - 1] = 2; } for (j = 0; j < width; ++j) { level [y * level_width + j + x] = 2; level [(y + height - 1) * level_width + j + x] = 2; } } for (i = 1; i < level_height - 1; ++i) { for (j = 1; j < level_width - 1; ++j) { if (((level [i * level_width + (j - 1)] == 1) && (level [i * level_width + j] == 2) && (level [i * level_width + (j + 1)] == 1)) || ((level [(i - 1) * level_width + j] == 1) && (level [i * level_width + j] == 2) && (level [(i + 1) * level_width + j] == 1))) { level [i * level_width + j] = 1; } } } } int main (void) { int i, x, y; srand (time (0)); initialize_screen (); generate_party (); generate_level (); while (signal != 'Q') { for (y = 0; y < screen_height; ++y) { for (x = 0; x < screen_width; ++x) { screen_put (tiles [0].style, tiles [0].colour, tiles [0].symbol, x, y); } } for (y = 0; (y < level_height) && (y < screen_height); ++y) { for (x = 0; (x < level_width) && (x < screen_width); ++x) { i = (int) level [y * level_width + x]; screen_put (tiles [i].style, tiles [i].colour, tiles [i].symbol, x, y); } } screen_put (bold, cyan, '@', player.x, player.y); screen_print (bold, grey, "Warrior", screen_width - 24, 0, 24); synchronize_screen (); } free (level); deinitialize_screen (); return (0); }