653 lines
11 KiB
C
653 lines
11 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
#define CMD_LEN 10
|
|
#define NAME_LEN 10
|
|
#define POV_3D_SIZE 10
|
|
#define POV_SIZE 3
|
|
|
|
#define CMD_NULL "-"
|
|
#define CMD_FWD 's'
|
|
#define CMD_ATTACK 'a'
|
|
#define CMD_FLEE 'f'
|
|
|
|
#define SC_TITLE 0
|
|
#define SC_SETNAME 1
|
|
#define SC_STATION 2
|
|
#define SC_MAP 3
|
|
#define SC_MONSTER 4
|
|
#define SC_GAMEOVER 5
|
|
|
|
#define NORTH 0
|
|
#define EAST 1
|
|
#define WEST 2
|
|
#define SOUTH 3
|
|
|
|
#define TILE_WALL 'w'
|
|
#define TILE_FREE ' '
|
|
#define TILE_DOOR 'd'
|
|
#define TILE_START 's'
|
|
|
|
typedef struct {
|
|
int x;
|
|
int y;
|
|
char orientation;
|
|
} Position;
|
|
|
|
typedef struct {
|
|
char name[NAME_LEN];
|
|
int hp;
|
|
int gold;
|
|
int atk;
|
|
int def;
|
|
} Character;
|
|
|
|
typedef struct {
|
|
Character hero;
|
|
Character monster;
|
|
Position position;
|
|
char screen;
|
|
} Gamestate;
|
|
|
|
const char* statepath = "w.state";
|
|
char pov[POV_SIZE][POV_SIZE];
|
|
unsigned char pov3d[POV_3D_SIZE][POV_3D_SIZE];
|
|
Gamestate state;
|
|
|
|
int mapsize = 15;
|
|
char map[15][15] = {
|
|
"wwwwwwwwwwwwwww",
|
|
"w w",
|
|
"w wwwww wwwww w",
|
|
"w w w d w w w",
|
|
"w w w w w w w",
|
|
"w w w w w w",
|
|
"wdwwwwwdw w",
|
|
"w w w wwwwwdw",
|
|
"w www w w",
|
|
"ws w w w",
|
|
"wwwwwww w w",
|
|
"w w w",
|
|
"w w w",
|
|
"w d w",
|
|
"wwwwwwwwwwwwwww"
|
|
};
|
|
|
|
Character monsters[1] = {
|
|
{ "Alien", 1, 2, 1, 1 }
|
|
};
|
|
|
|
int dice()
|
|
{
|
|
return 1 + (rand() % 6);
|
|
}
|
|
|
|
char charatpos(int x, int y)
|
|
{
|
|
if (x < 0 || y < 0 || x >= mapsize || y >= mapsize)
|
|
{
|
|
return ' ';
|
|
}
|
|
return map[y][x];
|
|
}
|
|
|
|
void drawmap()
|
|
{
|
|
for (int y = 0; y < mapsize; y++) {
|
|
for (int x = 0; x < mapsize; x++) {
|
|
char toprint = charatpos(x,y);
|
|
if (y == state.position.y && x == state.position.x)
|
|
{
|
|
if (state.position.orientation == NORTH) toprint = '^';
|
|
if (state.position.orientation == SOUTH) toprint = 'v';
|
|
if (state.position.orientation == EAST) toprint = '>';
|
|
if (state.position.orientation == WEST) toprint = '<';
|
|
}
|
|
printf("%c", toprint);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
void savestate()
|
|
{
|
|
FILE* file = fopen(statepath, "w");
|
|
fwrite(&state, sizeof(Gamestate), 1, file);
|
|
fclose(file);
|
|
}
|
|
|
|
char currentchar()
|
|
{
|
|
return charatpos(state.position.x, state.position.y);
|
|
}
|
|
|
|
void update3dpov()
|
|
{
|
|
for (int i = 0; i < POV_3D_SIZE; i++)
|
|
{
|
|
memset(pov3d[i], ' ', POV_3D_SIZE);
|
|
}
|
|
|
|
// front constants
|
|
for (int i = 2; i < 8; i++)
|
|
{
|
|
pov3d[1][i] = '_';
|
|
pov3d[7][i] = '_';
|
|
}
|
|
|
|
if (pov[2][0] == TILE_FREE)
|
|
{
|
|
// front left free
|
|
pov3d[1][0] = '_';
|
|
pov3d[1][1] = '_';
|
|
pov3d[7][0] = '_';
|
|
pov3d[7][1] = '_';
|
|
}
|
|
else
|
|
{
|
|
// front left wall
|
|
pov3d[0][0] = '\\';
|
|
pov3d[1][1] = '\\';
|
|
pov3d[8][1] = '/';
|
|
pov3d[9][0] = '/';
|
|
for (int i = 2; i < 8; i++) pov3d[i][1] = '|';
|
|
}
|
|
|
|
if (pov[2][2] == TILE_FREE)
|
|
{
|
|
// front right free
|
|
pov3d[1][8] = '_';
|
|
pov3d[1][9] = '_';
|
|
pov3d[7][8] = '_';
|
|
pov3d[7][9] = '_';
|
|
}
|
|
else
|
|
{
|
|
// front right wall
|
|
pov3d[8][8] = '\\';
|
|
pov3d[9][9] = '\\';
|
|
pov3d[0][9] = '/';
|
|
pov3d[1][8] = '/';
|
|
for (int i = 2; i < 8; i++) pov3d[i][7+1] = '|';
|
|
}
|
|
|
|
if (pov[1][1] == TILE_FREE)
|
|
{
|
|
// far constants
|
|
pov3d[3][4] = '_';
|
|
pov3d[3][5] = '_';
|
|
pov3d[5][4] = '_';
|
|
pov3d[5][5] = '_';
|
|
|
|
if (pov[0][0] == TILE_FREE)
|
|
{
|
|
// far left free
|
|
pov3d[3][2] = '_';
|
|
pov3d[3][3] = '_';
|
|
pov3d[5][2] = '_';
|
|
pov3d[5][3] = '_';
|
|
|
|
// if front is free as well
|
|
if (pov[2][0] == TILE_FREE)
|
|
{
|
|
pov3d[3][0] = '_';
|
|
pov3d[3][1] = '_';
|
|
pov3d[5][0] = '_';
|
|
pov3d[5][1] = '_';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// far left wall
|
|
pov3d[2][2] = '\\';
|
|
pov3d[3][3] = '\\';
|
|
pov3d[7][2] = '/';
|
|
pov3d[6][3] = '/';
|
|
pov3d[4][3] = '|';
|
|
pov3d[5][3] = '|';
|
|
|
|
// ensure front view is complete
|
|
for (int i = 2; i < 8; i++) pov3d[i][1] = '|';
|
|
}
|
|
|
|
if (pov[0][2] == TILE_FREE)
|
|
{
|
|
// far right free
|
|
pov3d[3][6] = '_';
|
|
pov3d[3][7] = '_';
|
|
pov3d[5][6] = '_';
|
|
pov3d[5][7] = '_';
|
|
|
|
// if front is free as well
|
|
if (pov[2][2] == TILE_FREE)
|
|
{
|
|
pov3d[3][8] = '_';
|
|
pov3d[3][9] = '_';
|
|
pov3d[5][8] = '_';
|
|
pov3d[5][9] = '_';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// far right wall
|
|
pov3d[6][6] = '\\';
|
|
pov3d[7][7] = '\\';
|
|
pov3d[2][7] = '/';
|
|
pov3d[3][6] = '/';
|
|
pov3d[4][5+1] = '|';
|
|
pov3d[5][5+1] = '|';
|
|
|
|
// ensure front view is complete
|
|
for (int i = 2; i < 8; i++) pov3d[i][7+1] = '|';
|
|
}
|
|
}
|
|
|
|
const char doorchar = '#';
|
|
if (pov[1][1] == TILE_DOOR)
|
|
{
|
|
// front door
|
|
for (int i = 4; i <= 7; i++)
|
|
{
|
|
for (int j = 3; j < 7; j++)
|
|
pov3d[i][j] = doorchar;
|
|
}
|
|
}
|
|
if (pov[2][0] == TILE_DOOR)
|
|
{
|
|
for (int i = 5; i < 9; i++) pov3d[i][0] = doorchar;
|
|
}
|
|
if (pov[2][2] == TILE_DOOR)
|
|
{
|
|
for (int i = 5; i < 9; i++) pov3d[i][9] = doorchar;
|
|
}
|
|
|
|
if (currentchar() == TILE_START)
|
|
{
|
|
pov3d[0][4] = '[';
|
|
pov3d[0][5] = ']';
|
|
}
|
|
}
|
|
|
|
void updatepov()
|
|
{
|
|
int x = state.position.x;
|
|
int y = state.position.y;
|
|
char orientation = state.position.orientation;
|
|
|
|
for (int frontoffset = 2; frontoffset >= 0; frontoffset--)
|
|
{
|
|
for (int rtoloffset = -1; rtoloffset < 2; rtoloffset++)
|
|
{
|
|
int newX = x, newY = y;
|
|
switch (orientation)
|
|
{
|
|
case NORTH:
|
|
newX += rtoloffset;
|
|
newY -= frontoffset;
|
|
break;
|
|
case SOUTH:
|
|
newX -= rtoloffset;
|
|
newY += frontoffset;
|
|
break;
|
|
case EAST:
|
|
newX += frontoffset;
|
|
newY += rtoloffset;
|
|
break;
|
|
case WEST:
|
|
newX -= frontoffset;
|
|
newY -= rtoloffset;
|
|
break;
|
|
}
|
|
pov[2 - frontoffset][1 + rtoloffset] = charatpos(newX, newY);
|
|
}
|
|
}
|
|
}
|
|
|
|
void forward()
|
|
{
|
|
if (pov[1][1] != TILE_WALL)
|
|
{
|
|
switch (state.position.orientation)
|
|
{
|
|
case NORTH:
|
|
state.position.y -= 2;
|
|
break;
|
|
case SOUTH:
|
|
state.position.y += 2;
|
|
break;
|
|
case EAST:
|
|
state.position.x += 2;
|
|
break;
|
|
case WEST:
|
|
state.position.x -= 2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void right()
|
|
{
|
|
switch (state.position.orientation)
|
|
{
|
|
case NORTH:
|
|
state.position.orientation = EAST;
|
|
break;
|
|
case SOUTH:
|
|
state.position.orientation = WEST;
|
|
break;
|
|
case EAST:
|
|
state.position.orientation = SOUTH;
|
|
break;
|
|
case WEST:
|
|
state.position.orientation = NORTH;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void left()
|
|
{
|
|
switch (state.position.orientation)
|
|
{
|
|
case NORTH:
|
|
state.position.orientation = WEST;
|
|
break;
|
|
case SOUTH:
|
|
state.position.orientation = EAST;
|
|
break;
|
|
case EAST:
|
|
state.position.orientation = NORTH;
|
|
break;
|
|
case WEST:
|
|
state.position.orientation = SOUTH;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void dumpstate()
|
|
{
|
|
printf("Name:%s\nx:%d\ny:%d\norientation:%c\n",
|
|
state.hero.name,
|
|
state.position.x,
|
|
state.position.y,
|
|
state.position.orientation);
|
|
}
|
|
|
|
void clearscreen()
|
|
{
|
|
#ifdef _WIN32
|
|
system("cls");
|
|
#else
|
|
system("clear");
|
|
#endif
|
|
}
|
|
|
|
void init()
|
|
{
|
|
srand(time(NULL));
|
|
FILE* file = fopen(statepath, "r");
|
|
if (file)
|
|
{
|
|
fread(&state, sizeof(Gamestate), 1, file);
|
|
fclose(file);
|
|
}
|
|
else
|
|
{
|
|
state.screen = SC_TITLE;
|
|
}
|
|
}
|
|
|
|
void update(char command[CMD_LEN])
|
|
{
|
|
char c = command[0];
|
|
if (state.screen == SC_MAP)
|
|
{
|
|
switch (c)
|
|
{
|
|
case CMD_FWD:
|
|
case '\0':
|
|
forward();
|
|
if (dice() == 1)
|
|
{
|
|
memcpy(&state.monster, &(monsters[0]), sizeof(Character));
|
|
state.screen = SC_MONSTER;
|
|
}
|
|
break;
|
|
case 'x':
|
|
right();
|
|
break;
|
|
case 'w':
|
|
left();
|
|
break;
|
|
case 'r':
|
|
if (currentchar() == TILE_START)
|
|
{
|
|
state.screen = SC_STATION;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
updatepov();
|
|
}
|
|
else if (state.screen == SC_TITLE)
|
|
{
|
|
if (strcmp(command, CMD_NULL) != 0)
|
|
{
|
|
state.screen = SC_SETNAME;
|
|
}
|
|
}
|
|
else if (state.screen == SC_SETNAME)
|
|
{
|
|
if (strlen(command) > 0)
|
|
{
|
|
strcpy(state.hero.name, command);
|
|
state.hero.hp = 10;
|
|
state.hero.gold = 0;
|
|
state.hero.atk = 1;
|
|
state.hero.def = 1;
|
|
state.screen = SC_STATION;
|
|
}
|
|
}
|
|
else if (state.screen == SC_STATION)
|
|
{
|
|
if (c == 'n')
|
|
{
|
|
state.screen = SC_MAP;
|
|
state.position.x = 1;
|
|
state.position.y = 5;
|
|
state.position.orientation = NORTH;
|
|
updatepov();
|
|
}
|
|
}
|
|
else if (state.screen == SC_MONSTER)
|
|
{
|
|
if (c == CMD_FLEE)
|
|
{
|
|
state.screen = SC_MAP;
|
|
}
|
|
else if (c == CMD_ATTACK)
|
|
{
|
|
// hero then monster turn.
|
|
// possible outcomes: hero dead, monster dead, or still fight
|
|
|
|
// hero attacks
|
|
state.monster.hp--;
|
|
|
|
if (state.monster.hp <= 0)
|
|
{
|
|
state.hero.gold += state.monster.gold;
|
|
state.screen = SC_MAP;
|
|
}
|
|
else
|
|
{
|
|
// monster attacks
|
|
state.hero.hp--;
|
|
if (state.hero.hp <= 0)
|
|
{
|
|
state.screen = SC_GAMEOVER;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void debugoutput()
|
|
{
|
|
//drawmap();
|
|
}
|
|
|
|
void draw()
|
|
{
|
|
clearscreen();
|
|
|
|
int screenwidth = 30;
|
|
for (int i = 0; i < screenwidth; i++) printf("-");
|
|
printf("\n");
|
|
|
|
if (state.screen == SC_TITLE)
|
|
{
|
|
printf(" _ _\n");
|
|
printf(" / / / /\n");
|
|
printf(" / / / /\n");
|
|
printf(" / /__a / /__égende\n");
|
|
printf(" |____/ |____/\n");
|
|
printf("\n");
|
|
printf(" du ___\n");
|
|
printf(" / _ \\ \n");
|
|
printf(" / / | |\n");
|
|
printf(" / /_/ /ongeon\n");
|
|
printf(" /____ /\n");
|
|
printf("\n");
|
|
printf(" _____\n");
|
|
printf(" de l' / ___/\n");
|
|
printf(" / /_\n");
|
|
printf(" / /___space\n");
|
|
printf(" /_____/\n");
|
|
}
|
|
else if (state.screen == SC_SETNAME)
|
|
{
|
|
printf("Bonjour.\n\n");
|
|
printf("Bienvenue à la station\n");
|
|
printf("spaciale intergalactique.\n\n");
|
|
printf("Veuillez saisir votre nom.\n");
|
|
}
|
|
else if (state.screen == SC_MAP)
|
|
{
|
|
update3dpov();
|
|
int shift = 9;
|
|
for (int i = 0; i < shift; i++) printf(" ");
|
|
printf("o----------o\n");
|
|
|
|
for (int i = 0; i < POV_3D_SIZE; i++)
|
|
{
|
|
for (int s = 0; s < shift; s++) printf(" ");
|
|
printf("|");
|
|
for (int j = 0; j < POV_3D_SIZE; j++)
|
|
{
|
|
printf("%c", pov3d[i][j]);
|
|
}
|
|
printf("|\n");
|
|
}
|
|
for (int i = 0; i < shift; i++) printf(" ");
|
|
printf("o----------o");
|
|
|
|
if (charatpos(state.position.x, state.position.y) == TILE_START)
|
|
{
|
|
printf("\n\nr: Retour à la station\n");
|
|
}
|
|
else
|
|
{
|
|
printf("\n ^\n");
|
|
printf(" <w s x>\n");
|
|
}
|
|
//drawmap();
|
|
}
|
|
else if (state.screen == SC_STATION)
|
|
{
|
|
printf("\n");
|
|
printf(" STATION SPACIALE\n");
|
|
printf(" INTERGALACTIQUE\n");
|
|
printf("\n");
|
|
|
|
printf("n: Prendre la navette\n");
|
|
}
|
|
else if (state.screen == SC_MONSTER)
|
|
{
|
|
printf("Rencontre avec un %s\n", state.monster.name);
|
|
printf("f: Tenter de fuir\n");
|
|
printf("a: Attaquer\n");
|
|
}
|
|
else if (state.screen == SC_GAMEOVER)
|
|
{
|
|
printf("%s est fatiguée\n");
|
|
state.hero.hp = 10;
|
|
state.screen = SC_STATION;
|
|
}
|
|
|
|
if (state.screen == SC_MONSTER
|
|
|| state.screen == SC_STATION
|
|
|| state.screen == SC_MAP)
|
|
{
|
|
printf("\n");
|
|
for (int i = 0; i < screenwidth; i++) printf("-");
|
|
printf("\n");
|
|
printf("%s | P.V. : %d | C.G. : %d", state.hero.name, state.hero.hp, state.hero.gold);
|
|
|
|
}
|
|
|
|
debugoutput();
|
|
|
|
printf("\n");
|
|
for (int i = 0; i < screenwidth; i++) printf("-");
|
|
printf("\n> ");
|
|
|
|
}
|
|
|
|
void drawtopdownpov()
|
|
{
|
|
for (int y = 0; y < POV_SIZE; y++)
|
|
{
|
|
for (int x = 0; x < POV_SIZE; x++)
|
|
{
|
|
if (y == 0 && pov[1][1] != ' ')
|
|
{
|
|
printf(" ");
|
|
}
|
|
else if (y == 2 && x == 1)
|
|
{
|
|
printf("^");
|
|
}
|
|
else
|
|
{
|
|
printf("%c", pov[y][x]);
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
void getcommand(char* command)
|
|
{
|
|
fgets(command, sizeof(char) * CMD_LEN, stdin);
|
|
command[strcspn(command, "\n")] = 0;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
init();
|
|
|
|
char command[CMD_LEN] = CMD_NULL;
|
|
|
|
while (command[0] != 'q')
|
|
{
|
|
update(command);
|
|
draw();
|
|
getcommand(command);
|
|
}
|
|
savestate();
|
|
return 0;
|
|
}
|