この記事を書いた動機
ただ単にせっかく書いたコードを、無下にしてしまうのは勿体ないなと思い、非効率でバグだらけのスパゲッティコードではあるが、まあおいておこうかなと思っただけです。(かつコメントの英語もガバだらけ。。。)
ちなみに、授業の制約上、一つのファイルにまとめざるを得ず、プログラムを分割できなかったのでえげつなく肥大化しています。。。
使っているライブラリ
- C標準ライブラリ
- curses
プレイ動画
各画面の説明
スタート画面

終わりの画面

風のすてーじ

雨のすてーじ

晴れの日すてーじ

コンパイル
makefile
build:
gcc main.c -lcurses -lm -o main
bash 上の操作
make build
./main # 実行
コード本体
main.c
#include <curses.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#define START_BUTTON 0
#define END_BUTTON 1
#define RETURN_BUTTON 2
#define CURSOR "===================="
#define CORSOR_REMOVE " "
// define const values for each stage
#define RAIN_STAGE 0
#define WIND_STAGE 1
#define SUNNY_STAGE 2
// rain stage setting
#define RAIN_SIZE_X 2 // set size of a rain
#define RAIN_SIZE_Y 2 // set size of a rain
#define RAIN_Y_SPACE 10 // avoid rain creation if there are created rain near the new rain
#define RAIN_X_SPACE 3 // avoid rain creation if there are created rain near the new rain
#define NUMEBR_OF_RAIN 5 // number of newly created rain in 1 sec
#define SPEED_OF_RAIN 30 // in a sec
#define DAMAGE_OF_RAIN 10 // amount of damage when player hit a rain
#define NUMBER_OF_RETRY 20 // define how many times to recreate random nums
#define RAIN_STAGE_POSSIBLE 30 // possibily of rain stage to be selected
#define RAIN_STAGE_TIME_LIMIT 20
#define AMOUNT_OF_RAIN 28 // limit amount of rain
// wind stage setting
#define DAMAGE_OF_OBJ 20 // amount of damage when player hit a obj in this stage
#define NUMEBR_OF_BLOWN_AWAY_OBJ 5 // number of obj to be created in a sec
#define SPEED_OF_WIND_X 1 // numberOfFrame % this const value -> 100f in a sec
#define MOVEMENT_OF_OBJ_X 5 // amount of movement in one position update
#define SPEED_OF_WIND_Y 20 // amount of movement in a sec
#define AMOUNT_OF_OBJ 28 // limit amount of obj
#define WIND_STAGE_POSSIBLE 30 // possibily of wind stage to be selected
#define WIND_STAGE_TIME_LIMIT 20
// sunny stage setting
#define AMOUNT_OF_RACOVER 10 // amount of hp recover when player hit point obj
#define NUMEBR_OF_POINT 20 // amount of point obj to be cteated in a sec
#define AMOUNT_OF_POINT 10 // limit amount of point obj
#define SPEED_OF_POINT_X 40 // amount of movement in a sec
#define SPEED_OF_POINT_Y 40 // amount of movement in a sec
#define SUNNY_STAGE_POSSOIBLE 40 // possibily of sunny stage to be selected
#define SUNNY_STAGE_TIME_LIMIT 10
// main game setting
#define NUMBER_OF_FRAME 100 // amount of frame in a sec
#define DEFAULT_PLAYER_HP 100
#define DEFAULT_GAME_TIME 20 // sec
#define PLAYER_SPEED 2 // movement of player in a sec
#define PLAYER_JUMP_MAX 20 // height of player jump when there are space enough
#define PLAYER_JUMP_TIME 1 // define time length of player jump
#define PLAYER_SCORE 40 // one time, If player avoid obj
#define DAMAGE_INTARVAL 1 // define damage interval when player hit a obj
// player
#define IN_DAMAGE_INTARVAL 1
#define OUT_DAMAGE_INTARVAL 0
#define NUMBER_OF_GAME 3
//game system value
#define ALLOCATION_OK 0 // ram allocation alart
#define ALLOCATION_NOT_OK 1 // ram allocation alart
#define RESIZE_NOT_HAPPEND 0 // window resize alart
#define RESIZE_HAPPEND 1 // window resize alart
// show debug log when DEBUG is defined
// #define DEBUG
typedef struct VECTOR
{
int x,y;
}Vector;
// float version of vector
typedef struct VECTOR_F
{
float x,y;
}VectorF;
typedef struct GRAPHIC
{
// hold position of top and left corner
Vector position,PreviousPosition;
Vector size;
// [y][x]
char **data;
}Graphic;
typedef struct PLAYER
{
int hp,score,currentStageScore;
// enter defined value
int damageIntarval;
// enter number of frame since start interval
int datageIntarvalFrame;
Vector CurrentPosition,PreviousPosition;
VectorF speed;
// count number of played stage
int counterOfGame;
Graphic body;
}Player;
typedef struct STAGE
{
// hold possiblity of stage to be selected
int possible;
// hold time limit of each stages
int timeLimit;
char name[20];
// hold how long player play the stage
double timer;
// hold obj will be shown in stage
int numberOfPreparedObj;
Graphic *PreparedObj;
int numberOfObj;
Graphic *obj;
// stage function. This function will not contain game loop.
// This function will call random stage chooser or end screen
// void (*stageFunc)(Player *player,Stage *stages);
void (*stageFunc)(Player *player,struct STAGE*,int numberOfFrame);
}Stage;
// This value will be used globaly to run this game
int width,height;
char logs[256];
void setStageParam(Stage *stages);
void showPlayer(Player player);
void initPlayer(Player *player);
int jumpPlayer(Player *player,int numberOfFrame);
Vector clacBodyPosition(Vector position, Vector bodySize);
int resizeDetect(){
int w,h;
getmaxyx(stdscr,h,w);
int status = RESIZE_NOT_HAPPEND;
if(h != height || w != width){
status = RESIZE_HAPPEND;
width = w; height = h;
clear();
}
return status;
}
int adjustTimer(double timer){
double length = ((double)1 / NUMBER_OF_FRAME);
if(timer < length){
return (int)((length - timer) * 1000000);
}else{
return 0;
}
}
double clacTimeFromClock_t(clock_t time){
return (double) time / CLOCKS_PER_SEC;
}
void debugLog(int y,int x,char *text){
#ifdef DEBUG
char newlogs[240];
sprintf(newlogs,"debug log: %s",text);
mvaddstr(y,x,newlogs);
refresh();
#endif
}
// This function can be used any Graphic obj
int allocateGraphicRam(Graphic *target){
target -> data = (char **)malloc(sizeof(char *) * target -> size.y);
if(target -> data == NULL) return ALLOCATION_NOT_OK;
for(int y = 0; y < target -> size.y; y++){
target -> data[y] = (char *)malloc(sizeof(char) * target -> size.x);
if(target -> data[y] == NULL) return ALLOCATION_NOT_OK;
}
return ALLOCATION_OK;
}
// This function can be used any Graphic obj
void freeGraphicRam(Graphic *target){
for(int y = 0; y < target -> size.y; y++){
free(target -> data[y]);
}
free(target -> data);
}
void freeObjGraphicRam(Graphic *target,int numberOfObj){
for(int i = 0; i < numberOfObj; i++){
freeGraphicRam(&(target[i]));
}
}
// This function should be executed once when start this game
void initWholeGame(){
srand((unsigned)time(NULL));
initscr(); curs_set(0); noecho();
getmaxyx(stdscr,height,width);
}
// This function should be executed onec when end this game
void endWholeGame(Player *player,Stage *stages){
endwin();
// free pointers here
// 3 stages may contain pointers which are need to be freed.
for(int i = 0; i < 3;i++){
// freeObjGraphicRam(stages[i].obj,stages[i].numberOfObj);
freeObjGraphicRam(stages[i].PreparedObj,stages[i].numberOfPreparedObj);
// free(stages[i].obj);
free(stages[i].PreparedObj);
}
// player body may contain pointers which need to be freed.
free(player -> body.data);
}
void movePlayerRandomly(Player *player,int numberOfFrame){
// getmaxyx(stdscr,height,width);
resizeDetect();
player -> PreviousPosition = player->CurrentPosition;
if(player -> CurrentPosition.y > 0 && player->speed.y != 0) player -> CurrentPosition.y = jumpPlayer(player,numberOfFrame);
sprintf(logs,"player speed.y: %lf",player->speed.y);
debugLog(6,3,logs);
sprintf(logs,"player current position.y: %d",player -> CurrentPosition.y);
debugLog(7,3,logs);
if(numberOfFrame % (100 / PLAYER_SPEED) == 0){
// make random position
// 0 -> negative
// 1 -> 0
// 2 -> positive
Vector direction = {.x=rand() % 3,.y=rand() % 3};
sprintf(logs,"direction x: %d y: %d",direction.x,direction.y);
debugLog(4,3,logs);
refresh();
// update position
if(direction.x == 0 && player -> CurrentPosition.x > 0) player -> CurrentPosition.x -= 1;
if(direction.y == 0 && player -> CurrentPosition.y > 0 && !(player->speed.y != 0)) player -> CurrentPosition.y = jumpPlayer(player,numberOfFrame);
if(direction.x == 2 && player -> CurrentPosition.x < width) player -> CurrentPosition.x += 1;
// if(direction.y == 2 && player -> CurrentPosition.y < height) player -> CurrentPosition.y += 1;
// debug
sprintf(logs,"x: %d y: %d",player -> CurrentPosition.x,player -> CurrentPosition.y);
debugLog(5,3,logs);
}
// update player graphic position
player -> body.position = clacBodyPosition(player->CurrentPosition,player->body.size);
}
// Start UI -------------------------------------------------------
int startUI(){
int keys = 0;
// init these vars -> OK
Vector titlePosition,startButtonPosition,endButtonPosition;
Player player;
initPlayer(&player);
// set defalt option
int selectedButton = START_BUTTON;
clear();
getmaxyx(stdscr,height,width);
// set position retative to screen size
titlePosition.y = (height / 2) - 5;
startButtonPosition.y = (height / 2) + 1;
endButtonPosition.y = (height / 2 ) + 4;
titlePosition.x = (width / 2) - 5;
startButtonPosition.x = (width / 2) - 5;
endButtonPosition.x = (width / 2 ) - 5;
// show cursor with first defualt option
if(selectedButton == START_BUTTON){
mvaddstr(startButtonPosition.y + 1,startButtonPosition.x,CURSOR);
}else{
mvaddstr(endButtonPosition.y + 1,endButtonPosition.x,CURSOR);
}
// show title and start,end button
mvaddstr(titlePosition.y,titlePosition.x,"Climate survivor");
mvaddstr(startButtonPosition.y,startButtonPosition.x,"start game");
mvaddstr(endButtonPosition.y,endButtonPosition.x,"end game");
refresh();
int numberOfFrame = 0;
clock_t start = 0, delta = 0;
double deltaf = 0;
while(1){
start = clock();
// recaculation of position when resize window
if(resizeDetect() == RESIZE_HAPPEND){
titlePosition.y = (height / 2) - 5;
startButtonPosition.y = (height / 2) + 1;
endButtonPosition.y = (height / 2 ) + 4;
titlePosition.x = (width / 2) - 5;
startButtonPosition.x = (width / 2) - 5;
endButtonPosition.x = (width / 2 ) - 5;
}
timeout(0);
keys = getch();
movePlayerRandomly(&player,numberOfFrame);
showPlayer(player);
sprintf(logs,"conuter is %d",numberOfFrame);
debugLog(3,3,logs);
numberOfFrame++;
// when w or s key is pressed
if(keys == 'w' || keys == 's'){
if(selectedButton == START_BUTTON){
selectedButton = END_BUTTON;
}else{
selectedButton = START_BUTTON;
}
}else if(keys == '\n'){
break;
}
// show title and start,end button
mvaddstr(titlePosition.y,titlePosition.x,"Climate survivor");
mvaddstr(startButtonPosition.y,startButtonPosition.x,"start game");
mvaddstr(endButtonPosition.y,endButtonPosition.x,"end game");
// update cursor
if(selectedButton == START_BUTTON){
mvaddstr(endButtonPosition.y + 1,endButtonPosition.x,CORSOR_REMOVE);
mvaddstr(startButtonPosition.y + 1,startButtonPosition.x,CURSOR);
}else{
mvaddstr(startButtonPosition.y + 1,startButtonPosition.x,CORSOR_REMOVE);
mvaddstr(endButtonPosition.y + 1,endButtonPosition.x,CURSOR);
}
refresh();
delta = clock() - start;
deltaf = clacTimeFromClock_t(delta);
usleep(adjustTimer(deltaf));
}
// free ram which allocated in initPlayer function
free(player.body.data);
// for next
return selectedButton;
}
// Start UI -------------------------------------------------------
// end UI -----------------------------------------------------------
int endUI(Player *player){
int keys;
// init position -> ok
Vector scorePosition,endButtonPosition,returnButtonPosition;
Player backgoundPlayer;
initPlayer(&backgoundPlayer);
// set defualt option
int selectedButton = END_BUTTON;
clear();
getmaxyx(stdscr,height,width);
// init position
scorePosition.y = (height / 2) - 5;
returnButtonPosition.y = (height / 2) + 1;
endButtonPosition.y = (height / 2) + 4;
scorePosition.x = (width / 2) + 10;
endButtonPosition.x = (width / 2) + 10;
returnButtonPosition.x = (width / 2) + 10;
// show end or return button
// show score
char scoreText[30];
sprintf(scoreText,"Score is: %d",player -> score);
mvaddstr(scorePosition.y,scorePosition.x,scoreText);
// TODO: fix worngly inverted button
mvaddstr(returnButtonPosition.y,returnButtonPosition.x,"end game");
mvaddstr(endButtonPosition.y,endButtonPosition.x,"return start screen");
// show cursor
if(selectedButton == END_BUTTON){
mvaddstr(endButtonPosition.y + 1,endButtonPosition.x,CURSOR);
}else if(selectedButton == RETURN_BUTTON){
mvaddstr(returnButtonPosition.y + 1,returnButtonPosition.x,CURSOR);
}
refresh();
int count = 0;
clock_t start = 0, delta = 0;
double deltaf = 0;
while(1){
start = clock();
// recaculation of position when resize window is happened
if(resizeDetect() == RESIZE_HAPPEND){
scorePosition.y = (height / 2) - 5;
returnButtonPosition.y = (height / 2) + 1;
endButtonPosition.y = (height / 2) + 4;
scorePosition.x = (width / 2) + 10;
endButtonPosition.x = (width / 2) + 10;
returnButtonPosition.x = (width / 2) + 10;
}
timeout(0);
keys = getch();
count++;
movePlayerRandomly(&backgoundPlayer,count);
showPlayer(backgoundPlayer);
// when w or s key is pressed
if(keys == 'w' || keys == 's'){
if(selectedButton == END_BUTTON){
selectedButton = RETURN_BUTTON;
}else{
selectedButton = END_BUTTON;
}
}else if(keys == '\n'){
break;
}
// update cursor
if(selectedButton == END_BUTTON){
mvaddstr(endButtonPosition.y + 1,endButtonPosition.x,CORSOR_REMOVE);
mvaddstr(returnButtonPosition.y + 1,returnButtonPosition.x,CURSOR);
}else if(selectedButton == RETURN_BUTTON){
mvaddstr(returnButtonPosition.y + 1,returnButtonPosition.x,CORSOR_REMOVE);
mvaddstr(endButtonPosition.y + 1,endButtonPosition.x,CURSOR);
}
// update text when overwrited by background player
mvaddstr(scorePosition.y,scorePosition.x,scoreText);
// TODO: fix worngly inverted button
mvaddstr(returnButtonPosition.y,returnButtonPosition.x,"end game");
mvaddstr(endButtonPosition.y,endButtonPosition.x,"return start screen");
refresh();
delta = clock() - start;
deltaf = clacTimeFromClock_t(delta);
usleep(adjustTimer(deltaf));
}
free(backgoundPlayer.body.data);
return selectedButton;
}
// end UI -----------------------------------------------------------
// This function makes possible convert player position to body position for graphic
Vector clacBodyPosition(Vector position, Vector bodySize){
Vector result;
if (bodySize.x % 2 == 0) result.x = position.x - (bodySize.x / 2);
if (bodySize.x % 2 != 0) result.x = position.x - (bodySize.x / 2);
result.y = position.y - bodySize.y;
return result;
}
void initPlayer(Player *player){
player -> hp = DEFAULT_PLAYER_HP;
player -> score = 0;
player -> currentStageScore = 0;
player -> counterOfGame = 0;
player -> damageIntarval = OUT_DAMAGE_INTARVAL;
player -> datageIntarvalFrame = 0;
// set first player position
getmaxyx(stdscr,player -> CurrentPosition.y,player -> CurrentPosition.x);
player -> CurrentPosition.x = player -> CurrentPosition.x / 2;
player -> PreviousPosition = player -> CurrentPosition;
player -> speed.x = 0; player -> speed.y = 0;
// set player body
player -> body.size.x = 5; player -> body.size.y = 4;
player -> body.position = clacBodyPosition(player->CurrentPosition,player->body.size);
// allocate ram
// player.body.data need to be freed when end game
allocateGraphicRam(&(player -> body));
// create and set player graphic
char tempBody[4][5] = {
{' ','#','#','#',' '},
{'#','#','#','#','#'},
{' ','#','#','#',' '},
{' ','#',' ','#',' '}
};
for(int y = 0; y < player -> body.size.y ; y++){
for(int x = 0; x < player -> body.size.x ; x++){
player -> body.data[y][x] = tempBody[y][x];
}
}
}
void showBackgroud(Graphic background){
for(int y = 0; y < background.size.y ; y++){
for(int x = 0; x < background.size.x ; x++){
move(y + background.position.y ,x + background.position.x);
addch(background.data[y][x]);
}
}
}
void initStage(Stage stage){
clear();
}
int stageSelector(Stage *stages){
int random = rand() % 100;
sprintf(logs,"stage selector rundom num is: %d",random);
debugLog(14,3,logs);
if(random <= stages[RAIN_STAGE].possible)
return RAIN_STAGE;
if(stages[RAIN_STAGE].possible < random && random <= stages[RAIN_STAGE].possible + stages[WIND_STAGE].possible)
return WIND_STAGE;
if(stages[RAIN_STAGE].possible + stages[WIND_STAGE].possible < random && random <= stages[RAIN_STAGE].possible + stages[WIND_STAGE].possible + stages[SUNNY_STAGE].possible)
return SUNNY_STAGE;
// if any if sentence is not working
debugLog(5,3,"Warning! stageSelector function is not working correctly!");
return RAIN_STAGE;
}
void addPoint(Vector position,char draw){
if(
position.x >= 0 &&
position.y >= 0 &&
position.x <= width &&
position.y <= height
){
mvaddch(position.y,position.x,draw);
}
}
// generic version of show graphic
// player graphic is not rendered here
void showGraphic(Graphic target){
// getmaxyx(stdscr,height,width);
resizeDetect();
// clear old graphic
for(int y = 0; y < target.size.y; y++){
for(int x = 0; x < target.size.x; x++){
if(
y + target.PreviousPosition.y >= 0 &&
x + target.PreviousPosition.x >= 0 &&
y + target.PreviousPosition.y <= height &&
x + target.PreviousPosition.x <= width
){
// move(y + target.PreviousPosition.y, x + target.PreviousPosition.x);
// addch(' ');
Vector pp = target.PreviousPosition;
pp.y += y; pp.x += x;
addPoint(pp,' ');
}
}
}
// render new graphic
for(int y = 0; y < target.size.y; y++){
for(int x = 0; x < target.size.x; x++){
if(
y + target.PreviousPosition.y >= 0 &&
x + target.PreviousPosition.x >= 0 &&
y + target.PreviousPosition.y <= height &&
x + target.PreviousPosition.x <= width
){
// move(y + target.position.y, x + target.position.x);
// addch(target.data[y][x]);
Vector p = target.position;
p.y += y; p.x += x;
// TODO fix segmantation fault
addPoint(p,target.data[y][x]);
}
}
}
}
// This function will update player hp
// This function will delete obj which hit the player
int detectHit(Player *player,Stage *stages,int selectedStage){
int detect = FALSE;
// getmaxyx(stdscr,height,width);
resizeDetect();
// For loop for all obj in stage
for(int objs = 0; objs < stages[selectedStage].numberOfObj; objs++){
// for(int objs = 0; objs < 0; objs){
Graphic target = stages[selectedStage].obj[objs];
// refrence obj and player graphics and compare both chars
// if both char info is not space like ' ', that mean detect hit.
// return bool value
// check target posiotion and check box in range or not to player
Vector targetPosition = target.position;
Vector targetSize = target.size;
if(
targetPosition.x + targetSize.x <= player -> body.position.x &&
targetPosition.y + targetSize.y <= player -> body.position.y &&
targetPosition.x >= player -> body.position.x + player -> body.size.x &&
targetPosition.y >= player -> body.position.y + player -> body.size.y
){
// skip detect hit when trarget is not in player graphic
continue;
}
// For loop to refrence all player body char
for(int py = 0; py < player -> body.size.y; py++){
for(int px = 0; px < player -> body.size.x; px++){
// For loop to refrence all obj body char
for(int oy = 0; oy < target.size.y ; oy++){
for(int ox = 0; ox < target.size.x; ox++){
char Aplayer = ' ';
char Aobj = ' ';
sprintf(logs,"debug log: obj %d",objs);
debugLog(4,3,logs);
if(
player -> body.position.x + px == target.position.x + ox &&
player -> body.position.y + py == target.position.y + oy
){
Aplayer = player -> body.data[py][px];
Aobj = target.data[oy][ox];
sprintf(logs,"debug log: detect hit at x: %d y: %d ",player -> body.position.x + px,player -> body.position.y + py);
debugLog(5,3,logs);
sprintf(logs,"debug log: Player char: %c obj char: %c",Aplayer,Aobj);
debugLog(6,3,logs);
}
// comapre values
if(
Aplayer != ' ' &&
Aobj != ' '
) detect = TRUE;
}
}
}
}
}
sprintf(logs,"detection var: %d",detect);
debugLog(9,3,logs);
if(detect == TRUE){
debugLog(8,3,"collision detected");
}
return detect;
}
// do special task for each stage ---------------------------------
void rainStage(Player *player,Stage *stages,int numberOfFrame){
// If there are objs which are diesappered, add score.
// If collion is detected, reduce player hp
// getmaxyx(stdscr,height,width);
resizeDetect();
// move rain
// SPEED_OF_RAIN -> amount of movement in a sec
// numberOfFrame % (100 / SPEED_OF_RAIN) -> number of update in a sec
if(numberOfFrame % (int)((double)100 / SPEED_OF_RAIN) == 0){
// Rondomly move rain without limitation -> fall movement
for(int obj_index = 0; obj_index < stages[RAIN_STAGE].numberOfObj; obj_index++){
stages[RAIN_STAGE].obj[obj_index].PreviousPosition = stages[RAIN_STAGE].obj[obj_index].position;
stages[RAIN_STAGE].obj[obj_index].position.y += 1;
}
}
// make rain obj
// add rain with random shapes
// control number of new rain obj by if sentence blow
if(numberOfFrame % (int)((double)100 / NUMEBR_OF_RAIN) == 0 && stages[RAIN_STAGE].numberOfObj < AMOUNT_OF_RAIN){
// make rain array
// init the all array element with space
char rain[RAIN_SIZE_Y][RAIN_SIZE_Y] = {' '};
for(int y = 0 ; y < RAIN_SIZE_Y; y++){
for(int x = 0; x < RAIN_SIZE_X; x++){
// rain[y][x] = '&';
int random = rand() % 2;
if(x % 2 == 0){
if(random % 2 == 0){
rain[y][x] = '&';
rain[y][x + 1] = ' ';
}
if(random % 2 != 0){
rain[y][x] = ' ';
rain[y][x + 1] = '&';
}
}
}
}
// create random position
// make not make same random num
int randomPosition = 0;
int count = 0;
while (count < NUMBER_OF_RETRY)
{
count++;
int moreBreak = FALSE;
randomPosition = rand() % width;
// avoid segmantation fault
if(stages[RAIN_STAGE].numberOfObj == 0) {
moreBreak = TRUE;
break;
}
for(int obj_index = 0; obj_index < stages[RAIN_STAGE].numberOfObj; obj_index++){
if(
// check obj in same x position
stages[RAIN_STAGE].obj[obj_index].position.x == randomPosition &&
// check how far from new obj in y aixs
stages[RAIN_STAGE].obj[obj_index].position.y < RAIN_Y_SPACE
){
// If there are no space enough, recreate random num
sprintf(logs,"debug log: false random num is %d",randomPosition);
debugLog(3,3,logs);
}else if(stages[RAIN_STAGE].obj[obj_index].position.x < RAIN_X_SPACE){
// If there are no space enough, recreate random num
sprintf(logs,"debug log: false random num is %d",randomPosition);
debugLog(3,3,logs);
}else{
sprintf(logs,"debug log: true random num is %d",randomPosition);
debugLog(3,3,logs);
moreBreak = TRUE;
break;
}
}
if(moreBreak == TRUE) break;
}
// allocate ram for new rain obj
// set position. x position is random but y position is always being at 0.
Vector size = {.x=RAIN_SIZE_X,.y=RAIN_SIZE_Y};
Vector position = {.x=randomPosition,.y=0};
int status = ALLOCATION_OK;
if(stages[RAIN_STAGE].obj == NULL){
while(stages[RAIN_STAGE].obj == NULL){
stages[RAIN_STAGE].obj = (Graphic *)malloc(sizeof(Graphic) * (AMOUNT_OF_RAIN + 2));
}
stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj].size = size;
stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj].position = position;
status = allocateGraphicRam(&(stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj]));
if(status == ALLOCATION_OK){
// add rain obj to stage obj
for(int y = 0 ; y < RAIN_SIZE_Y; y++){
for(int x = 0; x < RAIN_SIZE_X; x++){
stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj].data[y][x] = rain[y][x];
}
}
}
}else{
stages[RAIN_STAGE].numberOfObj += 1;
stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj].size = size;
stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj].position = position;
status = allocateGraphicRam(&(stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj]));
if(status == ALLOCATION_OK){
// add rain obj to stage obj
for(int y = 0 ; y < RAIN_SIZE_Y; y++){
for(int x = 0; x < RAIN_SIZE_X; x++){
stages[RAIN_STAGE].obj[stages[RAIN_STAGE].numberOfObj].data[y][x] = rain[y][x];
}
}
}else{
stages[RAIN_STAGE].numberOfObj -= 1;
}
}
}
// show and update all rain graphics
// separate code for in range version and out of range version
// check in range or not
for(int obj_index = 0; obj_index < stages[RAIN_STAGE].numberOfObj; obj_index++){
// make and use show graphic function
showGraphic(stages[RAIN_STAGE].obj[obj_index]);
}
// add score as player is alive
int score = 0;
score += (stages[RAIN_STAGE].timer * PLAYER_SCORE);
player -> currentStageScore = score;
}
void windStage(Player *player,Stage *stages,int numberOfFrame){
// getmaxyx(stdscr,height,width);
resizeDetect();
// If there are objs which are diesappered, add score.
// If collion is detected, reduce player hp
// move obj by wind
// update position
if(numberOfFrame % SPEED_OF_WIND_X == 0 || numberOfFrame % (int)((double)100 / SPEED_OF_WIND_Y) == 0){
for(int obj_index = 0; obj_index < stages[WIND_STAGE].numberOfObj; obj_index++){
stages[WIND_STAGE].obj[obj_index].PreviousPosition = stages[WIND_STAGE].obj[obj_index].position;
}
}
// SPEED_OF_WIND_X -> amount of movement in a sec
if(numberOfFrame % SPEED_OF_WIND_X == 0){
for(int obj_index = 0; obj_index < stages[WIND_STAGE].numberOfObj; obj_index++){
stages[WIND_STAGE].obj[obj_index].position.x += MOVEMENT_OF_OBJ_X;
}
}
// SPEED_OF_WIND_Y -> amount of movement in a sec
if(numberOfFrame % (int)((double)100 / SPEED_OF_WIND_Y) == 0){
for(int obj_index = 0; obj_index < stages[WIND_STAGE].numberOfObj; obj_index++){
if(rand() % 2){
stages[WIND_STAGE].obj[obj_index].position.y -= 1;
}else{
stages[WIND_STAGE].obj[obj_index].position.y += 1;
}
}
}
// create new obj
if(numberOfFrame % (int)((double)100 / NUMEBR_OF_BLOWN_AWAY_OBJ) == 0 && stages[WIND_STAGE].numberOfObj < AMOUNT_OF_OBJ){
// create random position
Vector position = {.x=0,.y=0};
position.y = rand() % height;
// create obj
int choosenObj = rand() % stages[WIND_STAGE].numberOfPreparedObj;
char **fig;
fig = stages[WIND_STAGE].PreparedObj[choosenObj].data;
int status = ALLOCATION_OK;
Vector size = stages[WIND_STAGE].PreparedObj[choosenObj].size;
if(stages[WIND_STAGE].obj == NULL) {
while(stages[WIND_STAGE].obj == NULL){
stages[WIND_STAGE].obj = (Graphic *)malloc(sizeof(Graphic) * (AMOUNT_OF_OBJ + 2));
}
stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].size = size;
stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].position = position;
// if size value is not set, cause segmantation fault
status = allocateGraphicRam(&(stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj]));
// add rain obj to stage obj
if(status == ALLOCATION_OK){
for(int y = 0 ; y < stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].size.y ; y++){
for(int x = 0; x < stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].size.x ; x++){
stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].data[y][x] = fig[y][x];
}
}
}
}else{
stages[WIND_STAGE].numberOfObj += 1;
stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].size = size;
stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].position = position;
status = allocateGraphicRam(&(stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj]));
// add rain obj to stage obj
if(status == ALLOCATION_OK){
for(int y = 0 ; y < stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].size.y ; y++){
for(int x = 0; x < stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].size.x ; x++){
stages[WIND_STAGE].obj[stages[WIND_STAGE].numberOfObj].data[y][x] = fig[y][x];
}
}
}else{
stages[WIND_STAGE].numberOfObj -= 1;
}
}
}
// update graphics
for(int obj_index = 0; obj_index < stages[WIND_STAGE].numberOfObj; obj_index++){
// make and use show graphic function
showGraphic(stages[WIND_STAGE].obj[obj_index]);
}
// add score as player is alive
int score = 0;
score += (stages[WIND_STAGE].timer * PLAYER_SCORE);
player -> currentStageScore = score;
// move obj randomly -> in x and y aixs
// show random obj
// count obj, disappered obj, appered obj
// use count obj result to caculate score and then update player score
}
void sunnyStage(Player *player,Stage *stages,int numberOfFrame){
// getmaxyx(stdscr,height,width);
resizeDetect();
// move obj randomly
// update position
if(numberOfFrame % (int)((double)100 / SPEED_OF_POINT_X) == 0|| numberOfFrame % (int)((double)100 / SPEED_OF_POINT_Y) == 0){
for(int obj_index = 0; obj_index < stages[SUNNY_STAGE].numberOfObj; obj_index++){
stages[SUNNY_STAGE].obj[obj_index].PreviousPosition = stages[SUNNY_STAGE].obj[obj_index].position;
}
}
// SPEED_OF_POINT_X -> amount of movement in a sec
if(numberOfFrame % (int)((double)100 / SPEED_OF_POINT_X) == 0){
for(int obj_index = 0; obj_index < stages[SUNNY_STAGE].numberOfObj; obj_index++){
if(rand() % 2){
stages[SUNNY_STAGE].obj[obj_index].position.x -= 1;
}else{
stages[SUNNY_STAGE].obj[obj_index].position.x += 1;
}
}
}
// SPEED_OF_POINT_Y -> amount of movement in a sec
if(numberOfFrame % (int)((double)100 / SPEED_OF_POINT_Y) == 0){
for(int obj_index = 0; obj_index < stages[SUNNY_STAGE].numberOfObj; obj_index++){
if(rand() % 2){
stages[SUNNY_STAGE].obj[obj_index].position.y -= 1;
}else{
stages[SUNNY_STAGE].obj[obj_index].position.y += 1;
}
}
}
// create new obj
if(numberOfFrame % (int)((double)100 / NUMEBR_OF_POINT) == 0 && stages[SUNNY_STAGE].numberOfObj < AMOUNT_OF_POINT){
Vector position = {.x=rand()%width,.y=rand()%height};
// create obj
int choosenObj = 0;
char **fig;
fig = stages[SUNNY_STAGE].PreparedObj[choosenObj].data;
Vector size = stages[SUNNY_STAGE].PreparedObj[choosenObj].size;
int status = ALLOCATION_OK;
if(stages[SUNNY_STAGE].obj == NULL) {
while(stages[SUNNY_STAGE].obj == NULL){
stages[SUNNY_STAGE].obj = (Graphic *)malloc(sizeof(Graphic) * (AMOUNT_OF_POINT + 2));
}
stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].size = size;
stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].position = position;
status = allocateGraphicRam(&(stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj]));
// add point obj to stage obj
if(status == ALLOCATION_OK){
for(int y = 0 ; y < stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].size.y ; y++){
for(int x = 0; x < stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].size.x ; x++){
stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].data[y][x] = fig[y][x];
}
}
}
}else{
stages[SUNNY_STAGE].numberOfObj += 1;
stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].size = size;
stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].position = position;
status = allocateGraphicRam(&(stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj]));
// add point obj to stage obj
if(status == ALLOCATION_OK){
for(int y = 0 ; y < stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].size.y ; y++){
for(int x = 0; x < stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].size.x ; x++){
stages[SUNNY_STAGE].obj[stages[SUNNY_STAGE].numberOfObj].data[y][x] = fig[y][x];
}
}
}else{
stages[SUNNY_STAGE].numberOfObj -= 1;
}
}
}
// update graphics
for(int obj_index = 0; obj_index < stages[SUNNY_STAGE].numberOfObj; obj_index++){
// make and use show graphic function
showGraphic(stages[SUNNY_STAGE].obj[obj_index]);
}
}
// do special task for each stage ---------------------------------
// show ui top left and right corner
void ShowStageUI(Stage stage,Player player){
Vector timerPosition,hpPosition,scorePosition,stageNamePosition;
// getmaxyx(stdscr,height,width);
resizeDetect();
timerPosition.y = 1; timerPosition.x = width - 20;
hpPosition.y = timerPosition.y + 1; hpPosition.x = width - 20;
scorePosition.y = hpPosition.y + 1; scorePosition.x = width - 20;
stageNamePosition.y = 1; stageNamePosition.x = 1;
char timerText[20];
char hpText[20];
char scoreText[20];
sprintf(timerText,"Time: %-3d/%-3d(sec)",(int)stage.timer,stage.timeLimit);
sprintf(hpText,"HP: %-3d",player.hp);
sprintf(scoreText,"Score: %-3d",player.currentStageScore + player.score);
mvaddstr(timerPosition.y,timerPosition.x,timerText);
mvaddstr(hpPosition.y,hpPosition.x,hpText);
mvaddstr(scorePosition.y,scorePosition.x,scoreText);
mvaddstr(stageNamePosition.y,stageNamePosition.x,stage.name);
refresh();
}
int jumpPlayer(Player *player,int numberOfFrame){
// pi value should be between 0 and PLAYER_JUMP_MAX
int result = 0;
double temp = 0;
float pi = 0;
int playerJumpHeight = PLAYER_JUMP_MAX;
// getmaxyx(stdscr,height,width);
resizeDetect();
if(playerJumpHeight > height){
playerJumpHeight = height - 4;
}
double lengthInOneFrame = (double)(playerJumpHeight * 2) / 100;
lengthInOneFrame /= PLAYER_JUMP_TIME;
if(player -> speed.y < (playerJumpHeight * 2)) player->speed.y += lengthInOneFrame;
else player -> speed.y = 0;
pi = sin(player -> speed.y * (3.14f / (playerJumpHeight * 2)));
temp = (double)height - (pi * (double)playerJumpHeight);
return (int)temp;
}
void controlPlayer(Player *player,int numberOfFrame){
// getmaxyx(stdscr,height,width);
resizeDetect();
int keys;
// player can be controled by wasd keys
timeout(0);
keys = getch();
player->PreviousPosition = player->CurrentPosition;
// jump
if(((keys == 'w' || keys == ' ') && player->CurrentPosition.y > 0) || player->speed.y != 0) player->CurrentPosition.y = jumpPlayer(player,numberOfFrame);
// move left and right in constant speed
if(keys == 'a' && player->CurrentPosition.x > 0 + (player->body.size.x / 2) + 1) player->CurrentPosition.x -= PLAYER_SPEED;
if(keys == 'd' && player->CurrentPosition.x < width - player->body.size.x) player->CurrentPosition.x += PLAYER_SPEED;
// update graphic position
player -> body.position = clacBodyPosition(player->CurrentPosition,player->body.size);
}
void detectHitPlayer(Player *player,Stage *stages,int selectedStage,int numberOfFrame){
int collosion = detectHit(player,stages,selectedStage);
if(collosion == TRUE && player -> damageIntarval == OUT_DAMAGE_INTARVAL){
switch (selectedStage)
{
case RAIN_STAGE:
flash();
player -> hp -= DAMAGE_OF_RAIN;
break;
case SUNNY_STAGE:
flash();
player -> hp += AMOUNT_OF_RACOVER;
player -> currentStageScore += PLAYER_SCORE;
break;
case WIND_STAGE:
flash();
player -> hp -= DAMAGE_OF_OBJ;
break;
default:
debugLog(3,10,"Worng stage is selected. Check code.");
break;
}
player -> damageIntarval = IN_DAMAGE_INTARVAL;
}
if(player -> damageIntarval == IN_DAMAGE_INTARVAL) player -> datageIntarvalFrame += 1;
if(player -> datageIntarvalFrame == (100 * DAMAGE_INTARVAL)){
player -> damageIntarval = OUT_DAMAGE_INTARVAL;
player -> datageIntarvalFrame = 0;
}
sprintf(logs,"damage intarval: %d",player -> datageIntarvalFrame);
debugLog(11,3,logs);
}
void showPlayer(Player player){
// clear old player graphic
Vector oldBodyPosition = clacBodyPosition(player.PreviousPosition,player.body.size);
for(int y = 0; y < player.body.size.y; y++){
for(int x = 0; x < player.body.size.x; x++){
move(y + oldBodyPosition.y,x + oldBodyPosition.x);
addch(' ');
}
}
// show player
for(int y = 0; y < player.body.size.y; y++){
for(int x = 0; x < player.body.size.x; x++){
move(y + player.body.position.y,x + player.body.position.x);
addch(player.body.data[y][x]);
}
}
refresh();
}
// TODO: fix segmatation fualt after wind stage
// call once when start button selected
// make start_UI call this function when start button is selected. -> OK
void StageLoop(Player *player,Stage *stages){
int selectedStage = WIND_STAGE;
for(int times = 0; times < NUMBER_OF_GAME; times++){
selectedStage = stageSelector(stages);
initStage(stages[selectedStage]);
clock_t start = 0, delta = 0;
time_t gameStartTime = time(NULL);
double deltaf = 0;
int numberOfFrame = 0;
int resizeHappn = RESIZE_NOT_HAPPEND;
while(1){
start = clock();
resizeHappn = resizeDetect();
// move -> update graphic -> collion detection
controlPlayer(player,numberOfFrame);
// show time hp score stage name -> OK
ShowStageUI(stages[selectedStage],*player);
// update order
// stage graphic -> player graphic
if(numberOfFrame % 30 == 0) stages[selectedStage].stageFunc(player,stages,numberOfFrame);
showPlayer(*player);
// collsion system
detectHitPlayer(player,stages,selectedStage,numberOfFrame);
refresh();
numberOfFrame++;
delta = clock() - start; deltaf = clacTimeFromClock_t(delta);
stages[selectedStage].timer = difftime(time(NULL),gameStartTime);
if(resizeHappn) resizeHappn = RESIZE_NOT_HAPPEND;
usleep(adjustTimer(deltaf));
if(stages[selectedStage].timer > stages[selectedStage].timeLimit || player -> hp <= 0) break;
}
// all stage reqire addtional memory management
freeObjGraphicRam(stages[selectedStage].obj,stages[selectedStage].numberOfObj);
free(stages[selectedStage].obj);
stages[selectedStage].numberOfObj = 0;
// stages[selectedStage].timer = 0;
setStageParam(stages);
player -> score += player -> currentStageScore;
player -> currentStageScore = 0;
if(player -> hp <= 0) break;
}
}
// pass stage array whose size is 3
void setStageParam(Stage *stages){
// getmaxyx(stdscr,height,width);
resizeDetect();
// rain stage --------------------------------------------------------------------------------
stages[RAIN_STAGE].possible = RAIN_STAGE_POSSIBLE;
stages[RAIN_STAGE].timer = 0;
stages[RAIN_STAGE].timeLimit = RAIN_STAGE_TIME_LIMIT;
sprintf(stages[RAIN_STAGE].name,"rain stage");
// rain obj
// obj will be used to manage rain obj in rain stage
// rain will be made by function and caculation
// So in this function, I will not allocate
stages[RAIN_STAGE].numberOfObj = 0;
stages[RAIN_STAGE].obj = NULL;
stages[RAIN_STAGE].numberOfPreparedObj = 0;
stages[RAIN_STAGE].PreparedObj = NULL;
// stage function pointer
stages[RAIN_STAGE].stageFunc = rainStage;
// rain stage --------------------------------------------------------------------------------
// wind stage --------------------------------------------------------------------------------
stages[WIND_STAGE].possible = WIND_STAGE_POSSIBLE;
stages[WIND_STAGE].timer = 0;
stages[WIND_STAGE].timeLimit = WIND_STAGE_TIME_LIMIT;
sprintf(stages[WIND_STAGE].name,"wind stage");
// blown away obj
// rectangle obj 0
int obj_index = 0;
stages[WIND_STAGE].numberOfPreparedObj = 1;
stages[WIND_STAGE].PreparedObj = malloc(sizeof(Graphic) * 3);
stages[WIND_STAGE].PreparedObj[obj_index].position.x = 0; stages[WIND_STAGE].PreparedObj[obj_index].position.y = 0;
stages[WIND_STAGE].PreparedObj[obj_index].size.x = 3; stages[WIND_STAGE].PreparedObj[obj_index].size.y = 3;
allocateGraphicRam(&(stages[WIND_STAGE].PreparedObj[obj_index]));
char rectangle[3][3] = {
{'A','A','A'},
{'A',' ','A'},
{'B','B','B'}};
for(int y = 0; y < stages[WIND_STAGE].PreparedObj[obj_index].size.y; y++){
for(int x = 0; x < stages[WIND_STAGE].PreparedObj[obj_index].size.x; x++){
stages[WIND_STAGE].PreparedObj[obj_index].data[y][x] = rectangle[y][x];
}
}
obj_index++;
stages[WIND_STAGE].numberOfPreparedObj += 1;
// triangle obj 1
stages[WIND_STAGE].PreparedObj[obj_index].position.x = 0; stages[WIND_STAGE].PreparedObj[obj_index].position.y = 0;
stages[WIND_STAGE].PreparedObj[obj_index].size.x = 5; stages[WIND_STAGE].PreparedObj[obj_index].size.y = 3;
allocateGraphicRam(&(stages[WIND_STAGE].PreparedObj[obj_index]));
char triangle[3][5] = {
{' ',' ','a',' ',' '},
{' ','A',' ','A',' '},
{'b','B','B','B','b'}};
for(int y = 0; y < stages[WIND_STAGE].PreparedObj[obj_index].size.y; y++){
for(int x = 0; x < stages[WIND_STAGE].PreparedObj[obj_index].size.x; x++){
stages[WIND_STAGE].PreparedObj[obj_index].data[y][x] = triangle[y][x];
}
}
obj_index++;
stages[WIND_STAGE].numberOfPreparedObj += 1;
// hexagon? obj 2
stages[WIND_STAGE].PreparedObj[obj_index].position.x = 0; stages[WIND_STAGE].PreparedObj[obj_index].position.y = 0;
stages[WIND_STAGE].PreparedObj[obj_index].size.x = 5; stages[WIND_STAGE].PreparedObj[obj_index].size.y = 6;
allocateGraphicRam(&(stages[WIND_STAGE].PreparedObj[obj_index]));
char hexagon[6][5] = {
{' ',' ','*',' ',' '},
{' ','J',' ','L',' '},
{'A',' ',' ',' ','A'},
{'A',' ',' ',' ','A'},
{' ','L',' ','J',' '},
{' ',' ','*',' ',' '}};
for(int y = 0; y < stages[WIND_STAGE].PreparedObj[obj_index].size.y; y++){
for(int x = 0; x < stages[WIND_STAGE].PreparedObj[obj_index].size.x; x++){
stages[WIND_STAGE].PreparedObj[obj_index].data[y][x] = hexagon[y][x];
}
}
stages[WIND_STAGE].numberOfObj = 0;
stages[WIND_STAGE].obj = NULL;
// stage function pointer
stages[WIND_STAGE].stageFunc = windStage;
// wind stage --------------------------------------------------------------------------------
// sunny stage --------------------------------------------------------------------------------
stages[SUNNY_STAGE].possible = SUNNY_STAGE_POSSOIBLE;
stages[SUNNY_STAGE].timer = 0;
stages[SUNNY_STAGE].timeLimit = SUNNY_STAGE_TIME_LIMIT;
sprintf(stages[SUNNY_STAGE].name,"sunny stage");
// point obj 0
// This obj give player score and point
// If player miss this obj, these obj will not be score
obj_index = 0;
stages[SUNNY_STAGE].numberOfPreparedObj = 1;
stages[SUNNY_STAGE].PreparedObj = malloc(sizeof(Graphic) * 1);
stages[SUNNY_STAGE].PreparedObj[obj_index].position.x = 0; stages[SUNNY_STAGE].PreparedObj[obj_index].position.y = 0;
stages[SUNNY_STAGE].PreparedObj[obj_index].size.x = 3; stages[SUNNY_STAGE].PreparedObj[obj_index].size.y = 5;
allocateGraphicRam(&(stages[SUNNY_STAGE].PreparedObj[obj_index]));
char point[5][3] = {
{'P','P','P'},
{'P',' ','P'},
{'P','P','P'},
{'P',' ',' '},
{'P',' ',' '}};
for(int y = 0; y < stages[SUNNY_STAGE].PreparedObj[obj_index].size.y; y++){
for(int x = 0; x < stages[SUNNY_STAGE].PreparedObj[obj_index].size.x; x++){
stages[SUNNY_STAGE].PreparedObj[obj_index].data[y][x] = point[y][x];
}
}
stages[SUNNY_STAGE].numberOfObj = 0;
stages[SUNNY_STAGE].obj = NULL;
// stage function pointer
stages[SUNNY_STAGE].stageFunc = sunnyStage;
// synny stage --------------------------------------------------------------------------------
}
int main(int argc,char ** args){
int selectedMode = START_BUTTON;
Player player;
Stage *stages;
stages = malloc(sizeof(Stage) * 3);
setStageParam(stages);
initWholeGame();
// show start UI
selectedMode = startUI();
initPlayer(&player); // OK
while(1){
if(selectedMode == START_BUTTON){
initPlayer(&player); // OK
StageLoop(&player,stages);
// show end UI
selectedMode = endUI(&player);
}else if(selectedMode == RETURN_BUTTON){
selectedMode = startUI();
}else if(selectedMode == END_BUTTON){
break;
}
}
// end curses and free ram
endWholeGame(&player,stages);
free(stages);
return 0;
}