|
그동안의 예시들에서는 조건문이 하나의 구역 안에 두 개 이상 나온 적은 없었기 때문에 이 고민을 할 필요가 없었을 겁니다. 하지만 실제로는 어느 하나의 조건으로 이벤트 등의 조건이 결정되는 경우는 오히려 예외적인 경우겠죠. 따라서, 두 개 이상의 조건이 하나의 조건 구역 내에 서술되었을 때에 그 조건들 사이의 관계가 어떤 것인지는 매우 중요한 문제가 됩니다.
일단 답은 간단합니다. 어떤 조건 구역이든, 조건 구역 내에서의 기본 연산 원칙은 AND 연산입니다. AND 연산이라고 하니까 전산 쪽에 소양이 없는 분들은 좀 어렵게 느끼시겠네요. 간단합니다. 즉, 모든 조건을 만족해야만 참이 된다는 것이죠. 위의 예시에서라면, 성인이고 남성이며 수감 상태가 아니어야만 이 조건 구역이 전체로서 참이 된다는 겁니다. 이해되시죠?
별 거 아닌 내용이라고 생각하실 수 있습니다만, 지금 말씀드린 조건 구역 내에서 기본적으로 AND 연산을 한다는 규칙은 매우 중요합니다. 이 개념을 확실히 머릿속에 집어넣고 가셔야 이후의 내용, 더 나아가 여러 개의 연산자와 스코프 지시자 구역이 중첩된 복잡한 조건 구역을 해석하는 데에 무리가 없습니다. 다시 한 번 상기하시고 다음으로 넘어가겠습니다.
그런데, 이벤트를 만들다 보면 언제나 AND 연산만 사용할 수는 없습니다. A,B,C를 모두 만족하라는 식의 조건도 물론 있을 수 있겠지만, A,B,C 중 어느 하나만 만족하면 된다는 조건도 얼마든지 생각할 수 있잖아요? 이런 경우, OR 연산자를 사용하면 됩니다. 아래의 예를 보십시오.
potential = { OR = { is_adult = yes is_female = no } }
위의 예시처럼, OR 연산을 할 조건문들을 묶어주시면 됩니다. 일반적인 프로그래밍 언어와 연산자의 사용 방법이 다르므로 주의하십시오. "성인이거나 (성인이 아니라도) 남성이면" 위 조건 구역이 전체로서 참이 되는 겁니다. 두 조건 중 어느 하나만 충족하면 전체가 참인 거죠.
그런데, 모양이 어째 지난 페이지까지 열심히 공부했던 스코프 지시자와 비슷하지 않나요? 그렇게 생각하셨다면 지난 페이지까지 열심히 공부하셨기 때문이니 자신에게 칭찬 하나를 얹어주시면 됩니다. 네. 스코프 지시자는 스스로 하나의 구역을 열고 닫을 수 있었지요. 사실 구역을 이끌 수 있는(=열고 닫을 수 있는) 예약어로서 대표적인 것이 바로 스코프 지시자이긴 합니다만(그리고 그 종류와 갯수도 엄청나게 많았지요), 여기서 공부하고 있는 연산자 역시 위와 같이 하나의 구역을 이끌 수 있는 예약어입니다. 따라서, 어떤 것이 스코프 지시자이고 어떤 것이 연산자인지 알고 계셔야겠죠. OR = { } 을 보고 이건 무슨 스코프 지시자야? 하고 있으면 곤란하잖아요.
아래의 예시를 먼저 보고 시작하도록 합시다.
potential = { OR = { is_adult = yes FROM = { is_adult = yes is_female = no } } }
위 예시와 비슷한 것 같은데, 달라진 게 있습니다. OR = { } 이 이끄는 구역 안쪽에, FROM = { } 이 이끄는 또 다른 구역이 등장했습니다. 이런 경우 이 코드의 해석을 어떻게 할 것인가가 이번 절의 핵심입니다.
일단 답부터 먼저 던지고 시작하겠습니다. 연산자가 직접 이끄는 구역 내에 또 다른 구역이 등장하는 경우, 그 구역은 그 구역 전체로서 하나의 조건문과 같이 판단합니다. 현재 OR = { } 로 묶여 있는 구역 안에 조건문 하나와 스코프 지시자 FROM = { } 이 이끄는 구역 하나가 존재하는데, 이 두 개의 지위가 동등하다는 것입니다. 그 결과, OR = { } 연산자는 자신 내부에 있는 FROM = { } 이 이끄는 구역 전체가 마치 하나의 조건문인 것처럼 취급됩니다. 즉, 아래와 같이 해석된다는 거죠.
여기서 어라? 하시는 분이 분명 계실 겁니다. 왜 OR = { } 구역 내에 있는데, FROM = { } 안에 있는 두 개의 조건문의 관계가 "이고" 로 해석되는지 이해가 안 되시는 분이 분명 계실 거예요.
결론부터 말씀드리면, OR = { } 연산자는 자신의 안에 위치하는 FROM = { } 구역 내에 영향을 줄 수가 없습니다. 구역을 이끄는 연산자가 영향을 미치는 범위는 자신이 직접 이끄는 조건문(FROM = { } 이 이끄는 구역을 전체로서 하나의 조건문으로 보므로 OR = { } 의 입장에서는 구역 자체를 그냥 조건문 취급)에 한정되기 때문이지요. Crusader Kings 2 식으로 설명해 볼까요? 왕의 봉신인 공작이 있고, 그 공작의 봉신인 백작이 있는데요. 왕이 직접 백작에게 이래라 저래라 할 수 있나요? 없죠? 그것과 같은 이치입니다.
위 코드의 OR = { } 구역 안에서 OR = { } 과 직접 맞부딪치는 것은 두 가지입니다. is_adult = yes 라는 조건문과, FROM = { } 스코프 지시자가 이끄는 구역이 그것이죠. 이 둘은 하나는 구역이고 하나는 조건문이지만, OR = { } 연산자와 직접 연결되어 있다는 점에서는 같고, 따라서 이들은 OR = { } 앞에서 동등합니다. 그래서 OR = { } 연산자는(왕) 자신의 구역을 해석하면서, FROM = { } 을(공작) 만나는 순간 그 내부의 해석에 대해서는 본인은 알 바 아니라는 식으로 대응합니다. 대신 FROM 에게 "네 구역 안에 있는 객체들(백작)을 네가 통째로 해석해서 그 결과만 나에게 가져오라"고 요구하는 거죠.
그 결과, FROM = { } 이 이끄는 구역 내에서는 OR = { } 연산자가 힘을 쓰지 못하므로, 다시 원칙으로 돌아가 FROM = { } 구역 내의 여러 개의 조건문에 대한 해석 규칙은 AND 연산이 되는 것입니다. 따라서 FROM = { } 구역의 해석은 "성인이고 남성" 이라고 해석되며, FROM = { } 스코프 지시자는 이 해석 결과를 그대로 OR = { } 연산자에게 넘겨줍니다. 그리고 OR = { } 연산자는 그 해석을 전체로서 자신 구역 내에 있는 다른 조건문 또는 구역들과 동등한 지위에 놓고 판단을 하는 것입니다. 설명이 좀 장황했는데, 풀어서 설명하려다 보니 좀 길어졌으니 잘 이해해 보십시오. 그래도 이해가 안 되시면 질문하시고요.
설명을 드리다 보니 갑자기 노파심이 생겨서, 이 부분을 명확히 설명드린 후 진행해야겠다 싶은 관계로 잠시 옆길로 샜다가 다시 돌아오도록 하겠습니다.
이제 우리는 스코프 지시자와 연산자가 모두 하나의 구역 { } 을 이끌 수 있다는 사실을 압니다. 그런데, 스코프 지시자가 이끄는 구역과 그 외의 예약어가 이끄는 구역 사이에는 스코프 지시자의 해석에 있어서 중요한 차이가 발생합니다.
아래의 예시를 한 번 보시고 계속 설명드리도록 하죠. 이번 코드는 조금 복잡하고 어려울 수 있습니다.
potential = { location = { OR = { has_hospital = no port = yes owner = { is_adult = no character = PREVPREV } } is_winter = no } }
일단 본 적 없는 조건문이 하나 등장했죠?
그 외에는 사실 다 아는 조건문이고 스코프 지시자인데, 웬걸, 뭔가 해석이 삐걱거립니다. 아마 제 글을 충실하게 읽어오신 분 중 어떤 분은 위 코드의 오류를 지적하고 싶으실 수도 있어요. 제가 설명한 적이 없기 때문에, 이 모두는 타당한 반응이십니다만, 조금만 참으시고 마저 읽어보십시오. 단계적으로 해석해 보겠습니다!
해석이 잘 되셨나요? 매끄럽지 않더라도 해석이 되시는 분은 지금까지의 내용을 잘 따라오신 분입니다. 아예 해석이 안 되시는 분은 앞의 내용을 다시 공부하셔야 하고요. 그런데, 해석이 되시는 분 중에서도 PREVPREV 에 대해서 의문을 제기하시는 분이 계실지 모릅니다. 요컨대 PREVPREV 스코프 지시자의 대상은 character 조건문의 인수이므로 캐릭터여야 하는데, 위 코드에 의하면 캐릭터가 아니라 프로빈스를 가리키고 있지 않느냐는 거죠. 이것이 바로 이 절에서 말씀드리고자 하는 핵심입니다.
우리가 앞에서 배우기를, PREV 스코프 지시자는 현재 스코프 지시자의 깊이에서 한 단계를 거슬러 올라간 위치의 대상을 가리킨다고 배웠습니다. 따라서 이 경우는 PREVPREV 이므로 두 단계를 거슬러 올라가야 하죠. 자, 질문입니다. 스코프 구역의 최상위 구역을 0이라 하고, 스코프 구역의 깊이가 하나씩 깊어질 때마다 1씩을 뺀다고 합시다(다른 모더분들은 어떤 방식으로 생각하시는지 모르겠습니다만, 제 경우는 이런 식으로 계산합니다). 이 규칙에 의하면 location = { } 스코프 지시자가 이끄는 구역의 깊이는 -1이 되겠지요. 그렇다면, 문제의 PREVPREV 가 존재하는 owner = { } 구역의 깊이는 몇이 될까요? 위에서 의문을 제기하신 분들은 아마 -3이라고 답하셨을 텐데, 아닙니다. -2 입니다. 왜?
스코프 지시자 구역의 깊이를 계산할 때는 오직 스코프 지시자가 만드는 구역만을 계산해야 합니다. OR = { } 은 연산자일 뿐 스코프 지시자가 아니므로, OR = { } 내부의 스코프 지시자의 대상이 바뀌지 않습니다. 따라서 스코프 지시자 구역의 깊이를 계산할 때는 OR = { } 은 없는 것으로 치고 계산을 하는 거죠. 그렇다면, owner = { } 내에서 PREV 가 사용된 경우, 이 스코프 지시자가 가리키게 되는 현재 스코프 대상의 바로 윗 단계는 OR = { } 이 아닌 막바로 location = { } 구역이 되는 것입니다. 여기에선 PREVPREV 가 쓰였으므로 2단계 위로 올라가면 location = { } 구역보다 하나 더 위인 기본 스코프 지시자 ROOT 를 가리키게 되는 거죠.
스코프 지시자를 설명하면서는 구역의 깊이를 설명드리면서 오직 스코프 지시자가 만드는 구역의 깊이만을 놓고 설명을 드렸습니다. 그 때는 제가 그것밖에 가르쳐 드리지 않았으니까요. 그러나 이제는 구역을 이끄는 예약어가 스코프 지시자 외에도 존재한다는 것을 배우셨으므로, 이제부터는 단순한 "구역의 깊이"와, "스코프 지시자 구역의 깊이"를 구분하도록 합시다. 앞의 예를 가지고 다시 한 번 복습을 해 보죠. 아래 그림을 보십시오.
정리하면 이렇습니다. 단순히 구역의 깊이를 계산할 때는 종류에 관계 없이 하위 구역이 열릴 때마다 하나씩 깊이가 깊어지지만, PREV 스코프 지시자와 연계되는 스코프 지시자 구역의 깊이를 계산할 때는 오직 스코프 지시자가 생성한 구역의 깊이만 따져 계산한다는 것입니다. 단순 구역의 깊이는, 현재 구역에서 동등한 레벨에 있는 예약어 또는 구역이 무엇인지를 찾는 데에 활용합니다. 따라서 연산자로 묶인 구역에서 그 연산자가 영향을 끼치는 조건문을 확인하기 위해서는 단순한 구역의 깊이를 확인해야겠죠. 스코프 지시자 구역의 깊이는 PREV 스코프 지시자가 가리키는 대상이 어떤 것인지를 판단하기 위해서만 의미가 있습니다. 이 의미 차이를 설명하기 위해서 이런저런 예를 들어 봤는데, 설명이 잘 되었는지 모르겠습니다. 너무 어렵고 장황해 진 게 아닌가 싶기도 합니다.
독자에 따라서는 상당히 난해할 수 있는 내용이기도 한지라, 이번 페이지는 여기쯤에서 끊고 다음 페이지에서 조건문과 조건 구역에 관한 내용을 계속 살펴보겠습니다.
일단 눈에 띈 게 있어서 다시 원고를 잡긴 했습니다만, 1회의 글을 다듬고 내용을 추가하고 수정하는 데만 몇 시간씩 걸리다 보니, 이걸 과연 얼마나 더 할 수 있을지 의문이긴 합니다. 아무튼 하는 데까진 해 보겠으니, 또 중단되면 이후의 내용은 네이버 카페의 카페북으로 계속 이어서 보아주시기 바랍니다. 저도 2.6 ~ 2.7 이후로는 모딩에 거의 전혀 손을 대지 못했기 때문에 최신의 내용에 대해서는 거의 무지합니다.. ㅠㅠ
(최종 업데이트: 2018. 09. 24, 대응 버전: 무관)
첫댓글 항상 잘보고있습니다..
타키투스님 진심 오랜만이네요^^
타키투스님 히스토리 1년1월1일 버그 어떻게 고치나요? 다시 롤백해도 꺠짐
그 버그가 뭔지 모릅니다...
잘읽었읍니다