[CK2 모딩 팁]내멋대로 쓰는 Crusader King 2 모딩 매뉴얼 (7) 이벤트 파일의 구조, 이벤트의 기본 구조 (1) - 개정판 (2015/05/04 수정)
작성자tacitus작성시간15.02.13조회수3,350 목록 댓글 3내멋대로 쓰는 Crusader Kings 2 모딩 매뉴얼 - 개정판
5. 이벤트 파일의 작성
구판의 20회에 있던 이벤트 상단 이미지의 작성법이 여기로 옮겨왔습니다. 또한 각종 설명 및 이미지를 보강하고, 서술의 순서를 조금 바꾸었습니다. 그 결과 일부 설명이 다음 회로 밀렸으며, 또 다음 회에서 설명되던 내용의 일부가 앞으로 옮겨왔습니다. Fast Event Trigger 의 명칭이 Pre-Trigger 로 변경되었기 때문에 이에 맞추어 내용을 수정하였습니다.
(1) 서론
이벤트는 그냥 CKII 의 핵심이죠. 모든 사건과 사고를 일으키는 화약고.. 디시전에서 지시하는 행위를 실제로 수행하는 행동대장.. 뭐 어떻게 말해도 잘못된 말이 아닐 정도로 거의 모든 일을 다 하는 부분이 바로 이 이벤트들입니다. 이미 다룬 적이 있는 디시전과 이 이벤트까지만 이해하면 시스템 자체를 들어먹는 수준의 모딩이 아닌 일반적인 수준의 모딩은 위키의 명령어/조건문/스코프/모디파이어 목록 정도만 참조해가면서 얼마든지 만들 수 있습니다.
저도 가장 좋아하는 모딩은 시스템과 관련되는 모딩이 아니라, Way of Life 류의 소소한 일상 이벤트류의 모딩입니다.
그렇다고 해서 사생아 오브 라이프나 어쌔신 오브 라이프를 좋아한다는 건 아니예요.
그런데 말입니다. 이벤트도 사실 어렵지가 않습니다. 이벤트의 구조만 이해하고 있으면 얼마든지 응용이 가능하기 때문입니다. 앞에서 디시전 파일의 구조를 1회에 끝냈었죠? 이벤트도 아마 2회를 넘기지 않을 가능성이 큽니다. :-)
(2) 이벤트 파일의 저장 위치
이벤트 파일은 CKII 설치 폴더 이하에 events 폴더에 존재합니다. 한번 들어가 보시면 정말 많은 숫자의 이벤트 파일이 있는 것을 보실 수 있을 것입니다. 2.3.4 기준으로 120개의 이벤트 파일이 존재하네요.
이렇게 이벤트가 많다 보니, 게임을 진행하다 보면 '어, 이런 이벤트도 있었어?' 싶은 이벤트들이 정말 많이 나옵니다. 참고로, 유사한 종류의 이벤트는 같은 파일에 묶여 있기 때문에, 찾기를 원하는 이벤트와 관련되는 파일을 찾아보시면 좀 더 빠르게 원하는 이벤트를 찾으실 수 있습니다. 또한, events 폴더 내에 event_id.txt 파일을 열어보시면 이벤트 ID 및 해당 이벤트 ID 에 해당하는 이벤트의 종류를 대략적으로 기록해 둔 내용을 확인하실 수 있습니다. (자세한 건 아니고, 이벤트 몇 번부터 몇 번까지는 어떤 이벤트다 뭐 이런 정도의 주석입니다.)
첫 회에 말씀드린 것처럼, 모드 파일의 폴더 구조는 CKII 설치 폴더의 구조와 동일하므로, 본인이 작성한 모드의 이벤트 파일도 모드 폴더 이하에 events 폴더를 만들고 거기에 넣어두시면 됩니다. 이 폴더 내에 들어 있는 모든 .TXT 파일은 이벤트 파일로 취급되므로 파일명은 정하고 싶은 대로 정하셔도 됩니다. 다만 원본 폴더 내의 파일 이름과 겹치면 안 된다는 점은 이미 알고 계시겠죠?
(3) 이벤트 파일을 작성할 때 주의할 점
- 몇 번째 말씀드리지만 가장 중요한 것은, 원본 폴더의 이벤트 파일명과 파일 이름이 겹치면 안 된다는 것입니다. 의도적으로 겹치게 하는 경우도 있습니다만, 이건 그 파일을 완전히 대체할 때만 그렇게 합니다. 그런 경우에 원본의 내용을 살리고 싶다면 원본의 내용도 해당 파일 내에 옮겨 두어야 합니다.
- 이벤트 파일의 최선두에는 항상 namespace 를 기록하도록 합시다. 이에 대해서는 구조 부분에서 다시 말씀드릴께요.
- 이벤트 파일의 ID 는 원본 파일에 보시면 숫자만으로 구성되어 있는 경우가 많을 것입니다. 그러나 모드의 경우에는 이벤트 ID는 반드시 네임스페이스를 붙여서 사용하시는 것을 권장합니다. 바로 위의 내용과 함께 구조 부분에서 다시 말씀드리겠습니다.
- 주석을 잘 달아둡니다. 이게 뭐하는 이벤트인지, 그리고 이벤트마다 기본 스코프(FROM, ROOT, FROMFROM 등 대상이 고정된 기본 스코프 지시자)가 누구를 의미하는지 정도는 꼭 기록을 해 두십시오. 나중에 수많은 이벤트 사이를 헤매다 보면 이게 누구였더라 하고 한참을 찾는 사태가 벌어집니다. 멍한 상태에서 수정하다가 FROM 과 ROOT 를 바꿔적는 일도 비일비재하고요. (모더만 그런 게 아닙니다. 파라독스사의 개발자들도 이런 실수를 저질러서 버그를 내는 사례가 있습니다.)
(4) 이벤트의 종류
하나의 이벤트 파일 내에는 여러 종류의 이벤트들을 적을 수 있습니다. 각각의 이벤트는 그 출력되는 모양이 차이가 있을 뿐 근본적으로는 모두 동일합니다. 필요에 따라서 골라 쓰시면 되는데, 이에 대해서 조금 적어 보겠습니다.
■ 캐릭터 이벤트
이벤트를 받는 당사자가 캐릭터입니다. character_event = { } 로 시작하며, 기본 스코프는 캐릭터가 되죠.
2.2.x 부터 long_character_event = { } 라는 이벤트 구분자가 추가되었습니다. 일반 character_event = { } 보다 더 창이 넓기 때문에, 더 많은 내용을 하나의 창에 담을 수 있습니다. 샤를마뉴의 튜토리얼 이벤트나, Way of Life 의 일부 이벤트들에 사용되었습니다.
■ 프로빈스 이벤트
이벤트를 받는 주체가 프로빈스입니다. province_event = { } 로 시작하며, 보통 특정한 프로빈스에 어떤 효과를 부여하기 위해서 사용하곤 합니다.
■ 편지 이벤트
캐릭터 이벤트와 동일합니다만, 출력되는 모양이 편지 형식입니다. 그리고 위의 캐릭터나 프로빈스 이벤트와 달리 이벤트 창 상단에 이미지가 출력되는 부분이 없습니다. letter_event = { } 로 시작합니다.
■ 내러티브 이벤트
게임 내에서 갑자기 큰 창에 뭐 마자르가 정착을 했다느니, 십자군이 일어났다느니, 기사단이 생겼다느니 하는 큰 창이 뜰 때가 있죠? 이것이 바로 내러티브 이벤트로, 내러티브 이벤트는 게임 내의 모든 캐릭터에게 보여지는 이벤트입니다. 전체에 영향을 미치는 큰 사건이 발생하는 등의 경우에 사용할 만 하겠죠. narrative_event = { } 로 사용합니다.
게임 내의 모든 캐릭터에게 보여지는 이벤트라고 썼는데, 설정이 그렇다는 거예요. 실제 원본 이벤트를 살펴보면 내러티브 이벤트도 특정 캐릭터를 향해서 발생시킵니다. 실제로 모든 캐릭터에게 이 이벤트가 일어나는 건 아닙니다.
제일 많이 쓰이는 건 단연 캐릭터 이벤트이므로, 앞으로 구조 등의 설명은 캐릭터 이벤트를 기본으로 하여 그 외의 것들에 대한 설명을 부가하는 방식으로 하겠습니다.
(5) 이벤트 파일의 구조
■ 이벤트 파일의 일반적인 구조
일반적인 이벤트 파일의 구조를 한 번 보도록 하죠.
namespace = TST character_event = { id = TST.0001 .... } character_event = { id = TST.0002 .... } province_event = { id = TST.0003 .... } character_event = { id = TST.0004 .... } character_event = { id = TST.0005 .... } letter_event = { id = TST.0006 .... } narrative_event = { id = TST.0007 .... } ...
이처럼 하나의 이벤트 파일에 여러 종류의 이벤트 객체가 혼재되어 있어도 상관이 없습니다. 뭐 보통은 character_event = { } 만 한가득인 경우가 대부분이지만요.
■ 네임스페이스, 왜 써야 하는가?
주목해야 할 부분은 첫 줄의 namespace = TST 입니다. 일단 이 네임스페이스가 뭐고, 왜 써야 하는지를 좀 말씀드리도록 할께요.
과거부터 쭉 있었던 이벤트들은 거의 대부분 이벤트 ID가 숫자로만 이루어져 있습니다. 보통 세 자리부터 네 자리를 쓰고, 어떤 경우는 다섯자리까지도 쓰곤 합니다. 최근 버전에는 여섯자리 숫자의 이벤트 ID 도 있었던 것 같군요. 그런데, 이렇게 숫자로만 ID를 쓰다 보니, 두 가지 문제가 발생합니다. 우선 숫자만으로는 이게 대체 어디쯤 걸리는 이벤트인지 유추가 안 됩니다. 연속되는 숫자로 예비 영역을 만들어두긴 합니다만, 예비영역을 다 쓰게 되면 쌩뚱맞은 번호로 점프해야 하는 상황이 벌어지기도 하죠. (다섯자리 숫자가 나온 건 그래서였던 것 같습니다.) 무엇보다 가장 문제는, 번호로만 이벤트 ID 를 적다 보니, 실수든 아니든 부지불식간에 같은 ID를 갖는 이벤트가 나타날 위험성이 있다는 것입니다. 이벤트 ID 의 충돌이 발생한다는 거죠. 특히 여러 개의 모드를 함께 사용하는 경우에 이런 위험성은 매우 높아집니다.
그래서, 숫자 앞에 어떤 문자를 정해서 이벤트를 구분해 보자는 생각을 하게 됐고, 그래서 원본 이벤트들에도 일정 시기 이후에 등장한 이벤트들은 네임스페이스를 함께 사용하곤 합니다. 예를 들면 샤를마뉴 DLC의 이벤트들은 CM 이라는 머릿말을 달고 있고, Way of Life DLC의 이벤트들은 WoL 이라는 머릿말을 사용합니다. 이렇게 네임스페이스를 붙여서 사용하게 되면, 번호가 겹치더라도 안심이죠. 예를 들면 WoL.1001 과 CM.1001 은 서로 다른 이벤트이므로 충돌이 생기지 않습니다. 앞에 붙은 문자열을 통해 이게 어디에 속하는 이벤트인지 대충 감을 잡을 수도 있게 되죠.
우리야 모딩을 하는 입장이니 저런 사정까지 알 필요는 없지만, 원본 파일의 이벤트들과의 충돌을 막기 위해서, 우리가 작성하는 모드의 이벤트의 경우도 각자 네임스페이스를 정해서 사용하면 좋다는 점은 분명하죠. 다른 모드와 함께 쓰는 경우에 모드 간 이벤트 번호 충돌을 막는데도 유용합니다. 네임스페이스까지 겹치게 쓰는 경우는 보통 생각하기 어렵잖아요? ^^
제 경우는 같은 모드 내에서도 어떤 건물 관련 이벤트냐에 따라서 네임스페이스를 다르게 쓰고 있습니다. ^^
이렇게 네임스페이스를 붙이는 경우, 해당 파일의 최선두에 namespace = XXXX 와 같이 네임스페이스를 별도로 정의를 해 둡니다. 이 파일의 모든 이벤트에는 네임스페이스 XXXX 가 붙어있다는 것을 엔진에 알려주는 역할을 하는 것 같습니다. 정확히 어디까지 이것이 영향을 미치는지는 저도 잘 모르겠습니다만, 과거에 한 번 네임스페이스를 사용한 이벤트 파일에서 namespace = 정의 구문을 빼놓았더니 게임이 크래시가 났던 적이 있었습니다.
최근 업데이트 된 위키의 설명에 의하면, 지정된 네임스페이스는 실행 단계에서 일정한 숫자로 변환이 이루어진다고 합니다. (즉, 내부적으로는 모든 이벤트 ID 는 숫자라는 거죠.) 이 변환되는 자릿수는 상당히 큰 자릿수인데, 그로 인한 내부적인 충돌을 막기 위하여 이벤트 ID 로 사용할 수 있는 숫자의 크기에는 제한이 있습니다. 이 제한은 네임스페이스를 사용하는지 여부에 따라서 달라집니다.
- 네임스페이스를 사용하는 경우, 이벤트 ID 로 사용할 수 있는 번호의 최댓값은 99,999 (즉, 5자리 숫자) 입니다.
- 네임스페이스를 사용하지 않는 경우(권장하지 않음), 이벤트 ID 로 사용할 수 있는 번호의 최댓값은 999,999 (즉, 6자리 숫자) 입니다.
(6) 캐릭터 이벤트의 구조
바로 앞에서 이벤트 파일 자체의 구조를 확인했습니다. (그냥 개별 이벤트들을 늘어놓은 수준이죠.) 이제 시선을 개별 이벤트 하나하나로 옮겨보도록 합시다. 이벤트 개체의 구조는 캐릭터 이벤트건, 편지 이벤트건, 프로빈스 이벤트건 기본적으로는 크게 다르지 않습니다. 여기서는 가장 많이 쓰이는 캐릭터 이벤트를 가지고 구조를 확인하되, 다르게 사용되는 부분은 해당 부분에서 함께 말씀드리겠습니다.
■ 캐릭터 이벤트의 구조 : 필수 구조
일반적인 캐릭터 이벤트에서, 아래의 내용은 빠지지 않고 등장합니다. 따라서, 이들 요소를 필수 구조라고 칭하겠습니다.
character_event = { id = TST.1004 desc = EVTDESC_TST_1004 picture = GFX_evt_feast option = { name = EVTOPTA_TST_1004 } }
곁다리 다 빼고, 가장 기본적인 형태의 이벤트 구조만을 남겨두었습니다.
- id : 이벤트 ID 를 의미합니다. 대외적으로 이 이벤트를 호출하는 인식표 역할을 합니다.
- desc : 이벤트에 대한 설명.. 이라고도 할 수 있지만, 해당 이벤트를 호출했을 때 이미지 밑에 나오는 나레이션(..) 이라고 이야기하는 것이 좀 더 좋겠습니다.
- picture : 이벤트가 발생했을 때 이벤트 창 상단에 나타나는 이미지를 지정합니다. 뒤에는 이미지 ID 를 적는데, 이것은 뒤에서 좀 더 자세히 말씀드리겠습니다.
- option : 이벤트가 발생했을 때 이벤트를 받은 자가 선택할 수 있는 선택지를 의미합니다. 선택지는 반드시 하나는 존재해야 합니다. (선택지가 아예 없으면 이벤트 창 자체를 끌 수가 없게 됩니다! 이벤트가 발생하면 게임 진행이 중단되고, 이벤트가 끝나야만 게임 진행이 재개되죠.) 또한 option의 갯수는 몇 개를 지정해도 상관 없습니다만, 출력되는 건 상단의 4개까지입니다. (구체적인 option = { } 내부의 구조에 대해서는 별도로 항목을 잡아서 설명드립니다. 다만 여기서는 option = { } 내부에 name = 항목을 적어준다는 사실만 체크하고 넘어가십시오.)
option 의 경우, 일부 원본 이벤트에 이것이 하나도 없는 경우도 존재는 합니다. 이에 대해서는 조금 뒤에서 설명할 기회가 있습니다.
일반적인 이벤트는, 이미지와 함께 이벤트 설명 보여주고, 넌 뭐 선택할래? 하고 물어보는 거잖아요? 그러니, 이 4가지 요소가 기본 요소가 되는 겁니다. 거칠게 말해서, 이 4가지만 지정해 줘도 이벤트의 필수요소는 다 지정된 겁니다.
제가 용어를 "필수 구조"라고 적었기 때문에, 이들 요소가 "반드시" 들어가야 하는 것으로 오해될 수 있습니다. 그건 아닙니다. 실행해서 오류가 나지 않는 정도의 최소한의 "필수 요소"는, id 와 최소한 하나의 option = { } 객체의 두 가지만 있으면 됩니다. 다만, 최소한 위 4가지 요소가 다 정의되어야 이벤트의 꼴이 산다는 거죠.
아래의 이미지는 이렇게 설정된 캐릭터 이벤트가 어떻게 출력되는지를 보여드리기 위한 예시입니다. 이미 게임을 해 보신 분들이니 알고 계시겠지만, 눈으로 다시 한 번 보시면 좀 더 와 닿으실 겁니다.
이벤트 메시지와 각각의 선택 옵션의 선택 항목 메시지들은 언어 파일에서 설정합니다.
- 이벤트 메시지는 desc = 에 지정된 값을 메시지 ID로 하여 언어 파일에 설정합니다.
- 선택 옵션의 메시지들은 option = { } 내의 name = 에 지정된 값을 메시지 ID 로 하여 언어 파일에 설정합니다.
이에 의하면, 위 예제 이벤트의 경우 언어 파일에 아래와 같이 지정이 되겠지요.
EVTDESC_TST_1004;어쩌고저쩌고...;;;;;;;;x EVTOPTA_TST_1004;싫어!;;;;;;;;x
앞으로 어떤 값이 언어 파일의 메시지 ID 로 사용된다고 말씀드리면, 이런 식으로 그 값을 언어 파일에 항목으로 집어넣은 후 메시지를 쓸 수 있구나 라는 의미로 받아들이시면 되겠습니다.
메시지 ID 의 형태는 저의 경우 원본의 형식을 따라 EVTDESC나 EVTOPT 뒤에 메시지 ID 를 덧붙이는 방식으로 설정하였습니다만, 꼭 이 방식을 따라야 하는 것은 아닙니다. 유저가 쓰기 편할 대로 규칙을 정해서 쓰면 됩니다. 또한, 만약 여러 이벤트에서 출력해야 하는 내용이 동일한 경우에는 메시지 ID 를 하나만 설정하고 이 메시지 ID를 여러 이벤트에서 사용해도 괜찮습니다.
참고로, 편지 이벤트(letter_event)의 경우, 상단 이미지가 표시되지 않으므로 picture 는 정의하지 않습니다. 정의하면 출력이 되긴 하는데, 이 경우 편지 텍스트의 상단 일부를 이미지가 가리게 되기 때문에 별로 좋지 않은 모양이 돼요. 또한, 아마도 공간의 문제 상, 캐릭터 이미지는 보낸 사람(FROM) 하나만 출력이 됩니다. 아래 예시를 보시면 확실하겠지요.
그 외 내러티브 이벤트(narrative_event = { }) 의 경우에는 캐릭터 이벤트와 모든 것이 동일하지만, 내러티브의 특성상 제목이 이벤트 메시지 출력 영역 안쪽에 들어가며, 제목의 첫 글자가 꾸밈 문자로 제목의 문두에 들어가게 됩니다. 또한 창도 크고, 글씨도 조금 작습니다. 내용이 많이 들어갈 수 있겠지요. 아래 예시를 보십시오.
제목은 위에서 보지 않았지만, title = 뒤에 설정합니다. 마찬가지로 뒤에 설정하는 내용은 언어 파일에서 내용을 설정하기 위한 메시지 ID 로 사용됩니다.
title 은 반드시 내러티브 이벤트에서만 설정이 가능한 것은 아닙니다. 캐릭터 이벤트 등에도 설정은 가능합니다. 다만, 캐릭터 이벤트 등의 경우에는 안 그래도 좁은 이벤트 메시지 출력 영역에 공간이 부족하기 때문에, 설정할 경우 이벤트 상단 이미지 영역의 위쪽에 보통의 큰 글씨로 표시가 됩니다.
참고로, 제목에서의 첫 글자가 꾸밈 박스 글자로 표시되는 것은 내러티브 이벤트에서만 보이는 특수 효과인데, 무조건 제목의 첫 글자를 물고 들어가기 때문에 이를 감안하여 적어 주십시오. 예를 들면, 예시 이미지의 "바이킹 시대의 시작" 은 언어 파일을 찾아보면 아래와 같이 설정되어 있습니다. 메시지의 앞에 V 자를 남겨 두었죠.
EVTTITLE_CM_503;V바이킹 시대의 시작;;;;;;;;;;;;x;
long_character_event = { } 에 대해서는 별도로 예시 이미지를 띄워드리지는 않겠습니다. 그냥 가볍게 감을 잡는다면, 내러티브 이벤트 크기의 창에 캐릭터 이벤트가 출력되는 것이라고 생각하시면 편합니다. 즉, 훨씬 더 많은 내용을 적을 수 있는 거죠. 다만, 제목 첫 글자의 꾸밈 글자 효과가 없으며, 제목 자체도 캐릭터 이벤트에서처럼 이벤트 상단 이미지 영역의 위쪽에 보통의 큰 글씨로 출력됩니다.
이제 기본적인 필수 구조를 살펴보았으니, 각각의 내용을 좀 더 자세히 살펴보도록 하죠.
■ 이벤트 상단 이미지 (picture = 이미지 ID)
예시에서 보았듯이, 이벤트가 발생했을 때 이벤트 창의 상단에는 일정한 이미지가 출력됩니다. 이들 이벤트 이미지들은 기본적으로 450픽셀x150픽셀 크기의 .DDS 형식의 파일로 작성되어 있으며, CKII 설치 폴더의 gfx/event_pictures 폴더에 저장되어 있습니다. 이 폴더에 들어가 보시면 많은 수의 .DDS 파일이 저장되어 있는 것을 보실 수 있습니다.
각각의 파일의 내용을 열어보고 싶으시다면 (1회에서 알려드린 편집 프로그램을 사용하셔도 되지만, 굳이 그 무거운 프로그램을 사용할 필요 없이) .DDS 파일을 지원하는 이미지 뷰어 프로그램을 사용하시면 됩니다. 필자가 사용해 본 프로그램은 다음의 두 프로그램으로, 두 프로그램 모두 .DDS 파일을 정상적으로 보여줍니다: XnView, Imagine. 필자가 현재 사용하고 있는 프로그램은 Imagine 입니다. (이 프로그램을 기본 이미지 뷰어로 지정해서 사용하고 있기 때문에, 자연스러운 일이죠.)
참고로, XnView 는 개인 사용자의 경우 구매하지 않아도 되지만, 회사나 영리목적 사용자의 경우에는 라이센스를 구매해야 적법하게 사용 가능합니다. 따라서 가정의 PC에 설치하여 사용하는 것은 문제가 없습니다만, 회사나 PC방 등의 영업장 PC에는 함부로 설치하지 않도록 하십시오. Imagine 은 프리웨어(Donationware)로서, 라이센스의 부담이 없습니다.
1) 이벤트 이미지 목록 파일
이벤트에서 이벤트 상단 이미지를 지정할 때에는 picture = 뒤에 이미지 ID(picture = GFX_evt_feast 의 GFX_evt_feast 가 이미지 ID)를 지정하는 방식으로 지정하는 것을 위 예시에서 보셨을 겁니다. 그렇다면, 어딘가에 이 이미지 ID 와 실제 .DDS 파일을 연결해주는 이미지 목록 파일 내지 인덱스 파일이 존재하리라는 것을 쉽게 예상할 수 있죠.
사실 우리는 이미 디시전 아이콘을 설정하는 부분에서 이와 같은 방식의 예를 이미 본 바 있습니다. 이벤트 상단 이미지의 경우에도 그런 식으로 이미지 파일과 이미지 ID를 연결해 주는 파일이 존재합니다. 2.3.4 버전 기준으로, 원본의 모든 이벤트 이미지는 다음 두 파일 내에 정의/등록되어 있습니다.
- interface\eventwindow.gfx 파일 (Way of Life DLC 이전의 모든 이벤트들에 대한 이미지 파일)
- interface\event_pictures_WoL.gfx 파일 (Way of Life DLC 에 해당하는 이벤트들에 대한 이미지 파일)
만약, 자신의 모드에 사용할 새로운 이미지들을 등록하고 싶다면, 위 파일은 그냥 냅두시고 모드 폴더 내에 interface 폴더를 만드신 후, 그 안에 적당한 파일 이름으로 새로운 .GFX 파일을 하나 만드시면 됩니다. 어떻게 만드냐고요? 그걸 알려드리기 위해서, 원본의 이벤트 이미지 목록 파일 중 하나(eventwindow.gfx) 를 한 번 열어보겠습니다.
spriteTypes = { spriteType = { name = "GFX_evt_unraise_troops" texturefile = "gfx\\event_pictures\\learning_scenario\\unraise_troops.tga" allwaystransparent = yes } spriteType = { name = "GFX_evt_vassal_limit" texturefile = "gfx\\event_pictures\\learning_scenario\\vassal_limit.tga" allwaystransparent = yes } spriteType = { name = "GFX_evt_war_view" texturefile = "gfx\\event_pictures\\learning_scenario\\war_view.tga" allwaystransparent = yes } }
파일의 마지막 3개 항목만을 추렸습니다. 구조가 굉장히 낯이 익지 않습니까? 지난 회에 살펴본 디시전 아이콘 목록 파일과 구조가 매우 비슷하죠? 하나의 spriteType = { } 마다 하나의 이미지를 지정합니다.
-
name = 값은 디시전 아이콘 목록 파일과 같이 지정합니다. 다만 디시전 아이콘의 경우 GFX_ 뒤에 반드시 디시전 ID 를 적어야 했지만, 이벤트 상단 이미지의 경우에는 별다른 제한이 없습니다. 그냥 GFX_ 뒤에 사용자가 알아보기 편한 형식으로 적어 주시면 됩니다. 저는 원본에서처럼 GFX_evt_ 까지 적어준 후 그 뒤에 해당 이미지의 파일 이름 또는 파일 이름을 약간 변형한 제목을 적어줍니다.
-
texturefile = 뒤에는 gfx\ 부터 시작하는 이미지 파일의 경로를 적어주면 됩니다. \ 기호를 두 번 쓰는 것은 여기도 동일합니다. 저거 한 번만 써주면 오류가 발생하니 꼭 두 번 쓰도록 해 주세요. 다만 실제 파일의 확장자가 모두 .DDS 임에도 확장자를 .DDS 가 아닌 .TGA 로 쓰는데, 저도 이유를 모르겠습니다. (원본 이미지들은 저래도 문제 없이 읽어 오더군요.) 제 경우는 모드에 원래 확장자를 지켜서 .DDS 로 적었습니다.
-
allwaystransparent = yes : 그냥 적어 주시면 됩니다. 이름으로 보아 알파 채널을 이용한 투명도 지정을 그대로 사용하는 옵션인 듯 하지만, 그냥 알건 모르건 이렇게 적어 주세요.
원본 파일을 연 김에, 파일 내에서 위 예제에 있는 GFX_evt_feast 를 한번 찾아 보십시오. name 에 이것이 기록되어 있는 항목을 찾으시면 되겠네요. 찾아 보시면, 이 이미지에 연결된 파일은 Banquet_hall_Feast.tga (Banquet_hall_Feast.dds) 파일이라는 점을 쉽게 확인하실 수 있을 겁니다.
2) 내 이벤트를 위한 새로운 이벤트 상단 이미지 만들기
위에서 보듯, CKII 자체에도 수많은 이벤트들을 위한 기본 이벤트 상단 이미지들이 상당히 많이 제공되고 있기 때문에, 모드 내에 자신만의 이벤트를 만들 때에도 적당한 이미지가 이미 원본에 제공되고 있다면 그 이미지를 그대로 사용해도 됩니다. (.DDS 파일을 볼 수 있는 이미지 뷰어는 앞에서 소개드린 바 있죠?)
- 우선 gfx\event_pictures 의 이미지를 넘겨보면서 적당한 이미지를 찾은 후,
- interface 폴더 내의 eventwindow.gfx 또는 event_pictures_WoL.gfx 파일을 열어서 해당 파일의 파일명으로 검색을 하고,
- 해당 파일명으로 등록된 이미지 ID(name = 뒤의 값)를 이벤트의 picture = 뒤에 붙여 넣는다.
그러나, 자신의 이벤트와 딱 맞는 이미지가 존재하지 않는 경우, 모드를 위한 새로운 이벤트 상단 이미지를 직접 작성할 필요가 있을 수도 있습니다. 작업 순서는 대략 아래와 같습니다.
- 적당한 이미지 파일을 규격에 맞추어 .DDS 파일로 저장한다. (모드 폴더의 gfx\event_pictures 폴더)
- 작성한 .DDS 파일을 위한 이미지 목록 파일을 작성한다. (모드 폴더의 interface 폴더에 .GFX 확장자를 가진 파일로 작성)
- 이벤트의 picture = 뒤에 새로 작성한 이미지의 이미지 ID 를 적어 넣는다.
모드에 사용할 새로운 이벤트 상단 이미지 파일을 만드는 것은 CKII 의 모든 그래픽 작업들 중에서도 가장 쉬운 축에 들어갑니다. 그냥 450x150 크기의 이미지를 만들어서 .DDS 파일로 지정된 위치에 저장하면 되는 거거든요. 물론, 실제로 그림을 그리는 경우나, 여러 이미지 파일을 합성하여 새로운 이미지를 만드는 등의 작업을 하신다면 그 난이도가 한도 끝도 없이 올라갈 수도 있겠지만요.
그림에 소질이 있는 분이라면 스스로 캔버스에 그림을 그리셔도 되겠지만, 인터넷의 적당한 이미지를 찾아서 450x150 크기로 자르거나 크기를 조정하여 사용하실 수도 있습니다.
다만, 인터넷상에 돌아다니는 사진이나 이미지들은 저작권 문제를 항상 유의하셔야 합니다. 혼자 쓸 모드라면 신경 쓸 필요 없겠지만, 일반에 공개할 모드라면 아무래도 주의가 필요합니다. (어디 있는지도 모르는 모드 파일의 이미지까지 쫓아다니면서 저작권 태클을 걸 회사는 드물겠지만 말입니다.)
1회에서 소개해 드린 Paint.NET 을 사용하는 경우, 이미지를 편집하고 .DDS 파일로 저장하는 것은 이미 지난 회에서 디시전 아이콘 파일을 만들면서 다루었거나, 모드가 아닌 Paint.NET 의 사용법과 관련되는 내용이므로 따로 덧붙이지 않겠습니다.
다만, 일반적으로 이벤트 상단 이미지의 경우 특별히 알파 채널이 필요하지 않은 경우가 대부분이어서, .DDS 파일을 저장할 때에 파일 형식으로 A8R8G8B8 대신 DXT1 (불투명/1-비트 알파) 로 설정하셔도 상관이 없습니다. 이처럼 형식을 DXT1 로 설정할 경우, A8R8G8B8 로 설정할 경우에 비해 용량이 엄청나게 줄어듭니다. 아래 예시에서 보이는 이벤트 상단 이미지도 DXT1 형식으로 저장된 .DDS 파일입니다. 문제 없이 읽어와서 표시해주고 있죠.
이미지를 만들어서 저장했다면, 이 이미지를 위한 이벤트 이미지 목록 파일을 만들고, 거기에서 지정한 이미지 ID 를 이벤트의 picture = 뒤에 지정해 주시면 작업 끝! 참 쉽죠? (....)
■ 프레임 (border = 이미지 ID)
일부 원본 이벤트들 중에는, 이벤트 메시지 출력 영역의 테두리 색깔이 다른 경우가 있습니다. 이것이 5대 스탯 중 무엇에 관련된 이벤트인가에 따라서 색을 다르게 칠한 건데요. 이것은 border = 를 설정하면 그렇게 됩니다.
character_event = { id = TST.1004 desc = EVTDESC_TST_1004 picture = GFX_evt_feast border = GFX_event_normal_frame_intrigue .... }
따로 설정하지 않으면 보통 diplomacy 에 해당하는 푸른 색 테두리로 나타나게 됩니다.
이 테두리의 호출 ID 인 GFX_event_normal_frame_intrigue 역시 위에서 말씀드린 eventwindow.gfx 파일 내에서 찾을 수 있습니다. 파일의 경로를 확인해 보면 gfx/interface/event_normal_frame_intrigue.tga 라고 되어 있군요. 실제 저 위치에 가 보면 파일이 존재합니다. 뭐 당장은 직접 프레임을 만들어 쓸 것도 아니므로, 프레임 정의도 eventwindow.gfx 내에 있다는 점을 알고 있다면 필요할 때에 찾아 쓸 수 있겠죠. 이벤트의 종류별로 각각 5개씩 준비되어 있습니다.
- GFX_event_normal_frame_[diplomacy/war/economy/intrigue/religion] 일반 이벤트에 사용합니다.
- GFX_event_long_frame_[diplomacy/war/economy/intrigue/religion] 샤를마뉴 이후에 등장한 큰 이벤트 프레임에 사용합니다.
- GFX_event_letter_frame_[diplomacy/war/economy/intrigue/religion] 편지 이벤트 프레임입니다.
- GFX_event_narrative_frame_[diplomacy/war/economy/intrigue/religion] 내러티브 이벤트 프레임입니다.
칼라는 다음과 같습니다.
■ 타이틀 (title = 메시지 ID)
이미 앞에서 가볍게 다루고 넘어온 내용이죠. 보통 내러티브 이벤트에서 많이 사용된다고 말씀드렸습니다. 그래서 아래 내용도 내러티브 이벤트의 예시입니다. 아래와 같이 title = 뒤에 메시지 ID 를 기록하는 방식으로 설정하고, 그 메시지 ID 를 이용하여 언어 파일에 출력할 문장을 정의하면 됩니다.
narrative_event = { id = TST.1005 title = EVTTITLE_TST_1005 desc = EVTDESC_TST_1005 picture = GFX_evt_shadow border = GFX_event_normal_frame_intrigue .... }
앞에서도 말씀드렸듯이, 타이틀은 내러티브 이벤트에서는 거의 필수적으로 쓰이지만, 그 외의 이벤트에서도 설정이 가능합니다. 다만 내러티브 이벤트에서는 제목이 이벤트 메시지 출력 영역의 안쪽에 들어가고 첫 글자에 대해 꾸밈 효과가 주어집니다만, 그 외의 경우에는 제목의 출력 위치가 이벤트 상단 이미지의 위쪽이며 첫 글자의 꾸밈 효과도 없습니다.
■ FROM 의 얼굴을 숨기기 (hide_from = yes)
앞에서 보여드린 예시 이미지에도 나타나지만, 일반적인 캐릭터 이벤트에는 ROOT 와 FROM 의 얼굴이 상단 이미지와 메시지 사이에 나타나죠. 그런데 FROM 의 얼굴을 보여주고 싶지 않을 때가 있습니다. 이런 경우에 사용하는 옵션이 hide_from = yes 입니다. 제 경우는 이벤트 체인을 이어가면서 가끔 보여줄 필요가 없는 캐릭터가 중간에 끼는 경우가 있는데, 이럴 때에 종종 집어넣습니다.
character_event = { id = TST.1004 desc = EVTDESC_TST_1004 picture = GFX_evt_feast hide_from = yes .... }
■ FROM 대신 FROMFROM 의 얼굴을 보여줘! (show_from_from = yes)
위키엔 없는 내용인데, 원본 이벤트 파일에는 존재하는 녀석도 있습니다. 그대로 해석하면 얼굴 이미지에 FROMFROM 도 보여주라는 의미가 되죠. 실제로 실행해 보면, FROM 대신 FROMFROM 의 이미지가 출력됩니다. (가끔 이런 게 필요할 때가 있어요.) 같은 맥락으로, show_from_from_from = yes 라는 구문도 가능합니다.
character_event = { id = TST.1004 desc = EVTDESC_TST_1004 picture = GFX_evt_feast show_from_from = yes .... }
■ 이벤트 창이 나타나지 않는 이벤트 - 이벤트 창 숨기기 (hide_window = yes)
1) 숨은 이벤트
이벤트가 실행되는 창 자체를 숨겨버리는 것도 가능합니다. 아니 그러면 선택지는 어떻게? 보통 이런 경우는 선택지를 하나만 만들게 되고, 그럼 그 하나의 선택지가 자동으로 선택되면서 이벤트는 종료됩니다. 원하는 효과는 보통 option = { } 내에 입력합니다. (다른 방법으로, 과거에 잠깐 등장했던 immediate = { } 를 쓸 수도 있는데, 이것은 뒤에서 살펴볼 것이라 일단 넘어갑니다.)
character_event = { id = TST.1006 hide_window = yes option = { name = OK } }
어차피 보이지 않는 창이므로 desc 나 picture 는 필요가 없으므로, 지정해 주지 않아도 상관 없습니다. 물론 지정해 주더라도 보거나 읽을 수는 없겠죠. 창 자체가 보이지 않는데.
2) 그런데, 이걸 뭐에 쓰나요?
이벤트라는 것이 상호작용을 중요한 요소로 하기 때문에, 이렇게 보이지 않는 창을 무엇에 쓰라는 것이냐는 의문이 들 수 있습니다.
이런 경우를 생각해 봅시다. 어떤 이벤트를 일으키고 싶은데, 그 이벤트를 일으키는 트리거 이벤트를 별도로 구성하는 경우가 있습니다. 말이 좀 어렵죠? 플레이어와 임의의 다른 캐릭터 사이에 어떤 이벤트를 일으키고 싶은데, 그 이벤트가 일정한 조건을 갖추어야 일어나는 이벤트라고 합시다. 이 경우, 하나의 숨은 이벤트를 만든 후 그 숨은 이벤트에 목표하는 이벤트가 일어나기 위한 조건을 정의합니다. 그리고 그 조건을 만족했다면 그 숨은 이벤트에서 목적하는 이벤트를 실행시키고 숨은 이벤트는 종료시키도록 디자인하는 거죠.
아직 이벤트의 실행 조건을 설정하는 구문들을 살펴보지 않았기 때문에, 예시는 따로 들지 않겠습니다. 원본을 찾아보시면 예가 매우 많습니다.
이렇게 이벤트를 설계하면, 이벤트를 발생시키는 트리거와 본 이벤트가 서로 분리되므로, 연속되는 이벤트의 조건을 관리하기가 편리해지고, 버그가 발생할 여지도 조금 줄어들게 됩니다. 그런데, 이런 트리거 이벤트는 단지 조건을 확인하고 조건을 충족하면 다른 이벤트를 발생시키는 것만이 목적이므로, 굳이 이벤트 창을 화면에 띄울 이유가 없습니다. 오히려 일일이 화면에 뜨는 쓸데없는 이벤트에 마우스 클릭을 해 주는 게 고역이죠. 이런 종류의 이벤트라면, 이 옵션을 걸어서 숨은 이벤트로 만들어주는 것이 좋겠죠?
혹은, 일정한 시간이 지난 후에 어떤 효과를 주고 싶은데, 굳이 그 효과가 주어졌다는 것을 플레이어에게 알릴 필요가 없는 경우도 있습니다. 그런 경우에도 시간 조건과 함께 option = { } 내에 그 효과를 지정해 주고, hide_window = yes 를 설정하면 플레이어가 모르게 특정한 효과를 발동시킬 수 있겠죠.
■ Pre-Trigger (구 Fast Event Trigger)
지금 우리는 이벤트 파일의 구조를 보고 있습니다. 이벤트 파일에 설정 가능한 여러 가지 옵션들을 보고 있죠. 이번에 설명드릴 내용은 별로 중요하지 않을 것 같지만, 알아두면 유용하게 사용할 수 있습니다.
위키의 조건문 목록을 확인하다 보면, 그 중에서 Pre-Trigger (예전에는 Fast Event Trigger 라고 했었습니다) 라는 설명이 붙어 있는 애들이 있죠? 과거에 조건문을 보면서, 조건문들 중에 이 설명이 붙어있는 것이 있는데, 그에 대해서는 나중에 설명드리겠으니 일단 건너뛰시라고 말씀드린 것을 기억하시려나 모르겠습니다. 이제 이 부분에 대해서 설명을 드리려고 합니다.
디시전에서와 마찬가지로, 이벤트의 경우에도 이벤트를 실행하기 위한 조건이 매우 중요합니다. 디시전에서의 from_potential = { } / potential = { } 과 마찬가지로 이벤트에서도 조건을 설정하는 섹션이 마찬가지로 존재하는데, 아직 우리는 이에 대해서 확인하지 않았습니다. (아마 다음 회에서 확인하게 될 거예요.) 아무튼.
Pre-Trigger 는, 이벤트를 실행하기 위한 조건을 연산하기 전에, 해당 이벤트가 발생할 수 있는 캐릭터의 범위를 미리 줄여주는 역할을 합니다. 조건 확인의 대상이 되는 캐릭터의 범위를 미리 줄여주기 때문에, 해당 이벤트의 실행으로 인한 시스템의 부담을 조금 줄여주는 효과가 있으므로, 사용할 수 있다면 사용해 주는 것이 좋습니다.
몇 가지 자주 쓰이는 예시들을 한번 적어 보겠습니다.
- capable_only = yes : ROOT 가 의식불명(incapable 트레잇을 가진) 상태가 아닌 경우에만 실행합니다.
- min_age = N / max_age = N : 이벤트의 실행을 위한 최소 나이, 최대 나이를 지정합니다.
- only_men = yes / only_women = yes : 딱 봐도 뭔지 아시겠죠? 남자 또는 여자에게만 실행되도록 합니다.
- only_rulers = yes : 군주일 경우에만(즉, 영지가 있는 자만) 이벤트가 실행됩니다.
- only_independent = yes : 독립군주인 경우에만 이벤트가 실행됩니다. (즉, 영지가 있는 군주라 할지라도 상위 주군의 봉신인 경우에는 대상에서 빠집니다.)
- prisoner = no : 감옥에 갇힌 캐릭터는 범위에서 빠집니다.
- ai = no : AI 캐릭터에게는 이 이벤트가 일어나지 않습니다.
원본에서도 이들은 심심찮게 사용됩니다.
character_event = { id = 76000 desc = "EVTDESC76000" picture = GFX_evt_lovers min_age = 16 max_age = 25 only_men = yes only_rulers = yes capable_only = yes ... }
해석이 되시나요? 나이 16~25세(min_age = 16, max_age = 25)의 남자(only_men = yes)이며 의식불명 상태가 아닌(capable_only = yes) 군주(only_rulers = yes)에게만 이 이벤트의 발생 가능성이 있다는 거죠.
위 예시에서 보듯이, Pre-Trigger 는 조건절에 사용되는 것이 아니라, 각각의 이벤트의 최상위에 함께 설정합니다. 그리고, 이것은 이벤트가 일어나는 캐릭터(ROOT)에 대한 조건만을 제어합니다. 아, 한 가지 주의 사항. 다른 이벤트나 디시전에 의해서 강제로 실행되는 경우, 이 Pre-Trigger 는 무시됩니다. (이건 이벤트 조건의 경우도 마찬가지이지만..)
네. 이번 회에서는 여기까지 설명드리겠습니다. ^^
댓글
댓글 리스트-
작성자통장 작성시간 15.02.13 ㄷㄷㄷㄷ
-
작성자shyisna 작성시간 15.02.15 게임 만드시는 분일 줄...ㅋㅋㅋ 뒤에서 부터 흥미가 생겨 읽고 있는 중... 파일 열어본 1인
-
작성자네트 작성시간 17.02.12 갑자기 생각나서 eu4 파일 까봤다가 namespace 가 있어서 무슨 뜻인지 몰라 헤맸는데 꿀팁이 있었네요.
예전에 제가 모드 하나 만들었을적에 자꾸 에러가 터져서 왜 그런지 모르고 우왕자왕 하다 셔터 내렸었는데, 지금 돌이켜 생각해보니 이벤트 ID 값을 초과 했던 문제가 있었던 거였네요.
좋은 정보 감사합니다.