jrpg/w/w.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;
}