게임 엔진

1998년 원작이 안에서 어떻게 돌아가는지를 정리했습니다. 시간을 세는 방식부터 전투가 순서를 정하는 규칙, 이야기를 실행하는 스크립트, 지형이 바뀌는 구조까지 — 위키의 수치가 어디서 나온 것인지 알고 읽는 데 도움이 되는 부분만 모았습니다.

시간을 세는 방식

원작에는 초당 몇 장이라는 목표 프레임이 따로 없습니다. 대신 윈도우가 주는 밀리초 시계를 읽어 정해진 간격이 지났는지만 확인하고, 지났으면 그만큼 장면을 밀어냅니다. 화면이 빠른 컴퓨터에서도 같은 속도로 흐르는 이유이고, 느린 컴퓨터에서 그림이 건너뛰더라도 게임 속 시간은 어긋나지 않는 이유이기도 합니다.

페이즈 게이트기본 16ms
장면이 한 칸 나아가는 간격입니다. 초당 62.5번이고, 이 간격이 지나지 않으면 아무것도 진행하지 않습니다.
전투 중25ms
전투에 들어가면 간격을 25ms로 바꿉니다. 초당 40번이고, 전투 연출의 기준 시간도 이것입니다.
빠른 애니메이션4ms
원작의 빠른 연출 스위치가 켜지면 간격이 4ms로 줄어 같은 연출이 훨씬 빨리 지나갑니다.
작업 카운터16ms
페이즈와 별개로 도는 카운터입니다. 팔레트 변화와 소리 페이드가 여기에 맞춰 처리되고, 한 번에 최대 세 묶음까지만 밀어 넣습니다.

예약된 일은 따로 관리합니다. 만기 시각을 가진 타이머가 목록으로 이어져 있고, 매 페이즈마다 시각이 지난 것을 앞에서부터 꺼내 실행합니다. 그렇게 만들어진 메시지는 32칸짜리 큐에 쌓여 처리되는데, 원작은 이 큐가 가득 차면 그 자리에서 멈추도록 만들어져 있습니다.

주소 하나로 도는 세계

게임의 모든 상태는 정해진 주소에 놓인 표입니다. 일행의 기록은 0x607a08부터 188바이트씩 열여섯 칸, 소지금은 0x803a18, 아이템 수량은 0x806e30부터 360칸입니다. 이 위키의 수치가 원작과 같은 이유도 여기에 있습니다 — 화면을 보고 적은 것이 아니라 실행 파일 안의 표를 그대로 꺼낸 값입니다.

개수한 칸의 크기
캐릭터 기록16개188바이트 · 47개 값
아이템355개76바이트 · 수량 칸은 360개
몬스터218개124바이트
500개지형·출입구·전투 구성
캐릭터 스킬66개형태별 10칸 템플릿
맵 패치409개36바이트 · 이벤트 플래그 한 칸

이야기를 움직이는 작은 VM

이벤트와 행동은 미리 그려 둔 장면이 아니라 오프코드로 도는 작은 가상 기계가 한 줄씩 실행합니다. 대사 한 줄, 걸음 하나, 전투 시작이 모두 이 명령들의 조합입니다.

end · yield · wait
스크립트를 끝내거나, 한 페이즈 넘기거나, 정해진 시간 기다립니다.
jump · conditional_jump
조건 없이, 또는 조건을 보고 다른 자리로 건너뜁니다.
branch_table · call_table
여러 갈래를 표에서 골라 뛰거나 부릅니다.
if · else · while · repeat
원작 스크립트가 그대로 쓰는 제어 구조입니다.
random
난수를 뽑습니다. 조우와 확률 연출이 여기서 갈립니다.
native_callback
스크립트가 엔진 쪽 루틴을 직접 부릅니다.

같은 구조 덕분에 이벤트 일람의 대사를 스크립트에서 그대로 꺼낼 수 있습니다.

지형이 바뀌는 방법

문이 열리고 다리가 놓이는 변화는 맵을 새로 부르는 것이 아니라 맵 패치로 처리됩니다. 패치 한 칸은 어느 맵의 어느 사각형을, 켜졌을 때의 타일과 꺼졌을 때의 타일 중 무엇으로 채울지, 그리고 바뀔 때 어떤 소리를 낼지를 가지고 있습니다.

켜고 끄는 스위치가 이벤트 플래그입니다. 패치 번호가 곧 플래그 번호라서, 409번째 패치는 409번 플래그가 켜져 있는지만 봅니다. 맵에 들어설 때마다 그 맵에 속한 패치를 표 순서대로 다시 적용하므로, 같은 자리를 건드리는 패치가 여럿이면 뒤쪽이 이깁니다. 어떤 플래그가 어느 맵을 바꾸는지는 세이브파일 분석에 전부 정리해 두었습니다.

조우가 일어나는 조건

걷다가 전투가 벌어지는 데에는 여러 관문이 있습니다. 먼저 맵마다 조우 스위치가 있어 꺼져 있으면 아무 일도 없고, 일행 중 누구든 조우를 막는 장비를 차고 있으면 역시 없습니다. 그다음 마지막 전투 이후 걸은 걸음이 15~53걸음 사이에서 뽑힌 수를 넘어야 하고, 전투에 쓸 기록 칸이 비어 있어야 하며, 맵에 희귀도가 걸려 있으면 그 확률까지 통과해야 합니다.

통과하면 마지막으로 접근 연출을 고릅니다. 100분의 2로 가장 긴 연출, 10분의 1 미만이면 그다음, 이런 식으로 다섯 단계 중 하나가 뽑혀 전투가 시작되기까지의 뜸이 달라집니다. 드물게 걸리는 연출일수록 길게 다가옵니다.

전투가 순서를 정하는 규칙

행동 순서는 각자의 기록 안에서 게이지가 차오르는 방식입니다. 매 판마다 민첩에서 나온 양이 쌓이고 가장 많이 찬 쪽이 움직이며, 쓰러졌거나 행동이 막힌 사람은 쌓지 못합니다. 상태이상은 기록의 상태 비트 하나에 모여 있어 독·수면·침묵·마비·저주는 물론 럭키 마치나 파워 삼바 같은 강화도 같은 자리에서 켜집니다. 공격이 맞을 확률과 피해량은 서로의 관계에 따라 한 번 더 보정되고 반격이 나올 확률도 여기서 갈립니다. 자세한 수치는 전투에 정리돼 있습니다.

화면과 저장

화면은 8비트 팔레트 그림을 논리 프레임버퍼에 그리는 방식입니다. 실행 파일에는 800 × 600이 들어 있고 원작이 640 × 480도 함께 제공했는데, 이 값이 곧 "한 화면에 몇 칸이 보이는가"입니다. 해상도를 바꾸면 그림이 커지는 것이 아니라 보이는 범위가 달라지고, 화면보다 넓은 장면을 요구하는 스크립트는 원작에서 그랬듯 양옆이 잘립니다.

저장 파일은 15,232바이트로, 일행 기록과 소지품, 진행 플래그가 정해진 순서로 들어갑니다. 구조와 각 자리의 뜻은 세이브파일 분석에 정리했고, 그 페이지에서 직접 자기 저장 파일을 열어 볼 수 있습니다.

이 페이지의 수치는 원작 실행 파일의 표와 동작을 그대로 옮긴 코어 구현에서 센 값입니다.