#include #include #include #include #include #include #include #define level_width_limit (128) #define level_height_limit ( 64) #define members ( 6) #define items ( 36) #define random(from, to) (rand () % (to - from + 1) + from) #define minimum(a, b) ((a < b) ? a : b) #define maximum(a, b) ((a > b) ? a : b) #define clamp(x, a, b) ((x < a) ? a : (x > b) ? b : x) 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 char * point_name [points] = { "HP = ", "MP = ", "SP = ", "XP = " }; static char * attribute_name [attributes] = { "Strength : ", "Dexterity : ", "Agility : ", "Intelligence : " }; static char * skill_name [skills] = { "Fighting", "Blocking", "Shooting", "Spellcasting", "Evoking", "Trading", "Healing", "Lockpicking" }; static char * class_name [classes] = { "Warrior", "Mage", "Thief", "Priest", "Archer", "Alchemist", "Warlock", "Merchant" }; static struct { char clip, style, colour, symbol; } const tiles [] = { { 1, normal, white, ' ' }, { 0, bold, grey, '.' }, { 1, bold, grey, '#' }, { 1, reverse, blue, '-' }, }; 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 int screen_side; 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"); screen_side = 32; } 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 = clamp (player.x, 0, (char) level_width - 1); player.y = clamp (player.y, 0, (char) level_height - 1); } 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 (5, level_width / 2); height = random (5, 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] = level [(i + y) * level_width + x + width - 1] = 2; } for (j = 0; j < width; ++j) { level [y * level_width + j + x] = 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; } } } for (i = 0; i < level_height; ++i) { level [i * level_width] = level [i * level_width + level_width - 1] = 3; } for (j = 0; j < level_width; ++j) { level [j] = level [(level_height - 1) * level_width + j] = 3; } } static void generate_party (void) { int i, j; 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; } do { player.x = (char) (rand () % level_width); player.y = (char) (rand () % level_height); } while (level [player.y * level_width + player.x] != 1); } int main (void) { int i, j, x, y; srand (time (0)); initialize_screen (); generate_level (); generate_party (); 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 = maximum (0, player.y - screen_height / 2); (y < player.y + screen_height / 2) && (y < level_height); ++y) { for (x = maximum (0, player.x - screen_width / 2); (x < player.x + screen_width / 2) && (x < level_width); ++x) { i = (int) level [y * level_width + x]; screen_put (tiles [i].style, tiles [i].colour, tiles [i].symbol, screen_width / 2 + x - player.x, screen_height / 2 + y - player.y); } } screen_put (bold, cyan, '@', screen_width / 2, screen_height / 2); //~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; for (i = 0; i < members; ++i) { screen_print (bold, blue, class_name [(int) player.class [i]], screen_width - screen_side, i * (2 + 1 + attributes + 1) + 0, screen_side); screen_print (bold, white, skill_name [(int) player.skill [i]], screen_width - screen_side, i * (2 + 1 + attributes + 1) + 1, screen_side); //~for (j = 0; j < points; ++j) { //~int length = strlen (point_name [player.point [i]]); //~screen_print (bold, white, point_name [j], screen_width - screen_side, i * (2 + 1 + attributes + 1) + 2 + j, screen_side); //~screen_print (bold, white, player.point [i], screen_width - screen_side, i * (2 + 1 + attributes) + 2 + j, screen_side); //~} //~for (j = 0; j < attributes; ++j) { //~screen_print (bold, white, attribute_name [j], screen_width - 24, i * (2 + 1 + attributes + 1) + 2 + 1 + j, screen_side); //~} screen_print (bold, white, "--------------------------------", screen_width - screen_side, i * (2 + 1 + attributes + 1) + 2 + 1 + attributes, screen_side); } synchronize_screen (); } free (level); deinitialize_screen (); return (0); }