ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 다섯번째 포켓몬, 메타몽 구현 (변신)
    포켓몬 배틀 구현 2022. 3. 16. 23:51

    메타몽이다.

    체력, pp, 상태이상을 제외한 상대방의 모든 정보를 카피하는 포켓몬이다.

    즉 따로 무언가를 구현할 필요 없이,

    메타몽의 특성 "괴짜"만 구현하면 끝이다!

     

    이거 완전 개꿀이지 하고 시작했는데

    다른 포켓몬들이랑 시간은 비슷하게 걸렸다.

    이거때문에 다른 포켓몬들을 구현할때 발생한 버그들을 

    해결한 시간가지 포함하면 훨씬 더 걸렸다.

    역시 인생은 쉽지 않다.

     

    string 랜드로스[one][two] = {
        {"랜드로스", "땅", "비행", "164", "197", "112", "110", "100", "157", "n", "n","랜드로스", "위협", "생구"},
        {"지진", "땅", "100", "100", "10", "물리", "null", "null", "null", "null", "null", "n", "y", "y", "부가효과 없음"},
        {"칼춤", "노말", "-", "-", "5","변화", "랭크", "100", "공격", "2", "자신", "n", "y", "y", "사용자의 공격을 2랭크 올린다."},
        {"유턴", "벌레", "70", "100", "20", "물리", "교체", "100", "null", "null", "null", "n", "y" , "y", "공격 후 아군 포켓몬과 교체한다."},
        {"암석봉인", "바위", "60", "95",  "15", "물리", "랭크", "100", "스피드", "-1", "상대", "n", "y", "y", "상대방의 스피드를 1랭크 떨어뜨린다."},
        {"n", "n", "n", "n", "n", "0", "n"},
        {"얼음"},
        {"물"},
        {"격투", "벌레", "독"},
        {},
        {"땅", "전기"},
        {"공격력","특수공격력","방어력","특수방어력", "스피드", "0","0","0","0","0", "197", "112", "110", "100", "157"},
    };
    string 메타몽[one][two] = {
        {"메타몽", "노말", "null","155","68","68","68","68","53","n","y","메타몽", "괴짜", "스카프"},
        {"변신", "노말","-","-","5", "변화","-","-","-","-","-","-","y","y","상대 포켓몬으로 변신한다."},
        {"-", "-","-","-","5", "-","-","-","-","-","-","-","-","n","-"},
        {"-", "-","-","-","5", "-","-","-","-","-","-","-","-","n","-"},
        {"-", "-","-","-","5", "-","-","-","-","-","-","-","-","n","-"},
        {"n", "n", "n", "n", "n", "0", "n"},
        {""},
        {"격투"},
        {""},
        {""},
        {"고스트"},
        {"공격력","특수공격력","방어력","특수방어력", "스피드", "0","0","0","0","0", "68", "68", "68", "68", "53"},
    };

    기본적인 포켓몬의 정보를 담은 배열이다.

    메타몽의 경우 다른 포켓몬과 달리 쓸게 정말 적다!

    일부로 최대한 적게 하려다가 버그나서 한참 찾은건 이따 얘기하도록하고(...)

     

     

    if (p[pp][0][12] == "괴짜") {

    메타몽의 특성 괴짜는 등장하자 마자 상대방의 능력치를 카피하는 특성이다.

    즉 "즉발특성" 함수에서 처리한다.

     if (k[kn][0][11] == "메타몽") {
                if (s == 1) cout << "상대 ";
                cout << k[kn][0][0] << s1(k, kn) << "배낄 수 없다!\n";
            }

    일단 메타몽은 메타몽과, 누군가로 변신한 메타몽은 배낄 수 없다.

    즉 상대방의 원래 이름 k[kn][0][11]이 "메타몽"이라면 특성은 발동되지 않는다.

     

     else {
                if (s == 0) cout << "상대 ";
                cout << "메타몽은 " << k[kn][0][11] << k1(k, kn) << "변신했다!\n";
                for (int i = 0; i < one - 1; i++) {
                    for (int j = 0; j < two - 1; j++) {
                        if (i != 5) {
                            p[pp][i][j] = k[kn][i][j];
                        }
                    }
                }
                //상대방의 개체값을 카피함

    아닌 경우에는 상대방의 정보 배열을 일단 전부 카피한 다음,

    카피하면 안되는 내용들을 일부 수정하는 방식으로 진행하였다.

     

    상태이상 여부는 카피하지 않고 기존의 값을 유지해야하므로

    i가 5일때는 뺸다.

     

     p[pp][0][0] = k[kn][0][11] + "(메타몽)";
                //이름은 상대방 이름 + (메타몽)
                p[pp][0][3] = "155";
                //체력은 바뀌지 않음.
                p[pp][0][10] = "y";
                //이름의 받침 여부. 메타"몽"
                p[pp][0][11] = "메타몽";
                p[pp][0][13] = "스카프";
                p[pp][1][4] = "5";
                p[pp][2][4] = "5";
                p[pp][3][4] = "5";
                p[pp][4][4] = "5";
                //모든 스킬의 pp는 5로 고정

    일단 이름은 상대방의 이름 + (메타몽)으로 바꾼다.

    에이스번을 배꼈다면

    에이스번(메타몽)이 이름이 된다.

    메타몽의 경우 체력 값은 배끼지 않는다. 체력은 기존의 실능치 155이다.

     

    이름의 받침여부 메타몽"은"과 같은 조사들을 고르기 위한 값이므로 "y"로 바꾼다.

    *이름은 "에이스번(메타몽)"으로 출력되지만

    행동을 할때는 "메타몽은 무릎차기를 사용했다!"로 메타몽으로 출력된다.

     

    원래 이름은 "메타몽"으로 고정이고 절대로 바뀌지 않는다.

    아이템은 배끼지 않으므로 기존의 아이템 "스카프"로 고정된다.

     

    그리고 모든 스킬의 pp는 5로 고정된다.

     

     

    if (p[pp][0][12] == "탈까임") {
             p[pp][0][12] = "탈";
             //탈은 소모되는 특성이므로 이미 발동된 탈은 복구하여 배낀다
    }

    추가로 특성을 배끼는데,

    따라큐의 특성 "탈"은 1회용 특성이다.

    특성 "탈"이 발동되었다면 또 발동되는것을 막기위해 이름을 "탈까임"으로 바꾸는데,

     

    탈 특성이 빠진 따라큐를 배끼더라도 해당 특성은 복원되어야 하므로

    배낀 특성 이름이 "탈까임"이면 "탈"로 바꿔 탈을 복구해준다.

     

    if (k[kn][0][13] != "스카프") {
                    //메타몽의 지닌 물건은 스카프로, 스피드가 배낀 수치의 1.5배가 됨.
                    //단 상대도 지닌 물건이 스카프일때는 예외. (이미 1.5배가 된걸 배끼기 때문) 
                    string mss = to_string(stoi(p[pp][0][8]) * 3 / 2);
                    p[pp][0][8] = mss;
                    p[pp][11][14] = mss;
                    //현재 스피드 값과 원래 스피드 값을 1.5배.
    }

    그리고 메타몽의 아이템은 "스카프"로

    배낀 상대방의 능력치중 스피드는 1.5배가 된다.

     

    다만 주의 사항이 있는데,

    상대방의 아이템도 스카프일경우,

    스카프로 1.5배된 상대방의 스피드를 배낀뒤

    또 1.5배 되어 스피드가 2.25배가 된다.

    이러한 경우를 막기 위해 상대방의 아이템이 스카프가 아닐때만 스피드를 1.5배로 곱한다.

     

    즉발특성(p, pp, s, k, kn, ps);
                //상대로 변신하여 배낀 특성을 발동하기 위해 즉발 특성 함수를 다시 한번 호출.
                //메타몽 특성 발동 기준은 현재 이름과 원래 이름이 "메타몽"이여야 하는데,
                //상대로 변신하면 현재 이름이 "메타몽"이 아니므로 함수가 무한 반복되지 않음.

     

    그리고, "즉발특성" 함수 안의 메타몽 항목에서 다시한번 "즉발특성" 함수를 호출한다.

    한마디로 재귀함수다.

    이게 필요한 이유는, 배낀 특성이 즉발 특성일경우 바로 발동되기 때문이다.

     

    예를 들어 자시안과 메타몽이 동시에 교체했다면,

    스피드가 빠른 자시안의 특성이 먼저 발동하여 자신의 공력이 1랭크 오르고,

    메타몽은 이 공 1업 상태의 자시안을 배낀뒤,

    배낀 특성이 발동하여 또 공격력이 올라

    메타몽은 공2업 자시안이 된다.

     

    이러면 메타몽 구현 끝!

     

     

     

    이라면 좋겠다만

    아직 쬐금 남았다.

     

     

    일단 스킬 "변신"도 구현은 해놔야지

    쓸일이 있을지는 모르겠다만 구현은 간단하다

    if (skillname=="변신") { 즉발특성(p, pn, k, s, sn, ps); }

    변신은 변화기이므로 "변화스킬" 함수에 해당 내용을 추가한다.

    어차피 코드는 "즉발특성" 함수 안의 메타몽 파트와 동일하므로

    그냥 즉발특성 함수를 호출하면 된다.

     

     

        //필드에 있지않은 메타몽의 변신 상태와 pp 초기화
        for (int i = 1; i < 4; i++) {
            if (p[i][0][11] == "메타몽") {
                if (i != pp) {
                    p[i][0][0] = "메타몽";
                    p[i][0][12] = "괴짜";
                    for (int j = 1; j < 5; j++) {
                        ppp[i][j] = 5;
                    }
                }
            }
            if (s[i][0][11] == "메타몽") {
                if (i != ss) {
                    s[i][0][0] = "메타몽";
                    s[i][0][12] = "괴짜";
                    for (int j = 1; j < 5; j++) {
                        sss[i][j] = 5;
                    }
                }
            }
        }

    그리고 메타몽은 변신할때마다 현재 pp가 5로 초기화된다.

    "후처리" 함수에서

    필드에 있지 않은 메타몽들의

    이름은 메타몽으로, 특성은 괴짜로, 그리고 pp는 5로 계속 변경해준다.

     

     

    스카프도 구현했는데

    이는 가이오가 구현때 설명하기로 하고,

    메타몽덕분에 신나게 버그찾은 이야기로 마무리하고자 한다.

     

     

     

    포켓몬 배틀 시뮬이 얼추 완성되고

    버그도 거의 나타나지 않을때

    갑자기 미친 버그가 발생했다.

     

    랜드로스로 유턴을 썼는데, 교체가 되지 않는다.

    이게 또 신기한게

    "~~은 주인에게 되돌아갔다" 라는 텍스트는 제대로 뜨는데

    교체만 되질 않았다.

     

    근데 이게 또 상대 포켓몬 유턴은 잘된다.

    뭐가 문제인지 "교체" 함수를 하나하나 살펴보고,

    이리 저리 변수값을 출력해봤는데 문제가 보이질 않았다.

    애초에 건든게 딱히 없는데 갑자기 버그가 생기니 미칠 노릇이였다.

     

    근데 갑자기 생각난게,

    이거 설마 메타몽 떄문인가하고

    메타몽을 다른 포켓몬으로 바꾸니 버그가 없어졌다.

    상대방의 유턴은 잘 성공한 이유가 상대 포켓몬 목록엔 메타몽이 없어서 그런거였다 

     

    이제 메타몽 관해서 이리저리 살펴보다 찾은 문제점이,

     

    string 랜드로스[one][two] = {
        {"랜드로스", "땅", "비행", "164", "197", "112", "110", "100", "157", "n", "n","랜드로스", "위협", "생구"},
        {"지진", "땅", "100", "100", "10", "물리", "null", "null", "null", "null", "null", "n", "y", "y", "부가효과 없음"},
        {"칼춤", "노말", "-", "-", "5","변화", "랭크", "100", "공격", "2", "자신", "n", "y", "y", "사용자의 공격을 2랭크 올린다."},
        {"유턴", "벌레", "70", "100", "20", "물리", "교체", "100", "null", "null", "null", "n", "y" , "y", "공격 후 아군 포켓몬과 교체한다."},
        {"암석봉인", "바위", "60", "95",  "15", "물리", "랭크", "100", "스피드", "-1", "상대", "n", "y", "y", "상대방의 스피드를 1랭크 떨어뜨린다."},
        {"n", "n", "n", "n", "n", "0", "n"},
        {"얼음"},
        {"물"},
        {"격투", "벌레", "독"},
        {},
        {"땅", "전기"},
        {"공격력","특수공격력","방어력","특수방어력", "스피드", "0","0","0","0","0", "197", "112", "110", "100", "157"},
    };
    string 메타몽[one][two] = {
        {"메타몽", "노말", "null","155","68","68","68","68","53","n","y","메타몽", "괴짜", "스카프"},
        {"변신", "노말","-","-","5", "변화","-","-","-","-","-","-","y","y","상대 포켓몬으로 변신한다."},
        {"-", "-","-","-","5", "-","-","-","-","-","-","-","-","n","-"},
        {"-", "-","-","-","5", "-","-","-","-","-","-","-","-","n","-"},
        {"-", "-","-","-","5", "-","-","-","-","-","-","-","-","n","-"},
        {"n", "n", "n", "n", "n", "0", "n"},
        {""},
        {"격투"},
        {""},
        {""},
        {"고스트"},
        {"공격력","특수공격력","방어력","특수방어력", "스피드", "0","0","0","0","0", "68", "68", "68", "68", "53"},
    };

    위에서 말했듯이

    메타몽의 데이터 배열은 다른 포켓몬들보다 양이 적다.

    그렇기에 쓸데없는 욕심? 고집이 생긴 나는 메타몽의 데이터 배열에 최대한 적은 값을 넣고자하였고,

    메타몽의 체력값을 넣어놓지 않았다.

     

    그도 그럴게 체력값은 상대방의 체력값을 카피한 다음, 155라는 메타몽의 고유 체력 값으로 수정하니까,

    어차피 상대방 데이터를 카피하느랴 없어질 값이라 생각해서 데이터 배열에 넣지 않았다.

     

    근데 "교체" 함수는 다른 두 포켓몬의 체력 값을 참조한다.

    다른 두 포켓몬이 살아있어야 교체를 하는데 이는 포켓몬들의 현재 체력값으로 알 수 있으니까.

     

    즉 교체 대상에 메타몽이 존재하는데,

    해당 메타몽은 아직 상대방을 카피한 적이 없으므로 체력 데이터가 존재하지 않는다.

    즉 이 메타몽이 살아있는지 뒤졌는지 확인할 방법이 없어서

    그래서 교체 함수가 호출되어도 교체가 진행되지 않은것이였다.

     

    그렇게 랜드로스의 유턴이 안되는 버그는,

    메타몽의 데이터배열에 체력값을 추가하는것으로 해결되었다.

     

    아무것도 안했는데 갑자기 버그가 발생한 이유는,

    친구가 구경이나 해보자해서 exe 파일로 만들어서 전송했고,

    이때 친구가 원하는 포켓몬 조합으로 수정해줬는데

    그때 2번째 포켓몬이 메타몽이였다.

    메타몽이 1번 포켓몬일때만 체크하고

    2번이나 3번일때는 별도로 체크하지 않은 문제였다.

     

    체크 하더라도 1번 포켓몬이 유턴을 지닌 랜드로스여야하니,

    정말 낮은 확률로 발생하는 버그였고 

    그게 정말 운 좋게도(?) 발생한것이었다.

     

     

    가끔 게임 회사의 버그 이야기를 들어보면

    a에서 버그가 발생한게 전혀 다른 파트인 b때문이였다는걸 듣고

    왜 전혀 연관 없는 부분때문에 다른 부분에서 버그가 발생하나 궁금했는데,

     

    온라인 게임에 비하면 훨씬 간단한 내 프로그램에서도

    이와 같은 문제가 발생하다보니

    드디어 왜 그런 일이 일어나는지

    약간이나마 공감하게되었다.

     

     

     

     

    구현 완료한 모습

     

     

     

     

     

Designed by Tistory.