뮤테이터 만들기
기본 게임이나 어떤 모드 위에든 덧씌우는 작은 .oamut: 폴더, 매니페스트, mutate가 돌려주는 계획, 옵션, 샌드박스, 여러 개를 쌓을 때의 적용 순서.
이 장은 docs/mutators/authoring.md 문서와 docs/mutators/oamut-standard.md 문서를 요약합니다.
뮤테이터란
뮤테이터는 기본 게임이나 어떤 모드 위에든 덧씌우는 작은 .oamut 패키지입니다. 경기 하나를 바꿉니다. 라이브러리는 매니페스트의 ID로 Mutators 폴더에 설치하며, 설치한다고 켜지지는 않습니다. 플레이어가 스커미시, 대기실, 캠페인에서 켭니다. works-with는 맞는 모드를 밝히며, 별표는 모든 모드와 기본 게임을 뜻합니다.
패키지
폴더 최상위에 oamut.yaml이 있습니다. 진입 스크립트는 그 옆에 둡니다. 기본 이름은 mutator.lua이고 entry로 다른 이름을 지정할 수 있으며, files/, rules/, lua/ 아래에는 절대 두지 않습니다. lua/에는 추가 Lua 소스를 두며, require가 읽는 파일은 이것뿐입니다. files/에는 파일 레이어가 추가할 수 있는 바이트를 둡니다. rules/에는 이름이 .sm으로 끝나는 규칙 파일을 둡니다. 아이콘은 매니페스트가 지정한 PNG입니다. 이름이 .md나 .txt로 끝나는 메모는 사람을 위해 함께 담기며, 게임은 불러오지 않습니다. 이 목록 밖의 파일은 거부됩니다. 비교할 때 ASCII 문자의 대소문자는 무시합니다.
my-mutator.oamut플레이어가 받는 파일├─ oamut.yaml필수 매니페스트├─ mutator.lua진입 스크립트, mutate(ctx)├─ lua/선택 사항. Lua 모듈, require가 읽는 유일한 파일├─ files/선택 사항. 모델, 스크립트, 그 밖의 바이트├─ rules/선택 사항. .sm 규칙 파일├─ icon.png선택 사항. icon이 지정하는 PNG└─ README.md메모. 게임은 불러오지 않음매니페스트
모드 프로필과 같은 규칙의 엄격한 YAML입니다. 문서 하나, 최상위 매핑 하나이며 앵커와 블록 스칼라는 쓸 수 없습니다. 파일은 oamut 키를 정수 1로 설정하며 시작합니다. 표준에 없는 키는 거부됩니다. > 기호로 시작하는 값과 별표는 따옴표로 감싸세요. 그러지 않으면 리더가 다른 것으로 해석합니다. requires.engine을 따옴표로 감싸는 것도 이 때문입니다. 버전도 따옴표로 감쌉니다. 일반 숫자는 거부됩니다.
| 키 | 필수 | 하는 일 |
|---|---|---|
oamut | 예 | 형식. 정수 1. 1.0과 따옴표로 감싼 1은 거부됩니다. |
id | 예 | 소문자 케밥 케이스, 1~64바이트. 하이픈은 앞뒤에 오거나 연달아 올 수 없습니다. 설치 폴더 이름입니다. |
name | 예 | 1~64바이트, 제어 문자 없음. 플레이어에게 보이는 이름입니다. |
version | 예 | 따옴표로 감싸며, 최대 32바이트. 점으로 이은 1~3개 부분이며, 각 부분은 0~65535의 숫자로 앞자리에 0이 오지 않습니다. |
author | 예 | 매핑. name은 필수이며 1~128바이트. email은 선택 사항입니다. |
description | 아니요 | 선택 사항, 1~2,000바이트. 줄 바꿈을 쓸 수 있습니다. 첫 줄을 200바이트로 자른 것이 목록에 표시되는 요약입니다. |
homepage | 아니요 | 선택 사항, 1~256바이트. http 또는 https 주소. |
icon | 아니요 | 선택 사항. 정사각형 PNG의 패키지 경로이며 .png로 끝납니다. 설치 프로그램이 그림을 검사합니다. |
tags | 예 | ID 1~4개, 중복 없음. 라이브러리가 아이콘으로 표시하는 8개는 아래에 있습니다. |
works-with | 예 | 조건 1~32개, 같은 ID는 두 번 쓸 수 없습니다. 별표는 모든 모드와 기본 게임을 뜻하며, 그때는 유일한 항목이어야 합니다. ta-3.1c는 모드 없는 기본 게임입니다. 그 밖의 ID는 모드이며, 버전 범위를 붙일 수 있습니다. |
requires | 아니요 | 선택 사항. engine과 mutators만 씁니다. engine은 이 빌드에 대한, 따옴표로 감싼 범위입니다. mutators는 켜져 있어야 하는 패키지를 지정하며, 적은 순서대로 이 뮤테이터보다 먼저 적용됩니다. |
conflicts-with | 아니요 | 선택 사항. 이 뮤테이터가 함께 실행되기를 거부하는 뮤테이터입니다. 여기 적는 ID는 requires.mutators에 있는 ID나 이 뮤테이터 자신의 ID일 수 없습니다. |
layers | 예 | 이름 1~9개, 중복 없음: files, units, weapons, features, sides, tables, menus, maps, hacks. 계획은 여기 적은 레이어에만 쓸 수 있습니다. |
clashes | 아니요 | 선택 사항, add 또는 replace. 이름이 이미 게임에 있는 유닛이나 무기를 이 뮤테이터가 어떻게 처리할지 정합니다. 플레이어의 선택이 먼저이고, 그다음이 이 키, 그다음이 환경 설정 mutators.clash-default이며, 설정하지 않으면 replace입니다. |
options | 아니요 | 선택 사항, 최대 16개. 플레이어가 경기 전에 고르는 설정입니다. ctx.options로 읽습니다. |
strings | 아니요 | 선택 사항, 최대 16개 언어 태그. 이름, 설명, 옵션 레이블의 번역입니다. |
entry | 아니요 | 선택 사항. 진입 스크립트로, .lua로 끝나는 패키지 경로이며 files/, rules/, lua/ 아래에 있으면 안 됩니다. 생략하면 mutator.lua입니다. |
legacy | 아니요 | 선택 사항. 이 패키지가 대체하는 TA: Mutation 뮤테이터의 기록 1~16개. 각 기록은 name, prefix, compatibility, files로 이루어집니다. 리스트가 아닌 단독 매핑은 거부됩니다. |
여덟 가지 태그
리더는 1~32바이트의 소문자 케밥 케이스 태그를 최대 4개까지 받습니다. 라이브러리는 이 여덟 ID와 정확히 일치할 때만 아이콘과 번역된 레이블을 표시합니다. 다른 ID는 아이콘 없이 쓴 그대로 보입니다. 매니페스트에 icon이 없으면, 첫 태그가 여덟 가지 중 하나일 때 배지에 그 태그의 아이콘을 씁니다.
| 키 | 하는 일 |
|---|---|
statistics | 능력치 |
economy | 경제 |
commanders | 커맨더 |
new-units | 새 유닛 |
disable | 비활성화 |
gameplay | 게임플레이 |
ai | AI |
maps | 맵 |
계획
진입 스크립트는 mutate를 정의합니다. 엔진은 계획 단계에서 mutate(ctx)를 한 번 호출하며, 이 호출 자체는 게임을 바꾸지 않습니다. mutate는 테이블 하나를 돌려줍니다. 빈 테이블은 아무것도 바꾸지 않습니다. 엔진이 모르는 키는 거부됩니다.
files는 add와 mask로 이루어진 테이블입니다. 각각 텍스트 리스트이며, 둘 중 하나는 생략해도 됩니다. add는 패키지 안의 폴더를 순서대로 지정하며, 두 폴더에 같은 경로가 있으면 나중 폴더가 이깁니다. mask는 경로를 숨깁니다. rules는 완성된 블록의 리스트입니다. 블록은 where, all, named, on으로 만든 뒤 :change를 붙인 것이며, .sm 파일을 지정하는 sm 경로도 들어갈 수 있습니다. 변경은 set, scale, lock, remove, append 중 하나입니다. scale에는 하한과 상한을 줄 수 있으며, 그 범위는 해당 배율 하나만 제한합니다. 훅은 함수입니다. units, weapons, features, sides, tables, menus 순서로 실행됩니다. maps는 모든 뮤테이터가 끝난 뒤, 경기에서 맵을 고른 경우에만 실행됩니다. hacks는 레지스트리가 뮤테이터에 열어 둔 매개변수를 이 경기에 한해 설정합니다. 쓰기가 허용되는 것은 레이어를 선언했기 때문입니다.
옵션과 ctx
mutate가 실행되는 동안 ctx에는 모드(ID, 버전, 게임), 엔진 버전, 옵션, ctx.incompatible이 들어 있습니다. 켜진 모드가 없으면 ctx.mod.id는 ta-3.1c입니다. 이유를 넣어 ctx.incompatible을 호출하면 이 뮤테이터가 중단되며, 그 이유가 플레이어에게 보이는 텍스트입니다. 컬렉션은 아직 불러오지 않은 상태입니다. 훅은 레이어를 선언하지 않고도 ctx의 units, weapons, features, sides, tables, menus를 읽을 수 있습니다. 쓰려면 레이어가 필요합니다.
ctx.options에는 옵션 ID마다 필드가 하나씩 있습니다. toggle은 true나 false입니다. number와, 값이 숫자인 choice는 숫자입니다. 값이 식별자인 choice는 텍스트입니다. 플레이어가 건드리지 않은 옵션은 기본값입니다. type은 toggle, choice, number 중 하나입니다. choice는 값을 2~16개 나열하며, 모두 숫자이거나 모두 식별자여야 합니다. 단어가 값과 다르면 labels를 씁니다. number에는 min, max, step, default가 있습니다. 플레이어는 min부터 max 사이에서 step에 맞는 값만 고를 수 있으므로, 스크립트에서 범위를 다시 검사할 필요가 없습니다. step에 맞지 않는 값은 스크립트가 실행되기 전에 거부됩니다. 옵션 ID는 Lua 이름이며, Lua 키워드는 거부됩니다.
샌드박스
스크립트는 샌드박스 하나에서 Lua로 실행됩니다. 파일, 네트워크, 시계, 환경 변수, 프로세스가 없습니다. io, os, debug, package, coroutine은 열리지 않으며, 미리 컴파일한 청크는 거부됩니다. 모든 청크는 소스입니다. 두 뮤테이터는 상태를 공유하지 않습니다.
단계마다 명령 허용량은 처음부터 다시 50,000,000이고, 실시간 제한도 다시 10초입니다. 메모리 상한은 64 MiB이며 다음 단계에서 다시 주어지지 않습니다. 문자열 하나는 최대 65,536바이트입니다. 스크립트가 계산하는 능력치에는 fixed를 쓰세요. 65,536분의 1 단위로 세므로, 같은 스크립트는 어느 기기에서나 같은 텍스트를 씁니다. pairs는 정해진 순서로 키를 순회합니다. 결과는 기기에 따라 달라지지 않습니다.
쌓기
플레이어는 뮤테이터를 순서대로 나열하며, 위에서 아래로 적용됩니다. 첫 번째가 먼저 적용됩니다. 뒤의 뮤테이터는 위의 뮤테이터들이 바꿔 놓은 게임을 봅니다. requires.mutators에 지정된 뮤테이터는 이 뮤테이터와 함께 켜지고, 그 리스트에 적힌 순서대로 이 뮤테이터보다 먼저 적용됩니다. 뮤테이터가 32개를 넘거나, 같은 ID가 두 번 나오거나, 위쪽 어디에서도 충족되지 않는 요구가 있거나, 서로 충돌하는 두 뮤테이터가 있으면 리스트 전체가 거부되고 아무것도 실행되지 않습니다.
먼저 모든 뮤테이터의 파일이 리스트 순서대로 덧씌워지며, 같은 경로는 나중 뮤테이터가 이깁니다. 그다음 각 뮤테이터가 같은 순서로 자기 유닛, 무기, 다운로드 파일을 레코드로 읽고, 규칙을 적용한 뒤 훅을 실행합니다. 규칙은 정해진 순서로 한 번에 하나씩 적용됩니다. 배율은 현재 숫자에 곱해지며, 범위 제한은 그 배율에만 걸리고 이후 배율에는 걸리지 않습니다. 대입은 현재 값을 바꿉니다. lock은 값을 설정하고, 이후 어떤 뮤테이터도 그 필드를 바꾸지 못하게 합니다. Lua 블록 하나 안에서는 테이블에 적은 순서가 아니라, ASCII 소문자로 바꾼 필드 이름 순서로 변경이 실행됩니다. 뮤테이터 사이에서 평균을 내지는 않습니다. 모든 뮤테이터가 적용된 뒤, 게임이 저장하는 폭을 넘은 유닛이나 무기의 숫자와 게임이 읽는 범위를 넘은 지형지물의 숫자는 범위의 끝값으로 한 번 고정됩니다.