この記事を書いた動機

 ただ単にせっかく書いたコードを、無下にしてしまうのは勿体ないなと思い、非効率でバグだらけのスパゲッティコードではあるが、まあおいておこうかなと思っただけです。(かつコメントの英語もガバだらけ。。。)

 ちなみに、授業の制約上、一つのファイルにまとめざるを得ず、プログラムを分割できなかったのでえげつなく肥大化しています。。。

使っているライブラリ

  • C標準ライブラリ
  • curses

プレイ動画

各画面の説明

スタート画面

ZgotmplZ/

終わりの画面

ZgotmplZ/

風のすてーじ

ZgotmplZ/

雨のすてーじ

ZgotmplZ/

晴れの日すてーじ

ZgotmplZ/

コンパイル

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;
}