-
"부가효과" 함수의 구현포켓몬 배틀 구현 2022. 3. 16. 13:46
void 부가효과(string a[][one][two], int skillnumber, string b[][one][two], int aa, int bb, int s, int alife[], int blife[], int ps[], int bt[], int damage) {
배틀 파트의 마지막 함수, "부가효과" 함수이다.
저번 글에서 말했듯이
"위력증감" 함수는 공격 이전에 발생하는 이벤트를,
"부가효과" 함수는 공격 이후 발생하는 이벤트들을 처리하는 함수이다.
int rd = rand() % 100; // 공격시 발동하는 효과 랜덤 카운터 if (blife[bb] > 0) {//상대방에게 발동되는 부가효과는 상대방의 체력이 0이 아닐때만 발생. if (a[aa][skillnumber][6] == "화상" && b[bb][5][0] == "n" && rd < stoi(a[aa][skillnumber][7]) && b[bb][0][1] != "불꽃" && b[bb][0][2] != "불꽃") { //스킬의 부가효과가 "화상"이고, 적이 상태이상에 걸리지 않았으며 적이 불타입이 아닐때 부가효과 확률에 의해 적이 화상이 걸림 if (s == 1) cout << "상대 "; cout << b[bb][0][11] << "은 화상을 입었다!\n"; int atk = stoi(b[bb][0][4]); atk /= 2; string aattkk = to_string(atk); b[bb][0][4] = aattkk; // 상대 공격력을 절반으로 깎음 b[bb][5][1] = "y"; //화상 여부 y 처리 b[bb][5][0] = "y"; //상태이상 여부 y 처리. 다른 상태이상과 중복되지 않게 하기 위함 } }
일단 rd라는 0~99의 임의의 수를 뽑는다.
적에게 부가효과가 터질지 여부는, 이 rd의 값에 따라 결정된다.
화상 확률이 10%라면, rd가 0~9일때 화상이 걸리고 10 이상은 화상에 걸리지 않는다.
그리고 일단, 공격을 맞은쪽에게 발생하는 부가효과를 먼저 처리해야한다.
이는 맞은쪽이 기절했으면 발생하지 않으므로, blife[bb]>0 이란 조건을 앞에 추가한다.
첫번째 구현한 상태이상은 화상인데,
조건이 정말로 많다.
1.a[aa][skillnumber][6] == "화상"
공격측이 사용한 스킬의 6번칸의 값이 "화상"일때,
즉 사용한 스킬의 부가효과가 화상일때이다.
2.b[bb][5][0] == "n"
맞은쪽 포켓몬의 [5][0]값이 "n"일때,
이는 맞은쪽이 상태이상에 걸리지 않았을때를 의미한다.
포켓몬은 한번에 하나의 상태이상만 걸릴 수 있고,
기존에 이미 상태이상에 걸려있다면 다른 상태이상이 걸리지 않는다.
3.rd < stoi(a[aa][skillnumber][7])
stoi(a[aa][skillnumber][7])은 스킬의 7번칸 값의 int 값으로 부가효과가 터질 확률이다.
rd가 해당값보다 작으면 부가효과가 발생한 것이다.
4.b[bb][0][1] != "불꽃" && b[bb][0][2] != "불꽃"
맞은 쪽의 타입이 불꽃타입이 아닐때.
불꽃타입 포켓몬은 화상에 걸리지 않는다.
이렇게 4개의 조건을 전부 통과해야 상대방에게 화상이 걸린다.
이제 내부 코드를 살펴보자면
if (s == 1) cout << "상대 "; cout << b[bb][0][11] << "은 화상을 입었다!\n"; int atk = stoi(b[bb][0][4]); atk /= 2; string aattkk = to_string(atk); b[bb][0][4] = aattkk; // 상대 공격력을 절반으로 깎음 b[bb][5][1] = "y"; //화상 여부 y 처리 b[bb][5][0] = "y"; //상태이상 여부 y 처리. 다른 상태이상과 중복되지 않게 하기 위함 }
일단 상대는 화상을 입었다는 텍스트를 출력한다.
화상은 상대방의 공격력을 1/2로 깎는 효과가 존재하므로,
맞은측 포켓몬의 [0][4]값, 즉 공격력을 가져와 절반으로 깎은뒤 다시 저장한다.
그리고 상태이상에 걸린 여부 [5][0]과
화상에 걸린 여부 [5][1]을 "y"로 바꿔준다.
[5][0]은 다른 상태이상에 추가로 걸리지 않도록,
[5][1]은 이후 화상 데미지를 처리하기 위해서 필요하다.
if (p[ps[0]][5][1] == "y" && plife[ps[0]]>0) { cout << p[ps[0]][0][11] << s1(p, ps[0]) << "화상 데미지를 입었다! ("; cout << plife[ps[0]] << "-" << stoi(p[ps[0]][0][3]) / 16 << "="; plife[ps[0]] -= stoi(p[ps[0]][0][3]) / 16;//화상 데미지는 최대 체력의 1/16 cout << plife[ps[0]] << ")\n"; if (plife[ps[0]] <= 0) {//화상 데미지로 체력이 0이 된 경우 cout << p[ps[0]][0][11] << s1(p, ps[0]) << "쓰러졌다!\n"; }
화상 데미지는 "후처리" 함수,
배틀이 끝나고 다음 턴이 시작되기 전에
처리해야할 이벤트들을 처리하는 "후처리" 함수에서 처리된다.
필드 위 두 포켓몬이 화상상태일때, 즉 p[ps[0]][5][1]이 "y"일때
최대 체력의 1/16만큼 데미지를 준다.
화상을 "거는" 부분과 공격력을 깎는 부분은 "부가효과" 함수에서,
화상으로 인한 데미지는 "후처리" 함수에서 나눠서 구현했다.
if (a[aa][skillnumber][6] == "독" && b[bb][5][0] == "n" && rd < stoi(a[aa][skillnumber][7]) && b[bb][0][1] != "독" && b[bb][0][2] != "독" && b[bb][0][1] != "강철" && b[bb][0][2] != "강철") { // 독은 상대가 독, 강철 타입이 아닐때 발동 if (s == 1) cout << "상대 "; cout << b[bb][0][11] << "은 독에 걸렸다!\n"; b[bb][5][2] = "y"; b[bb][5][0] = "y"; //독과 화상으로 인한 데미지는 "후처리"함수에서 따로 처리됨. }
다른 상태이상들은 비슷하다.
상태이상 "독"의 경우 마찬가지로
1.스킬의 부가효과가 "독"이고
2.상대방이 상태이상에 걸리지 않았으며
3.부가효과 확률값보다 rd값이 작고
4.맞은쪽의 타입이 독타입이 아닐때
5.그리고 추가로 맞은쪽의 타입이 강철타입이 아닐때 발생한다.
독은 독과 강철 두 타입에게 무효된다.
내용물 역시 비슷하다.
독에 걸렸다는 텍스트를 출력하고
[5][2]와 [5][0]값을 "y"로 바꾼뒤 데미지는 "후처리"함수에서 따로 실행한다.
마비는 상대가 전기타입이 아닐때, 스피드를 절반 깎고
얼음은 상대가 얼음타입이 아닐때를 조건으로 추가한다.
if (a[aa][skillnumber][6] == "혼란" && b[bb][5][4] == "n" && rd < stoi(a[aa][skillnumber][7])) { //혼란은 다른 상태이상과 중첩되므로 조건이 약간 다름. if (s == 1) cout << "상대 "; cout << b[bb][0][11] << "은 혼란에 빠졌다!\n"; b[bb][5][4] = "y"; int cr = rand() % 4 + 2; b[bb][5][5] = to_string(cr); //혼돈이 걸릴 턴 수. 2부터 5까지 랜덤 값. }
혼란은 다른 상태이상과 중첩된다.
즉 [5][0]값이 어떤 값이든 상관없고,
상대가 이미 혼란에 걸리지 않았을때, [5][4]=="n"일때가 조건이다.
또한 2부터 5의 랜덤한 값중 하나를 뽑는데,
이는 혼란이 지속되는 턴이다.
혼란은 1~4턴동안 지속되고,
일단 카운트를 깎은 다음 혼란 상태이상을 처리하기에 2~5의 값으로 했다.
if (a[aa][skillnumber][6] == "랭크" && rd < stoi(a[aa][skillnumber][7]) && a[aa][skillnumber][10] == "상대") { //스킬의 부가효과가 상대방의 랭크 변화인 경우 랭크(b, bb, a[aa][skillnumber][8], stoi(a[aa][skillnumber][9]), 0); }
마지막으로 랭크 변화는 그냥 랭크 함수를 호출하면 된다.
이는 나중에 따로 쓰도록하고
이제 공격을 맞은 쪽에게 발생하는 부가효과는 전부 처리했다.
다음은 공격을 한 쪽에게 발생하는 이벤트들을 처리해야한다.
//흡혈 부가효과는 반동 부가효과보다 우선적으로 처리해야함 if ((a[aa][skillnumber][0] == "데스윙" || a[aa][skillnumber][0] == "드레인키스") && alife[aa] != stoi(a[aa][0][3])) { //공격측이 사용한 기술이 "데스윙"이나 "드레인키스"이고, 현재 체력이 풀피가 아닌 경우 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"; }
첫번째는 흡혈,
포켓몬의 경우 흡혈을 한 다음에 반동 데미지를 입으므로
이를 반동 파트보다 먼저 처리야한다.
조건은 스킬 이름이 "데스윙", "드레인키스"일때 = 스킬 부가효과가 "흡혈"일때
그리고 현재 체력과 최대 체력이 같지 않을떄이다.
이는 풀피일때는 체력이 회복되지 않으므로 추가한 조건이다.
회복량은 상데에게 준 데미지의 3/4이고,
이는 이전 "공격스킬" 함수에서 계산한 damage 값을 인자로 받아 계산한다.
그리고 현재 체력에 회복량을 더한게 최대체력보다 높으면 최대체력 만큼만 회복한다.
이후 회복했다는 텍스트를 출력하면 끝.
if (a[aa][skillnumber][6] == "반동") { cout << a[aa][0][0] << s1(a, aa) << "반동 데미지를 입었다! ("; bandong = damage / stoi(a[aa][skillnumber][7]); //스킬 반동으로 인한 데미지는 스킬의 반동 수치에 따라 결정 if (bandong >= alife[aa]) { bandong = alife[aa]; } //반동 데미지가 현재 체력보다 높을경우 현재 체력만큼 데미지 cout << alife[aa] << "-" << bandong << "="; alife[aa] -= bandong; cout << alife[aa] << ") \n"; if (alife[aa] <= 0) { cout << alife[aa] << s1(a, aa) << "쓰러졌다!"; bt[1] = -1; return; } }
두번째는 공격한 측이 데미지를 입는 부가효과.
스킬이 반동기일때, 공격측의 지닌물건이 "생명의 구슬"일때, 방어측의 지닌 물건이 "울퉁불퉁멧"일떄
이 3가지의 경우에 공격측이 데미지를 입는다.
이는 각자 조건문으로 구현하고,
반동 데미지는 int bandong이란 값에 저장하고
해당 데미지가 현재 체력보다 높으면 현재 체력만큼만 데미지를 준다.
이로 인해 기절하면 기절했다는 텍스트와 함께 bt[1]값을 -1로 바꾼다.
이는 선공측이 반동 데미지로 기절했을때,
후공측은 공격할 대상이 존재하지 않으므로 공격이 무조건 실패하게 하기위해 사용하는 트리거이다.
그리고 공격측이 기절했으면,
공격측에게 발생하는 다른 부가효과가 발생하는것을 막기위해 바로 return하여 함수를 끝낸다.
//공격한 쪽에게 발동되는 부가효과들 if (a[aa][skillnumber][6] == "랭크" && rd < stoi(a[aa][skillnumber][7]) && a[aa][skillnumber][10] == "자신") { //스킬의 부가효과가 자신의 랭크 변화인 경우 랭크(a, aa, a[aa][skillnumber][8], stoi(a[aa][skillnumber][9]), 1); }
이 외에 공격측에게 발생하는 부가효과는 랭크변화
if (b[bb][0][12] == "정전기" && a[aa][skillnumber][11] == "y" && a[aa][5][0] == "n" && a[aa][0][1] != "전기" && a[aa][0][2] != "전기" && trd < 33) { //맞은쪽의 특성이 정전기이고, 상대가 사용한 기술이 접촉기이고, 상대가 상태이상에 걸리지 않았고 //상대가 전기 타입이 아니면 33% 확률로 상대를 마비시킴 printf("[특성 정전기]\n"); if (s == 0) cout << "상대 "; cout << a[aa][0][11] << s1(a, aa) << "마비되어 기술이 나오기 어려워졌다!\n"; int spd = stoi(a[aa][0][8]); spd /= 2; string ssppdd = to_string(spd); // 마비는 상대의 스피드를 절반으로 깎음 a[aa][0][8] = ssppdd; a[aa][5][0] = "y"; a[aa][5][3] = "y"; }
특성 정전기
*특성이 "정전기"인 포켓몬에게 접촉기로 공격하면, 33%의 확률로 마비 상태이상에 걸린다.
*자세한건 포켓몬 "썬더" 구현때 후술
if (a[aa][skillnumber][6] == "교체") { //공격 후 바로 교체하는 스킬 if (s == 1) {//내 포켓몬이 사용한 경우 cout << a[aa][0][11] << s1(a, aa) << "내 곁으로 돌아왔다!\n"; 교체(alife, aa, a, ps, b, bb);//"교체" 함수 호출 즉발특성(a, ps[0], 1, b, bb, ps); } else {//상대 포켓몬이 사용한 경우 cout << a[aa][0][11] << s1(a, aa) << "상대 곁으로 돌아갔다!\n"; 상대교체(alife, aa, a, ps, bb, b);//"상대 교체" 함수 호출 즉발특성(a, ps[1], 0, b, bb, ps); } }
공격후 바로 교체하는 "유턴"과 같은 기술
역시나 자세한건 포켓몬 "랜드로스" 구현때 설명
if (a[aa][skillnumber][6] == "풀죽음" && rd < stoi(a[aa][skillnumber][7])) { bt[0] = 1051; }
그리고 마지막 풀죽음,
풀죽음은 선공을 맞은 포켓몬에게 발생시 반격을 스킵한다.
이는 bt[0]값을 통해 메인 함수에서 처리한다.
이렇게 공격에 터지는 "부가효과" 함수까지 알아보았다.
배틀에 사용되는 함수는 전부 알아보았고,
"후처리"나 "변화스킬" 함수는 여러 처리해야할 타이밍이 같은 이벤트들을 한군데에 모아둔 함수이므로
이는 따로 알아보지 않고
각 포켓몬들의 설명글에서 써보자한다.
'포켓몬 배틀 구현' 카테고리의 다른 글
첫번째 포켓몬, 에이스번 구현 (기습, 무릎차기) (0) 2022.03.16 "교체" 함수 구현 (0) 2022.03.16 "공격 스킬" 함수의 구현 (0) 2022.03.16 "명중" 함수의 구현 (0) 2022.03.16 메인함수의 "배틀" (0) 2022.03.16