KOEI/삼국지 시리즈

삼국지5PK 일판에 한글을 출력시키고 말겠다. (3부)

K66Google 2022. 2. 16. 15:02

(2부에 이어서 계속...)

 

* 안내

본문에서 말하는 '메시지 파일' 은 MESSAGE.s5를 말하는 것이 아닌, MESSAGE.s5를 LS11 압축해제하고 나온 56개의 메시지 파일을 의미하는 것입니다.

 

11. 외부 메시지를 읽어들이는 런처 제작

지난번의 '메시지 파일 용량 제한 문제' 를 돌파하기 위해 나는 예전에 보았던 '런처 한글화' 방식을 떠올렸다.

런처 한글화 방식을 이용해서 메시지 파일에는 m00000 이런 식으로 치환 번호를 쓰고, 외부 메시지 파일(.txt)에는...

 

m00000>=테스트입니다.

 

이런 식으로 치환할 메시지를 입력하는 것이다.

 

다행히도 런처의 기본 소스는 '코에이 게임 연구소' 카페에서 얻을 수 있었다. (링크)

이 분에게는 대항해시대2 윈도우95판 한글화 때 엔딩 메시지 관련으로 도움 받은 게 있는데 여기서 또 도움을 받게 되었다. (크흑... 압도적 감사...)

다만 내가 C++을 다뤄본 적이 없기 때문에, 여기 있는 코드를 VB.Net에다 베껴 적어 보았다.

무슨 Structure라는 걸 엄청나게 많이 입력해야만 했다.

 

하지만 전혀 실행이 되지 않았다.

 

자꾸만 여기에서 막히고 저기에서 막힌다...

결국 비베닷넷에 입력하는 건 때려치고 일단 실행만 시켜보자는 식으로 원래 코드인 C++을 쓰기로 하였다. dev c++도 설치했다.

 

dev c++로 컴파일을 하려고 드니까 여기서도 컴파일러가 자꾸 'Eax? Rax와 착각한 거 아니냐?' 라는 소리만 떠들고 있었다.

하도 그러길래 소스 안의 Eax... 그러니까 E시리즈를 모두 R시리즈로 바꿔버렸다. 이렇게 하니까 변수 몇 개의 자료형에도 문제가 터지길래 (아마 unsigned long으로 들어가는 변수였을 거다.) 그것도 unsigned long long 이런 식으로 바꿔주었다.

그렇게 하니 일단 화면까지는 떴으나 동영상 재생에 실패하고 STATUS_ACCESS_VIOLATION 오류를 뿜으면서 튕겼다.

 

비베닷넷쪽도 계속 수리를 시도해서 화면 띄우기까지는 성공했다. (아마 CONTEXT를 WOW64_CONTEXT로 바꿨던 것 같다.)

그러나 여기도 동영상 재생에 실패하고 똑같은 오류가 떴다.

 

치트엔진으로 보니까 브레이크 포인트(0xCC, 이 값을 컴퓨터가 인지하면 멈추는 모양이다.) 는 잘 들어가는 것 같은데... 왜 자꾸 '접근 위반' 타령을 하는 걸까?

 

그러다가 얼떨결에 '작업 관리자'의 프로세스 목록을 보게 되었다. 그런데... 컴파일한 파일 옆에 (32비트) 라는 문구가 없었다.

설마 컴파일된 파일이 64비트 실행파일이라서? 컴파일러를 보니 64-bit Release로 설정되어 있었다. 혹시 이것 때문에...?

나는 32-bit Release컴파일러를 바꾸었다.

 

컴파일러를 바꾸고 코드도 원본 코드로 다 복귀시켰다. 그리고 브레이크 포인트를 밟으면 메시지 박스가 출력되도록 하고 실행해보니까... 오오!!! 메시지 박스가 출력되고 게임도 실행되었다.

 

이제 남은 일은 외부 텍스트 파일의 치환 번호와 치환할 메시지를 가져오고, 문장이 저장되는 메모리 주소에서 치환 번호를 발견할 시 메시지를 바꿔치기 하는 것... 이렇게 크게 두 가지다.

과연 내가 구현할 수 있을까? 이제 믿을 건 구글링 실력과 Stackoverflow 뿐이다.

 

일단 메시지 파일 안에는 미리 테스트용 치환 번호를 입력해두고 시작한다.

 

1단계 : 외부 텍스트 파일에서 치환 번호와 치환 문자열을 읽어들이는 기능을 구현했다.

(아직은 이걸로 치환하지 않는다.)

 

2단계 : m00000 이라는 치환 번호를 인식하면 '테스트입니다.' 가 출력되도록 하였다.

여기서 많이 게임이 튕겼고, 오류 주소는 대부분 0x77****** / 0x76****** 쪽이었다.

온갖 삽질 끝에 그 이유를 알아냈는데, 원인은 '한계 용량을 초과한 메시지 파일' 때문이었다. 그래서 용량을 초과하지 않은 메시지 파일로 교체해서 테스트했다.

'바이트 카운트'와 '출력 문장 마지막 주소'도 런처가 알아서 계산하도록 하였다. 

 

3단계 : m00000(m+숫자 5개)라는 유형의 치환 번호를 인식하면 외부 텍스트 파일에서 가져온 치환 번호와 대조해보고, 일치할 경우 해당 치환 번호가 가진 치환 메시지를 출력하게 만들었다. (m00000에 '테스트입니까?'를 넣었는데 잘 나온다.)

 

4단계 : 원본 메시지를 먼저 다 읽어들인 뒤에 치환 번호로 인식되면 치환 메시지로 바꿔주고, 아니면 그냥 원본 메시지대로 출력되도록 하였다. 이렇게 하니 치환 메시지가 원본 메시지 안에 포함되서 출력되었다.

 

5단계 : 치환될 메시지 문자열에서 \n 이라는 문자는 메모리에 [0A]로 집어넣도록 하였다. [0A]는 게임 내에서 개행문자(줄바꿈)로 사용되는 바이트다.

 

 

6단계 : 여기까지 온 김에, 한국어 조사 처리 구현까지 도전하기로 한다.

일단 조사 판별에 쓸 식별자를 지정하도록 한다.

 

$1 : 은/는

$2 : 이/가

$3 : 을/를

$4 : 과/와

$5 : 이/-  (~이랑 / ~이라면 할때의 '이')

$6 : 으로/로

$7 : 아/야

 

표로 정리하자면 다음과 같다.

식별자 앞 글자
종성 ㄹ이외
앞 글자
종성 ㄹ
앞 글자
종성 없음
$1
$2
$3
$4
$5 - (탈락)
$6 으로
$7

'으로/로' 때문에 [종성 있음 / 종성 없음]으로 구분하지 못하고 [종성 ㄹ이외 / 종성 ㄹ / 종성 없음] 이렇게 구분해야 되는 것 같다.

기본값은 '종성 ㄹ이외' 로 둔다. (은/이/을/과/이/으로/아)

 

종류 판별 방식은 먼저 조사 식별자 바로 앞에 있는 한글 1음절을 가져와서 '유니코드 코드 포인트' 화 시킨다.

유니코드에는 한글이 규칙적으로 배열되어 있기 때문에 이 값을 가지고 판별해야 편하다고 한다.

그런 다음 해당 값을 다음과 같이 계산한다.

 

종성 없음 : 해당 값에서 AC00 (가) 을 빼고 28로 나눈 나머지가 0일 경우

종성 있음 : 해당 값에서 AC00 (가) 을 빼고 28로 나눈 나머지가 0이 아닐 경우 한번 더 검사.

 ㄴ 종성 ㄹ : 해당 값에서 AC08 (갈) 을 빼고 28로 나눈 나머지가 0일 경우

 ㄴ 종성 ㄹ이외 : 해당 값에서 AC08 (갈) 을 빼고 28로 나눈 나머지가 0이 아닐 경우

한글이 아님 : 해당 값이 AC00 (가) ~ D7A3 (힣) 범위 안에 있지 않을 경우

 

판별 코드는 여기에서 가져온 다음 약간 수정했다.

 

일단 조사 식별자를 인식하고 치환되게 하는 데에는 성공했다.

문제는, 종성을 판단할때 유니코드 값으로 판단하지 못하고 한국어 인코딩(CP949)의 코드로 판단을 한다는 것이다.

'나' 자는 유니코드로 0xB098인데, 지금은 CP949의 0xB3AA로 값을 넣어서 종성 여부를 판단하고 있다.

그럼 어떻게 해야 CP949의 글자를 유니코드 값으로 변환할 수 있을까? 인터넷을 뒤져서 여러 관련 소스들을 추가해봤지만 자료형 문제 등으로 컴파일 오류만 떴다. 어쩌다가 실행이 되더라도 제대로 변환되지 않았다.

 

그렇게 한참 인터넷을 뒤지다가 IBM 사이트 문서에서 UTF16으로 변환하는 코드를 보게 되었다. (출처)

UTF16 인코딩에서 '가' 는 0xAC00으로 유니코드 코드 포인트와 똑같다. 어? 혹시... 이거 잘하면 조사 식별할때 써먹을 수 있을지도?

 

시험 삼아 '가' 자를 넣어보니 결과가 0xAC00으로 나온다. 좋다. 여기 변수에다가 값을 넣는 식으로 진행하면 되겠다.

 

이제 조사 처리 함수에 CP949 값이 아닌 유니코드(사실은 UTF16) 값이 들어가면서 정상적으로 종성 여부를 판단할 수 있게 되었다.

 

메시지 치환 런처는 이 정도면 거의 완성되었다고 보면 된다. 처음에는 'test' 라는 메시지 박스 하나 출력시키는 것도 버거웠는데... 마침내 여기까지 왔다.

 

 

12. 메시지 파일 전부 이식 후 용량 초과 분량 덜어내기

이제 런처도 성공적으로 구현되었고, 남은 일은 '일판 메시지 파일에 한글판 문장 전부 이식' 그리고 '용량이 초과된 메시지 파일을 적정 용량으로 회복' 시키는 것이다.

한글판의 모든 문장 이식이 끝나면 현재의 메시지 파일 용량이 일판 원본 메시지 용량보다 적어질때까지 문장들을 외부 메시지 파일(.txt)로 덜어내야 한다.

덜어낼때 메시지 파일에서는 치환 번호로 바꿔놓는다. 이때 원래의 제어코드인 {01}" 와 {05}{05}{05}에 주의해서 덜어내야 한다.

엑셀을 통해서 덜어내면 좀 더 편하게 덜어낼 수 있다. 텍스트 파일로 출력할때는 '다른 이름으로 저장 - 텍스트 (탭으로 분리)' 로 출력시킨다. 그 후 메모장의 바꾸기 기능으로 탭을 없애고, 따옴표(")도 없애면 된다.

 

용량 초과로 제대로 뜨지 않았던 보물 열전도 외부 메시지 파일을 통해 잘 출력되고 있다. 감격스럽다.

 

중간중간에 에디터에서 튀어나오는 버그들도 고쳐나갔다.

 

...그렇게 작업한 끝에 한글판의 모든 문장을 일판 메시지 파일에 이식시켰다. 이제 남은 건 용량 초과 분량 덜어내기 작업 뿐이다.

 

 

- 스크롤 압박으로 인해 4부에서 계속 -