ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • "교체" 함수 구현
    포켓몬 배틀 구현 2022. 3. 16. 16:40

    배틀 시스템의 기초가 되는 대부분의 함수는 설명이 끝났다.

    딱 하나 남았는데, 바로 "교체" 함수이다.

     

    처음에 교체 함수는 교체가 아니라 "기절" 함수였다.

    포켓몬을 교체하는 순간은 크게 3가지가 있다.

     

    첫번째는 행동으로 교체를 선택하는 것.

    두번째는 포켓몬이 쓰러져 교체하는 것

    세번째는 "유턴"과 같은 기술의 부가효과로 교체하는 것.

     

    3번의 경우는 일단 건너 뛰고,

    맨 처음 구현할때 때 나는

    1번의 경우는 플레이어와 CPU의 행동 선택 구간에서 교체를 진행하였고,

    2번의 경우 "기절" 함수를 만들어서 기절 이후의 과정을 처리하였다.

    다만 이후 3번의 경우도 추가하다보니 아무래도 비효율적이라 느껴졌고,

     

    "기절" 함수를 "교체" 함수로 바꿔서

    1번 2번 3번의 경우 모두를 동일한 함수 호출로 끝내버렸다.

    진작 이렇게 할껄.

     

    일단 교체 함수는 다음과 같다

    void 교체(int life[], int pp, string p[][one][two], int ps[], string s[][one][two], int ss) {

    .

    "교체" 함수는 플레이어의 교체를 담당하는 함수로,

    CPU의 교체는 따로 작성한다.

    해당 함수는 인자로 교체할 포켓몬의 정보 배열과 체력 배열, 그리고 PS 배열을 필요로한다.

    상대방의 정보와 순서 배열은 필요없다만,

    이는 "기절" 함수에서 "교체" 함수로 바꿨을때의 흔적이다.

    다만 없애자니 나중에 쓸수도 있을것같아서 일단은 그냥 남겨놨다.

     

     

     

    if ((life[a(pp)] > 0 ) && (life[b(pp)] > 0 )) {
            //다른 두 포켓몬이 전부 살아있는 경우
            cout << "누구로 교체하시겠습니까?   1:" << p[a(pp)][0][0] << "  2:" << p[b(pp)][0][0];
            int gyoche;
            while (1) {
                cout << "\n\n\n 입력:";
                cin >> gyoche;
                cout << "\n\n";
                if (gyoche == 1) { //1번 포켓몬으로 교체
                    cout << "나는 " << p[pp][0][11] << t1(p, pp) << p[a(pp)][0][11] << k1(p, a(pp)) << "교체했다!\n";
                    pp = a(pp);//현재 포켓몬의 번호를 해당 포켓몬 번호로 변경
                    break;
                }
                else if (gyoche == 2) {//2번 포켓몬으로 교체
                    cout << "나는 " << p[pp][0][11] << t1(p, pp) << p[b(pp)][0][11] << k1(p, b(pp)) << "교체했다!\n";
                    pp = b(pp);
                    break;
                }
                else // while문으로 맞는 숫자를 입력 받을 때까지 반복.
                    printf("\n\n[입력오류. 숫자 1이나 2를 입력 바랍니다.]\n\n");
            }
        }

    일단 첫번째, 현재 포켓몬을 제외하고 다른 두 포켓몬이 모두 살아있는 경우이다.

    누구로 교체하겠냐는 텍스트를 출력하고,

    1과 2의 숫자를 입력받아 값에 따라 1번 혹은 2번 포켓몬으로 교체한다.

    교체는 ~로 교체했다 라는 텍스트와 함께

    현재 포켓몬의 번호만 변경하면 되므로 생각보다 간단하다.

     

    else if ( life[a(pp)] > 0 && life[b(pp)] <= 0 ) {
            //1번 포켓몬만 살아있는 경우
            cout << "나는 " << p[pp][0][11] << t1(p, pp) << p[a(pp)][0][11] << k1(p, a(pp)) << "교체했다!\n";
            pp = a(pp);//1번 포켓몬으로 교체
     
        }
        else if ( life[a(pp)] <= 0  && life[b(pp)] > 0 ) {
            cout << "나는 " << p[pp][0][11] << t1(p, pp) << p[b(pp)][0][11] << k1(p, b(pp)) << "교체했다!\n";
            pp = b(pp);
        }

    그리도 둘중 하나만 살아있는 경우, 해당 포켓몬으로 자동 교체된다.

     

    ps[0] = pp; //현재 포켓몬의 번호를 ps 배열에 리턴

    이후 이렇게 변경된 PP값을 PS배열에 적용하면 끝

     

     

    교체이벤트(life, ge, p, ps, s, ss, 1);

    그치고 추가로, "교체이벤트"라는 함수를 호출한다.

    인자는 교체 함수와 비슷한데,

    교체 후 해당 함수르 호출하기때문에,

    pp는 교체 후 포켓몬의 번호를 가리킨다.

    그러므로 교체 전 포켓몬 번호를 pp를 변경하기전 ge 변수에 넣어 ge 값을 인자로 사용한다.

    맨 마지막 1은 내가 교체했다는 뜻,

    상대가 교체했다면 0을 넣는다.

     

    해당 함수를 따로 사용하는 이유는,

    교체시 발생하는 이벤트들을

    플레이어 교체 함수와 cpu 교체 함숟 2군데에 넣는건 비효율적이므로

    교체시 발생하는 이벤트들을 한데 모아 "교체", "상대교체" 두 함수에서 호출한다.

     

     

    //특성 재생력 : 교체시 체력 1/3 회복
        if (p[pp][0][12] == "재생력") {
            int hill = stoi(p[pp][0][3]) / 3; //회복량은 전체 체력의 1/3
            if (life[pp] + hill > stoi(p[pp][0][3]))
                hill = stoi(p[pp][0][3]) - life[pp];
            cout << "[특성 재생력]\n";
            if (k == 0) {
                printf("상대 ");
            }
            cout << p[pp][0][11] << "의 체력이 회복되었다! (";
            cout << life[pp];
            life[pp] += hill;//회복 처리
            cout << "+" << hill << "=" << life[pp] << ")\n";//회복량 프린트
        }

    교체 이벤트중 첫번째는 특성 재생력으로, 교체시 체력이 1/3 회복되는 효과이다.

     

    사실 포켓몬 배틀중 교체시 발동되는 이벤트는 대부분 원상태로 초기화되는게 대부분이다.

    랭크변화, 혼란 상태이상, 맹독 카운트 등

    해당 값들을 정해진 초기값으로 변경시키면 된다.

    그렇기에 나는 이들을 "교체" 함수가 아닌 "후처리" 함수에서 처리했다.

     

    a란 포켓몬 교체하여 혼란 상태이상이 풀린다고 할떄,

    a를 교체하는 시점에 혼란 상태이상을 푸는것과

    a가 교체하고 턴이 끝나기 직전, 필드 위에 없는 모든 포켓몬들의 호란 상태이상을 초기화 하는것은

    거의 동일한 결과를 내기 때문이다.

     

    예외사항이 있다면

    교체를 하였는데 "울부짖기"와 같은 상대방의 기술로 인해 턴이 바뀌기 전에 다시 교체되는 것.

    (울부짖기는 상대방을 강제로 교체시키는 기술이다.)

    a란 포켓몬을 교체하였는데 상대방의 울부짖기로 다시 a 포켓몬이 나왔다면

    전자의 경우 교체중 혼란 상태이상을 초기화하였으니 문제 없지만

    후자의 경우 턴 종료 시점에 해당 포켓몬은 필드 위에 존재하므로

    혼란 상태이상이 풀리지 않는다!

     

    물론 "울부짖기" 기술을 아직 구현 안해서... 아직은 일어날리 없는 문제점이다

     

    근데 이러한 교체 이벤트를 따로 생성한 이유는

    이 특성 재생력 때문이다.

    이는 칠색조의 특성으로

    교체시 체력이 1/3 회복된다.

    즉 필드위에 없는 포켓몬들의 특정 값을 고정된 값으로 변경하는게 아니여서, "후처리" 함수에서 처리가 불가능하다

    그렇기에 교체 이벤트 함수를 만들었고

    하는김에 다른것들도 이쪽으로 옮겨왔다.

     

    쨌든 코드 내용은 체력의 1/3 회복, 풀피 이상이면 풀피 만큼만 회복

    지금까지 몇번이나 봐온 코드이므로 자세한 설명은 생략

     

     

    //교체한 포켓몬의 "혼란" 상태이상 초기화
        p[pp][5][4] = "n";
    
        //교체한 포켓몬의 "맹독" 카운트 초기화
        p[pp][5][8] = "0";
    
        //교체한 포켓몬의 "방어" 성공률 초기화
        p[pp][4][15] = "100";
    
        //교체한 포켓몬의 랭크 변화 초기화
        for (int i = 5; i < 10; i++) {
            p[pp][11][i] = "0";
        }
    
        //교체한 포켓몬의 "스카프" 제약 초기화
        for (int i = 1; i < 5; i++) {
            p[pp][i][13] = "y";
        }
    
        //교체한 에이스번의 "리베로" 초기화
        if (p[pp][0][11] == "에이스번") {
            p[pp][0][1] = "불꽃";
            p[pp][7][0] = "땅";
            p[pp][7][1] = "물";
            p[pp][7][2] = "바위";
            p[pp][8][0] = "강철";
            p[pp][8][1] = "벌레";
            p[pp][8][2] = "불꽃";
            p[pp][8][3] = "얼음";
            p[pp][8][4] = "페어리";
            p[pp][8][5] = "풀";
        }

     

    그 외의 것들은 아까 말했듯이 고정된 값으로 변경하면 된다

    교체한 포켓몬의 혼란이 걸려있든 말든,

    현재 혼란 여부는 "n"으로 바꾼다.

     

    맹독은 턴이 지날수록 데미지가 강해지는데, 이는 교체하면 초기화된다.

    맹독 카운트를 "0"으로 바꿔준다.

    물론 맹독이 걸려있는지 아닌지는 중요하지 않다.

     

    포켓몬 기술중 하나인 "방어"는 연속 사용시 성공률이 떨어지고

    방어가 실패하거나, 교체하면 성공률이 되돌아온다.

    이 역시 해당 스킬이 방어든 아니든 성공률을 "100"으로 바꿔준다.

    스킬의 [15] 칸은 다른 기술들은 전부 공백이며 "방어" 기술만 성공률 값을 지니고 있다.

     

    랭크변화 초기화는 모든 실능치를 원래 실능치로 변경하고

    스카프 제약은 모든 스킬의 사용 가능 여부를 "y"로 바꾼다

    랭크 변화가 존재하는지, 지닌 아이템이 스카프인지는 역시 상관 없다.

     

    마지막은 에이스번의 특성 "리베로"

    자신이 사용한 스킬의 타입으로 변경되는 특성인데,

    이는 교체하면 원래의 불꽃타입으로 되돌아오므로 이 역시 "교체 이벤트" 함수에 구현해준다.

     

     

     

     

    void 상대교체(int life[], int ss, string s[][one][two], int ps[], int pp, string p[][one][two]) {
        int ge = ss;
        //상대의 포켓몬 교체를 처리하는 함수
        if ( life[a(ss)] >= 0 ) {
            cout << "상대는 " << s[ss][0][11] << t1(s, ss) << s[a(ss)][0][0] << k1(s, a(ss)) << "교체했다!\n";
            ss = a(ss);
        }
        else if ( life[b(ss)] >= 0 ) {
            cout << "상대는 " << s[ss][0][11] << t1(s, ss) << s[b(ss)][0][0] << k1(s, b(ss)) << "교체했다!\n";
            ss = b(ss);
        }
        교체이벤트(life, ge, s, ps, p, pp, 0);
        ps[1] = ss;
    }

    그리고 마지막, 상대방의 교체를 담당하는 함수,

    이 역시 어떠한 포켓몬으로 교체할지 ai를 구현해야하므로 일단은 앞 포켓몬부터 우선하여 교체하도록 하였고,

    해당 함수는 배틀 시스템을 전부 구현한 다음 구현할것이다.

     

     

    드디어 배틀 시스템에 쓰이는 함수들 설명이 전부 끝났다.

    물론 함수는 여러개 더 있지만, 이는 함수 그 자체보단

    각 포켓몬들의 구현 과정을 설명하면서 설명할것이다.

     

     

Designed by Tistory.