You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
4.5 KiB

// http://www.locklessinc.com/articles/512byte_roguelike/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <curses.h>
#define SIZEX 128
#define SIZEY 64
static char map[SIZEY][SIZEX];
#define MMAX 50
static int mx[MMAX];
static int my[MMAX];
static char mc[MMAX];
static int mhp[MMAX];
#define FLOOR '.'
#define PLAYER '@'
#define MONSTER 'm'
// Within these regions, draw this char
static void draw_region(int x1, int x2, int y1, int y2, char c)
{
int x, y;
for (y = y1; y < y2; y++)
{
for (x = x1; x < x2; x++)
{
map[y][x] = c;
}
}
}
// Get a random number within the bounds of v
static int rr(int v1, int v2, int r)
{
return (r % (v1 - v2)) + v1;
}
// Add character within X/Y (within limit MMAX characters in total)
static void addm(int x, int y, int hp, char c)
{
int i;
for (i = 0; i < MMAX; i++)
{
// If no character exists
if (!mc[i])
{
mx[i] = x;
my[i] = y;
mhp[i] = hp;
mc[i] = c;
return;
}
}
}
// Get the character ID at X/Y coord; -1 if none
static int getm(int x, int y)
{
int i;
for (i = 0; i < MMAX; i++)
{
// If character exists at coordinates, return which one
if ((mx[i] == x) && (my[i] == y)) return i;
}
return -1;
}
// Place character at random X/Y coord if nothing is there
static void rand_place(char c, int hp)
{
do
{
// Get a random coordinate within the bounds
int x = rand() & (SIZEX - 1);
int y = rand() & (SIZEY - 1);
if (map[y][x] == FLOOR)
{
map[y][x] = c;
addm(x, y, hp, c);
return;
}
}
while(1);
}
static void init_map(void)
{
int i, x1, x2, y1, y2;
// initialize the whole map with # (walls)
draw_region(0, SIZEX - 1, 0, SIZEY, '#');
for (i = 0; i < 200; i++)
{
// Get a random number between 0 and RAND_MAX
int r = rand();
// Set coordinates as a random number within the bounds
x1 = rr(1, SIZEX - 20,r);
x2 = rr(x1 + 5, x1 + 19,r);
y1 = rr(1, SIZEY - 8,r);
y2 = rr(y1 + 3, y1 + 7,r);
// draw floor at these coordinates
draw_region(x1, x2, y1, y2, FLOOR);
}
// Place the main character (@) somewhere on the map with 5 hp
rand_place(PLAYER, 5);
// Place ten enemies on the map
for (i = 0; i < 10; i++)
{
rand_place(MONSTER, 2);
}
}
// Draw each row of the map on to the screen
static void draw_screen(void)
{
int y;
clear();
/* Dump map */
for (y = 0; y < SIZEY; y++)
{
mvaddstr(y, 0, map[y]);
}
}
// Return position adjustment based on position of player and monster
static int sgn(int x)
{
return (x > 0) - (x < 0);
}
int main(void)
{
int c; // declare user input
int i = 0; //
srand(time(0)); // use current time as seed
init_map(); //
initscr(); // initialize curses
cbreak(); // allow user input to be used immediately https://linux.die.net/man/3/cbreak
while (1) // main game loop
{
int nx = mx[i], ny = my[i]; // character (player or monster) position
if (!i) // if it is the user's turn
{
draw_screen(); // draw the screen
c = 0; // Initialize input char
while (!(c=getch())); // wait for user input
// move character based on input
if ((c == '1') || (c == '4') || (c == '7')) nx -= 1;
if ((c == '3') || (c == '6') || (c == '9')) nx += 1;
if ((c == '7') || (c == '8') || (c == '9')) ny -= 1;
if ((c == '1') || (c == '2') || (c == '3')) ny += 1;
// if an enemy is at the current coordinate
if (map[ny][nx] == MONSTER)
{
// figure out which one it is
int j = getm(nx, ny);
// take away one hp from that monster
mhp[j]--;
// if at zero
if (!mhp[j])
{
// set the character at the map to be ground
map[ny][nx] = FLOOR;
// remove the monster from the map
mc[j] = 0;
}
}
}
// If a monster's turn
if (mc[i] == MONSTER)
{
// Move the monster one space closer to the player if possible
nx += sgn(mx[0]-nx);
ny += sgn(my[0]-ny);
// If the space they are moving to is the player
if (map[ny][nx] == PLAYER)
{
// Take one hp from the player
mhp[0]--;
// If the player takes 5 hits
if (!mhp[0])
{
// end game and quit
endwin();
exit(0);
}
}
}
// If character exists and there is nothing in the moved-to space
if (mc[i] && (map[ny][nx] == FLOOR))
{
// Set old position to ground (.)
map[my[i]][mx[i]] = FLOOR;
// Set new position
mx[i] = nx;
my[i] = ny;
// Set new map character
map[ny][nx] = mc[i];
}
// Iterate to next character
i++;
// If at max characters, start over for new turn at player
if (i == MMAX) i = 0;
}
return(0);
}