ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 여덟, 아홉번째 포켓몬 이벨타르 & 흑마렉스 구현 (흡혈)
    포켓몬 배틀 구현 2022. 3. 23. 02:08

    이번에 구현할 포켓몬은 2마리, 이벨타르와 흑마렉스다.

     

    https://pikalytics.com/pokedex/homebss/yveltal

     

    Yveltal Series 12 Battle Stadium Singles Stats Pokédex | Pokémon | Pikalytics

    Life Orb 78.500% Assault Vest 9.300% Weakness Policy 3.400% Black Glasses 3.400% Choice Scarf 1.200% Maranga Berry 0.700% Lum Berry 0.700% Heavy-Duty Boots 0.500% Choice Band 0.500% Choice Specs 0.300%

    pikalytics.com

    이벨타르

    의외로 픽률이 5위로 되게 높다.

    주 기술배치는 악의파동 열풍 기습 데스윙.

    여기서 기습만 물리기인데

    일단 쌍두형으로 구현해놓고

    나중에 물리/특수 특화 이벨타르를 따로 구현해봐야겠다.

     

    스킬에서 구현해야할것은

    악의파동의 "풀죽음"

    그리고 데스윙의 "흡수"

     

    풀죽음은 어디서 구현해야하나... 

    이것도 "명중"함수에 구현해야하나 싶었지만

    풀죽음은 선공을 맞은 후공 포켓몬이 반격을 못하는,

    즉 후공에게만 발동되는 상태이상이므로

    메인함수에 구현하기로 했다.

     

    bt[0] = 326;//공격을 맞은 포켓몬의 기절 여부
            bt[1] = 722;//공격을 한 포켓몬의 기절 여부
            if (speed == 1) { //플레이어가 더 빠를때
                if (act == 1) { 명중(p, s, ps[0], ps[1], number, attack, bt, 1, slife, ps, plife, speed, sattack, dmg, snumber); }
                //act가 1일때 = 스킬을 사용했을때 명중 함수 실행
                //명중 함수는 스킬의 명중 여부를 체크하고 배틀을 진행하는 함수.
                if (bt[0] == 1051 && sact == 1) { cout << "상대 " << s[ps[1]][0][0] << s1(s,ps[1])<<"풀이 죽어 움직일 수 없었다!\n"; }
                else if (bt[0] != -1 && sact == 1) { 명중(s, p, ps[1], ps[0], snumber, sattack, bt, 0, plife, ps, slife, speed, attack, dmg, snumber); }
                //bt[0]이 -1이 아닐때 = 후공인 포켓몬이 선공을 맞고 기절하지 않았을때
                //sact == 1 스킬 사용시 반격.
            }
            else if (speed == 0) { // 상대가 더 빠를때
                if (sact == 1) { 명중(s, p, ps[1], ps[0], snumber, sattack, bt, 0, plife, ps, slife, speed, attack, dmg, snumber); }
                if (bt[0] == 1051 && act == 1) { cout << p[ps[0]][0][0] << s1(p, ps[0]) << "풀이 죽어 움직일 수 없었다!\n"; }
                else if (bt[0] != -1 && act == 1) { 명중(p, s, ps[0], ps[1], number, attack, bt, 1, slife, ps, plife, speed, sattack, dmg, snumber); }
                //반대로 진행
            }

     

    선공에서 풀죽음이 터졌을때, 배틀 트리거 값을 1051로 한다.

    이후 후공이 반격하기 전에, 배틀 트리거 값이 1051이면 풀죽음이 터진것이므로

    반격을 하지않고, "풀이 죽어 움직일 수 없다!"라는 텍스트만 출력한다.

     

    if (a[aa][skillnumber][6] == "풀죽음" && rd < stoi(a[aa][skillnumber][7])) {
            bt[0] = 1051;
        }

    공격했을때 풀죽음이 발동하는 것은,

    공격한 다음에 발생하는 이벤트이므로

    "부가효과" 함수에 간단히 추가해준다.

     

    그러면 풀죽음 구현 끝!

     

     

    다음 구현해야 할 것은 데스윙의 "흡수"로

    상대에게 준 데미지의 3/4 만큼 회복한다.

    이 역시 공격한 다음 발생하는 이벤트이므로 "부가효과" 함수에서 처리한다.

    if (  a[aa][skillnumber][6] == "흡수"   &&   alife[aa] != stoi(a[aa][0][3])  ) {

    흡수 효과가 발생할때는 공격측이 사용한 스킬의 부가효과가 "흡수"이고

    공격측이 풀 체력이 아닐때.

    풀피면 회복량이 0이므로 발동되지 않는다.

     

     

    if (s == 0) printf("상대 ");
            cout << a[aa][0][0] << s1(a, aa);
            if (s == 1) printf("상대 ");
            int hill = damage * 3 / 4;
            if (alife[aa] + hill > stoi(a[aa][0][3]))
                hill = stoi(a[aa][0][3]) - alife[aa];
            cout << b[bb][0][0] << "에게서 체력을 흡수했다! (" << alife[aa] << "+" << hill;
            alife[aa] += hill;
            cout << "=" << alife[aa] << ")\n";

    회복량은 적에게 가한 damage의 3/4.

    적에게 준 damage 값은 함수 인자로 받으므로 쉽게 구현 가능하다.

    다만 문제는..

     

    지금까지 체력 이상의 데미지를 받아 체력이 음수가 되어도

    어차피 기절한것은 똑같으니까 딱히 별도의 처리를 하지 않았는데,

    이러면 체력이 1 남은 상대한테 흡수 공격을 가하면

    1의 체력만 회복되어야하는데 그 이상의 체력이 회복되어버린다.

     

    그렇기에 지금까지 데미지를 주는 코드에 해당 데미지가 현재 체력 이상이면

    현재 체력만큼만 데미지를 주도록 대대적으로 수정했다(...)

     

    그리고 실제 포켓몬 인게임에선

    흡수를 한 다음 반동 데미지를 입으므로, 이에 맞춰 해당 부가효과를 다른 반동 부가효과들보다 앞에 둔다.

    이 역시 사소하지만 지키지 않으면 인게임과 다른 결과가 벌어질수있으므로 주의해야한다.

     

     

     

    그러면 이벨타르의 다른 스킬, 기습과 열풍은 이미 에이스번, 썬더에서 구현했고

    아이템 생구 역시 썬더에서 구현해놨으므로

    마지막으로 특성 "다크오라"만 구현하면 된다.

    이는 필드를 "다크오라" 상태로 만들어

    악타입 스킬의 위력을 4/3배로 한다.

    특이한 점이라면 자신 뿐만 아니라 상대의 악타입 기술 위력도 4/3으로 증가한다.

     

    이 역시 "필드"에 관한 특성이므로

    필드 상태를 처리하는 ps 배열에 이를 처리하는 칸을 추가로 할당해야하나 고민했는데...

    어차피 저 특성은 이벨타르가 필드 위에 존재할때만 발동되는 효과이다 

    즉 공격을 할때, 공격한 쪽이나 맞는 쪽 둘중 하나는 특성이 "다크오라"여야한다!

    그러므로 따로 ps 배열에 값을 할당에 필드를 확인할 필요 없이,

    그냥 공격한 쪽과 맞는 쪽의 특성을 확인하면 된다!

     

    좋게 말하면 효율적으로 구현하는 방법이고

    나쁘게 말하면 꼼수가 늘어가고 있다.

    if ((p[pp][0][12]=="다크오라" || s[ss][0][12] == "다크오라") && skilltype == "악") {//필드가 다크오라일때 악타입 스킬의 위력 1.33배
                damage = damage * 4 / 3;
            }

    이는 공격의 데미지를 변화시키므로 "위력증감" 함수에서 처리한다.

    공격측이나 맞는 쪽의 특성이 다크오라고, 이떄 공격 스킬이 "악"타입이면

    위력을 4/3으로 한다.

     

    그러면 간단하게 이벨타르 구현 끝!

    구현 완료된 모습

     

    이벨타르만 하기엔 너무 짧고,

    어차피 내용도 겹치므로

    흑마렉스도 같이 구현해버리자.

     

    https://pikalytics.com/pokedex/homebss/calyrex-shadow

     

    Calyrex-Shadow Series 12 Battle Stadium Singles Stats Pokédex | Pokémon | Pikalytics

    Focus Sash 48.100% Choice Scarf 27.800% Choice Specs 9.200% Life Orb 6.900% Leftovers 5.100% Spell Tag 1.100% Lum Berry 0.500% Light Clay 0.400% Petaya Berry 0.200% Rocky Helmet 0.100%

    pikalytics.com

    흑마렉스의 픽률은 6위.

    상위권인건 예상대로이지만

    이벨타르가 흑마렉스보다 순위가 높다니, 예상 외다.

     

    주로 배치하는 스킬 순위는

    아스트랄비트, 사이코쇼크, 드레인키스, 트릭, 나쁜음모, 사이코키네시스, 리프스톰 순이다.

     

    일단 아스트랄 비트는 필수 스킬이므로 채용.

    사이코 쇼크와 드레인 키스도 좋은 스킬이므로 채용하고,

    트릭을 좀 고민했다.

     

    트릭은 자신과 상대의 아이템을 바꾸는 기술로,

    아이템을 구애안경

    -특공이 1.5배 오르는 대신 처음 사용한 스킬만 사용할 수 있다.

    즉 특수 어태커가 아니면 매우 방해되는 아이템-

    으로 하고 상황에 따라 흑마렉스 자신이 쓰거나 상대방에게 넘겨버린다.

     

    근데 그러기엔 구애안경 채용율이 10% 밖에 안된다.

    즉 흑마렉스는 트릭을 채용하지 않는 경우가 대부분이지만,

    그 픽률이 여러 스킬로 분산되어 트릭의 픽률이 높아보이는 것이다.

    일명 통계의 함정이다.

     

    이러한 구애트릭 형태는 따로 구현해보도록하고,

    일단은 무난히 채용할 수 있는 다른 스킬들을 보기로했다.

     

    나쁜음모 = 특공 2랭크 상승 버프스킬

    이전에 구현한 칼춤(공 2랭 상승)와 사실상 똑같으므로 생략

    사이코키네시스 = 에스퍼 타입 특공기. 사이코 쇼크와 겹치므로 생략

    그렇기에 리프스톰을 채용했다.

     

     

    채용할 스킬들을 정했으니 이제 구현해야할것을 알아보자면

     

    1.아스트랄 비트 = 부가효과 없음

    2.드레인 키스 = 흡수기 = 위에서 했음

    3.리프스톰 = 사용시 특공 2랭 다운 = 이전에 했음

     

    4.사이코 쇼크

    사이코 쇼크는 조금 독특한 기술인데,

    특수 기술이지만 상대방의 물리 방어력을 참조한다.

     

    데미지를 계산할떄,

    물리기면 사용자의 물리 공격력과 방어 측의 물리 방어력을,

    특수기면 사용자의 특수 공격력과 방어 측의 특수 방어력을 계산에 참조하는데,

    사이코 쇼크는 사용자의 특공과 방어측의 물방을 참조하는, 독특한 기술이다.

     

    포켓몬 배틀을 보면,

    일명 "물리막이", "특수막이"로써

    물리 방어력이나 특수 방어력중 한쪽을 집중하여 올린 뒤 탱커로 사용한다.

     

    즉 흑마렉스는 물리 막이한테는 다른 특수기들로,

    특수 막이한테는 사이코 쇼크로 공격하면 되므로

    어태커로써 매우 좋은 장점을 지니고 있다 할 수 있다.

     

    뭐 설명은 여기까지하고 구현을 어떻게 하냐면...

     

    if (a[aa][number][5] == "물리") { tm = 4; mt = 6; }
    else if (a[aa][number][5] == "특수") { tm = 5; mt = 7; }
    
    if (a[aa][number][0] == "사이코쇼크") { tm = 5; mt = 6; };

     

    데미지 계산 함수에서

    사용 스킬이 물리면 물공=4 물방=6,

    특수기면 특공=5 특방=7을 참조하는데

     

    여기에 스킬 이름이 사이코쇼크이면

    특공=5 물방=6을 참조하는 if문을 하나 추가해주면 끝.

    아주 간단하게 구현 완료다.

    아이템 기띠는 옛날에 구현했고,

    마지막으로 특성만 구현하면 끝난다.

     

     

     

    보면 알겠지만

    흑마렉스는 흑마 위에 버드렉스가 타고있는 모양새이다.

    보통 이걸 "탑승"이라고 하지만 포켓몬에선 "합체"인가보다

    쨌든 그렇기에 흑마렉스는 특성을 2개 지니고있다.

     

    첫번째 특성은 상대방이 열매를 먹지 못하게 하는 "긴장감"

    두번째는 적을 쓰러뜨리면 특공이 1랭크 상승하는 "흑의 울음"

     

    근데 "긴장감"은 아직 열매를 도구로 지니는 포켓몬이 존재하지 않아서(...) 현재는 구현할수없고

     

    if (blife[bb] <= 0) {
                    //공격을 맞고 체력이 0 이하가 된 경우
                    if (s == 1) cout << "상대 ";
                    cout << b[bb][0][11] << s1(b, bb);
                    cout << "쓰러졌다!\n";
                    bt[0] = -1;
                    //상대가 기절했으므로 bt[0] = -1, 상대가 기절한 뒤 행동하는걸 막기위해 사용
                    if (a[aa][0][12] == "흑의울음") {
                        cout << "[특성 흑의울음]\n";
                        랭크(a, aa, "특공", 1, s);
                    }
                }

    흑의 울음은 데미지 계산을 진행하는 "데미지" 함수에서

    적을 쓰러뜨렸을때,

    이때 공격측의 특성이 "흑의울음"이면

    공격측의 특성을 1랭크 올리도록 랭크 함수를 호출한다.

     

    그러면 두 포켓몬 구현 완료!

Designed by Tistory.