NML 강좌(NewGRF 제작) / 1강 : 시작하기

https://telk.kr/tb/free/1591
NewGRF을 제작하기 위해서는 기본적인 제작 프로그램이 있어야 합니다.

크게 GRFMaker를 이용하는 방법과 NML, NFO 방식으로 프로그래밍하는 방법 등이 있습니다.
하지만 GRFMaker는 TTD 시절에 이용되던 프로그램이라
OpenTTD 최신 버전과는 잘 맞지 않는 단점이 있고,

NFO 방식은 저급 프로그래밍 언어[1]라 배우기가 어렵습니다.

그래서 제 경우에는 (배우기는 그래도 어렵지만)
고급 프로그래밍 언어[2]인 NML 방식을 이용해서 NewGRF을 제작하고 있습니다.


이번 기회에 부족한 실력이지만 제가 배운 NML을 알려드리고자 팁을 작성합니다.


* 읽기 전에

하늘색 부분은 여러분이 마음대로 이름을 정할 수 있는 부분입니다.
분홍색 부분은 정해진 문자열이나 값을 찾아서 지정해주어야 하는 부분입니다.


1. NML 컴파일러 준비하기

NML 방식은 NewGRF을 '프로그래밍'하는 방식입니다.
따라서 소스 코드인 *.nml 파일을 *.grf 파일로 변환하기 위한 '컴파일러'가 필요합니다.
이 컴파일러가 바로 nmlc.exe 파일입니다.

http://bundles.openttdcoop.org/nml/nightlies/LATEST에서 다운로드할 수 있습니다.
(들어가서 파일 이름이 nml-XXXXX-windows-win32.zip 으로 되어있는 것 다운로드)


압축을 풀면 여러 개의 파일이 뜨지만,
우리가 사용할 것은 nmlc.exe 실행파일 단 하나입니다.

nmlc.exe 파일이 있는 폴더 경로를 잘 기억하십시오.

[시작]-[실행]을 눌러 입력창에 cmd (XP 기준)를 입력하고 엔터를 치면
옛날에 본 듯한 도스창(명령 프롬포트)이 뜹니다.

방금 전에 nmlc.exe 파일이 있는 폴더로 이동(cd 폴더명)한 뒤,
명령창에 nmlc 를 입력하면 다음과 같이 안내문이 뜹니다.
sage: nmlc [options] <filename> Where <filename> is the nml file to parse Options: \--version show program's version number and exit -h, \--help show this help message and exit -d, \--debug write the AST to stdout -s, \--stack Dump stack when an error occurs \--grf=<file> write the resulting grf to <file> \--md5=<file> Write an md5sum of the resulting grf to <file> \--nfo=<file> write nfo output to <file> -M output a rule suitable for make describing the graphics dependencies of the main grf file (requires input file or --grf) \--MF=<file> When used with -M, specifies a file to write the dependencies to \--MT=<file> target of the rule emitted by dependency generation (requires -M) -c crop extraneous transparent blue from real sprites -u save uncompressed data in the grf file \--nml=<file> write optimized nml to <file> -o <file>, \--output=<file> write output(nfo/grf) to <file> -t <file>, \--custom-tags=<file> Load custom tags from <file> [default: custom_tags.txt] -l <dir>, \--lang-dir=<dir> Load language files from directory <dir> [default: lang] -a <dir>, \--sprites-dir=<dir> Store 32bpp sprites in directory <dir> [default: sprites] \--default-lang=<file> The default language is stored in <file> [default: english.lng] \--start-sprite=<num> Set the first sprite number to write (do not use except when you output nfo that you want to include in other files) -p <palette>, \--palette=<palette> Force nml to use the palette <pal> [default: ANY]. Valid values are 'DOS', 'WIN', 'ANY' --quiet Disable all warnings. Errors will be printed normally.

영어로 되어있어 무슨 소리인지 모르겠지만 일단은 그러려니 하고 넘어갑니다.
어차피 우리가 사용할 명령어는 몇 개 없습니다.



2. 프로젝트 폴더 만들기

이제 NewGRF을 만들기 위해 프로젝트 폴더를 하나 만듭니다.
nmlc.exe 파일이 있는 폴더 안에 아래와 같이 적당히 폴더를 하나 만듭니다.
이번 강좌에서는 my_newgrf 이라고 해보겠습니다.
그 폴더 안에 또다시 lang 이라는 폴더를 만듭니다.
최종적으로 아래와 같은 구조가 될 것입니다. (폴더는 기울임 표시하였습니다.)
(...)
└nmlc.exe
 └ my_newgrf
  ├ lang
  └ (본체 파일이 들어갈 곳)


3. 가장 기초적인 NewGRF 만들기 : 언어파일

NML의 가장 큰 장점 중 하나가 바로 '번역을 손쉽게 지원할 수 있다'는 점입니다.
방금 만드신 lang 폴더에 언어 파일(*.lng)을 제작해서 넣으시면 됩니다.
하지만 기본적으로 영어 언어 파일(english.lng)은 반드시 있어야 합니다.



만약 한국어 번역을 지원하고 싶다면
english.lng 파일과 korean.lng 파일을 만들어서
아래와 같이 위치시키시면 됩니다. (굵은 글씨)
(...)
└nmlc.exe
 └my_newgrf
  ├lang
  │├ english.lng
  │└ korean.lng
  └ (본체 파일)

언어 파일은 다음과 같이 작성합니다.
#grflangid {{#ef007c <number>}} {{#00b0a2 <string-name> :<text> <string-name> :<text> }}...


하나 하나 설명하겠습니다.

```##grflangid <number>
##grflangid 는 이 언어 파일이 어떤 언어를 나타내는지 알려주는 부분입니다. {{#ef007c <number>}} 부분에 언어에 대한 코드값을 입력해주어야 합니다. 영어는 00, 한국어는 3A 입니다. 단, 이 코드값은 16진수값이므로, 입력시 앞에 0x 를 붙여주어야 합니다. ex) 영어: ##grflangid 0x00 한국어: ##grflangid 0x3A 다른 언어의 코드값은 [[[http://newgrf-specs.tt-wiki.net/wiki/NML:Language_files]]]의 가장 하단에 있는 표에서 참고할 수 있습니다. <string-name>: <text>
<string-name>은 문자열 이름입니다. 아래 소스 코드 본체에서 사용될 부분입니다. <text>는 그 문자열 이름에 해당하는 문자열입니다. 이 둘을 콜론(:)으로 구분하여 입력하면 됩니다. <string-name>은 <text> 이다 라고 생각하시면 편하겠네요. 백번 설명하는 것보다 직접 보여드리는 게 낫겠지요. 이번에 만들 NewGRF에서 쓸 언어 파일 코드입니다. 따라해보세요. '''[영어 언어 파일 (english.lng)]''' ##grflangid 0x00

STR_MY_NEWGRF_NAME :My First NewGRF
STR_MY_NEWGRF_DESC :This is my first NewGRF. This is a description.
'''[한국어 언어 파일 (korean.lng)]''' ##grflangid 0x3A

STR_MY_NEWGRF_NAME :내 첫 번째 NewGRF
STR_MY_NEWGRF_DESC :내가 만든 첫 번째 NewGRF입니다. 이건 설명입니다.
'''4. 가장 기초적인 NewGRF 만들기 : 소스 코드 본체''' 이제 정말 기초적인 NewGRF을 만들어보겠습니다. 지금 만들 NewGRF은 어떤 기능도 하지 않고, 그저 NewGRF 목록에 이름만 올리는 용도입니다. 하지만 내가 만든 GRF이 게임 상에서 그 이름을 표시한다는 게 꽤 뿌듯하답니다. 본체 파일은 확장자가 .nml 이며, 여기에 코드를 작성하여 컴파일하는 방식입니다. 메모장이나 기타 텍스트 편집 프로그램을 열고 다음과 같이 코드를 작성합니다. {{#951015 NML은 C 계열의 프로그래밍 언어처럼 줄 끝에 항상 세미콜론(;)을 붙여야 합니다.}} (참고: 주석도 C 계열을 따라갑니다. //, /* */ 사용 가능) grf {
grfid: "ABCD";
name: string(STR_MY_NEWGRF_NAME);
desc: string(STR_MY_NEWGRF_DESC);
version: 0;
min_compatible_version: 0;
}
하나 하나 설명을 해보겠습니다. grf { ~ }
중괄호로 묶인 하나의 영역을 '''블록'''이라고 합니다. grf 블록은 NewGRF의 기본적인 정보를 선언해줍니다. 중괄호 안에 있는 grfid, name 같은 것들은 속성값입니다. grfid: "ABCD";
grfid 속성은 NewGRF의 고유한 ID를 지정하는 부분입니다. 4바이트 고정 문자열로 되어있습니다. (더도말고 덜도말고 딱 4글자라는 말입니다.) {{#00b0a2 ABCD}} 부분을 고치시면 됩니다. 숫자를 써도 괜찮습니다. 하지만 이럴 경우 다른 NewGRF과 중복될 수도 있기 때문에, 이를 피하기 위해 '''16진수 방식'''으로도 입력할 수 있습니다. 1글자(1바이트)는 2글자의 16진수로 되어있습니다. 뒤에 오는 숫자가 16진수임을 표시하기 위해 자를 앞에 덧붙입니다. 예를 들면 A = 65, 0 = 48 등입니다. (ASCII 코드표 참조) 예를 들어 자기 이름이 '홍길동'이고 1번째로 만드는 NewGRF이라면 grfid 속성을 'HGD1' 이라고 지정하는 습관을 들이는 것도 좋습니다. (1이 1글자임) name: string(STR_MY_NEWGRF_NAME);
name 속성은 게임 상에서 나타날 NewGRF의 이름입니다. string({{#00b0a2 STR_MY_NEWGRF_NAME}}) 은 위 '언어 파일' 부분에서 나온 <string-name>입니다. STR_MY_NEWGRF_NAME 이라는 문자열을 읽어오겠다는 뜻입니다. 나중에 STR_MY_NEWGRF_NAME에 '나의 첫번째 NewGRF' 등의 문자열을 넣으면 됩니다. desc: string(STR_MY_NEWGRF_DESC);
desc 속성은 이 NewGRF의 설명(description) 부분을 지정합니다. 마찬가지로 {{#00b0a2 STR_MY_NEWGRF_DESC}}?라는 문자열을 지정합니다. version: 0;
version 속성은 이 NewGRF의 버전을 나타냅니다. 숫자 0부터 시작하여 NewGRF을 수정할 때마다 1씩 올리는 방식입니다.(소숫점 불가) 0을 포함한 자연수로 값을 입력하셔야 합니다. (마지막에 세미콜론 붙이는 것도 잊지 마세요.) min_compatible_version: 0;
min_compatible_version 속성은 처음 만들 때에는 version과 같이 값이 0입니다. 하지만 NewGRF을 수정하고 수정하다 구 버전과 호환이 안되게 될 경우, 이 min_compatible_version 속성을 수정하면 됩니다. 호환이 가능한 가장 낮은 version 값을 지정해주면 됩니다. 백문이불여일견이라고 실제 이번 강좌에서 만들 NewGRF의 NML 소스를 확인해봅시다. 샘플 소스에서는 주석을 어떻게 사용하는 지에 대해서도 적어두었습니다. 이 소스 파일을 '''{{#00b0a2 my_newgrf}}.nml''' 이라고 저장하겠습니다. 아래와 같은 위치에 만드시면 됩니다.(굵은 글씨) (...) └nmlc.exe  └''{{#00b0a2 my_newgrf}}''   ├''lang''   │├english.lng   │└korean.lng   └ '''{{#00b0a2 my_newgrf}}.nml''' /*
이런 형태로 주석을 사용할 수 있습니다.
이 형식의 주석은 여러 줄의 설명을 달 수 있습니다.
*/

// 이런 형태의 주석도 사용 가능합니다.

// NewGRF 기본 정보 선언
grf {
grfid : "HGD1"; // 홍길동(HGD)의 첫 번째(1) NewGRF
name : string(STR_MY_NEWGRF_NAME);
desc : string(STR_MY_NEWGRF_DESC);
version : 0;
min_compatible_version : 0;
}
'''5. 컴파일하여 .grf 파일로 만들기''' 이제 모든 준비가 끝났습니다. 최종적으로 다음과 같은 파일/폴더 구조가 되어야 합니다. (...) └nmlc.exe  └''{{#00b0a2 my_newgrf}}''   ├''lang''   │├english.lng   │└korean.lng   └ my_newgrf.nml 이제 [시작]-[실행]을 누릅니다. 입력창에 '''cmd''' (XP기준)를 입력하면 명령 프롬프트(도스창)가 뜹니다. '''''dir''''' (폴더 목록 나열/검색)과 '''''cd''''' (폴더 이동)명령어를 이용해 nmlc.exe 파일이 있는 폴더까지 들어갑니다. 입력줄에 '''nmlc'''를 쳐봤을 때 아까 봤던 긴 영어 안내문이 나오면 됩니다. 이제 입력줄에 다음과 같이 입력합니다. nmlc -l ./my_newgrf/lang/ ./my_newgrf/my_newgrf.nml
명령어를 해석하자면 이렇게 되겠네요. nmlc : 컴파일해주세요.
-l ./my_newgrf/lang/ : 언어 파일은 ./my_newgrf/lang/ 폴더에 있어요.
./my_newgrf/my_newgrf.nml : 본체 소스 파일은 ./my_newgrf/my_newgrf.nml 입니다.
```






이제 my_newgrf 폴더로 들어가보면 전에 없던 my_newgrf.grf 파일이 생성된 것을 볼 수 있습니다.
이제 이 파일을 OpenTTD가 설치된 폴더 내에 있는 newgrf 폴더에 넣어볼까요?





와우! 게임에 내가 만든 NewGRF이 뜨는군요!
아까 언어파일에서 입력한 문자열도 잘 뜹니다.


게임 전체 언어를 영어로 바꾸어도 잘 뜨네요.











* 마치며
이번에 만든 NewGRF은 추가해서 적용해도 게임 상에 아무런 영향을 끼치지 않는 것입니다.
grf 블록으로 NewGRF의 기본적인 정보만 지정해주었을 뿐,
그 이후에 아무 것도 코딩하지 않았기 때문입니다.
이후 자동차, 전차, 기차 등을 만들기 위해서는 추가적인 문법을 더 공부해야 합니다.
일단은 오늘은 여기서 만족하도록 하지요. :)

  1. [1] 사람이 이해하기 난해한 소스 코드를 가진 프로그래밍 언어. 어셈블리어가 대표적인 예
  2. [2] 사람이 이해하기 비교적 쉬운 소스 코드를 가진 프로그래밍 언어. Perl, PHP, ASP, JSP, Java 등

이모지를 이용해서 글에 반응해보세요!

댓글



꼬리표를 선택하세요


↑TOP

신고하기 ×

신고 종류
작성자
내용

신고 사유