도스 삼국지2 - 에디터 (#6) / 출현 장수 데이터 분석
게임을 하다보면 탐색으로 발견되는 장수도 있고 혈연으로 묶여 자동으로 추가되는 장수도 있다.
마등에게는 마초/마대/마철이 그러하고, 손책에게는 여몽/주유/손권이 그러하며 또 손권에게는 손유/손익/노숙이 그러하다
1번 시나리오로 하다보면 마등에게서 192년에 마초와 193년에 마대가 194년에 마철이 자동으로 추가된다.
또 191년 21번 땅에서 감녕을 탐색 할 수 있으며, 3번 땅에서 조운을 그리고 10번 땅에서 만총을 탐색할 수 있다.
이러한 각 시나리오별로 짜여진 각본(?)이 TAIKI.DAT 파일에 들어있다.
오늘은 이 데이터를 분석해 보도록 한다.
파일에는 각 시나리오별(6개의) 나타날 장수들의 목록이 기록되어 있다.
나타나는 조건은 2종류인데
하나는 특정 지역에서 해당 연도 이후에 탐색 가능한 상태가 되는 경우다.
예를 들어 시나리오1에서 191년이 되면 21번 땅에서 감녕이, 3번 땅에서 조운이 10번 땅에서 만총이 탐색으로 발견된다.
다른 하나는 해당 연도에 혈연을 가진 장수가 자동으로 추가되는 경우다.
이 경우 혈연의 대상자가되는 장수를 보유하고 있다면 그 땅에서 장수로 등록되어 진다.
예를 들어 시나리오1에서 어찌어찌하여 손책을 보유(손견으로 시작하든 아니면 손책을 뺏어오든)하고 있다면
194년에 여몽이 195년에 주유가 198년에 손권이 손책이 있는 땅에 추가된다
파일 첫 6바이트는 각 시나리오별 기록되어 있는 장수의 카운트를 나타낸다.
각 바이트는 162, 105, 76, 43, 22, 10 이라는 숫자를 가지고 있다.
이는,
시나리오1에서는 162명의 장수가
시나리오2에서는 105명의 장수가
...
시나리오6에서는 10명의 장수가 추가될 것이라는 기록을 의미한다.
한글판의 경우 시나리오별 각 장수 데이터의 크기는 39 byte(영문판은 46)를 가지고 있으며
전체 크기에서 첫 6바이트를 제외한 나머지를 39로 나누면 420이라는 숫자가 나옴을 알 수 있다.
한글판 : (전체 크기 16,386 byte - 6 byte) / 장수 데이터 39 byte = 420
영문판 : (전체 크기 19,326 byte - 6 byte) / 장수 데이터 46 byte = 420
// 장수 데이터
const data = readTaikiData.slice() // 읽어온 TAIKI.DAT file data
let start = 0
// 처음 6byte는 각 시나리오별 장수의 수
let length = 6
let offset = start + length
let scenarioSums = data.slice(start, offset)
let scenarios = []
let sum = 0
// 모든 시나리오별 장수의 누적 카운트 계산
scenarioSums.forEach(e=>{
sum += 0
scenarios.push(sum)
})
// 시나리오 번호
let scenarioIdx = 0
length = 39 // 한글판의 경우
// 화면에 그릴 장수 데이터
const drawTaikiDataArray = []
const totalCount = (data.length-6)/length // 수정하지 않는다면 이 값은 420이다.
// 모든 장수 데이터를 뽑아보자.
for (let i=0; i<totalCount; i++) {
start = offset
offset = start + length
const taiki = data.slice(start, offset)
const drawTaiki = parseTaikiData(i, taiki)
const t = {
idx: i+1,
...drawTaiki
}
// 현재 누적 수가 시나리오 단계의 누적수에 도달하면 시나리오 번호 변경.
if (i===scenarios[scenarioIdx]) {
// 시나리오 번호가 4(0 base이므로)까지는 시나리오 번호 증가
if (scenario<5) {
scenario++
} else {
// 시나리오 번호가 5이상이면 더이상 시나리오가 없으므로 -1로 세팅한다.
scenario = -1
}
}
if (scenarioIdx>-1) {
// 정상적인 시나리오 번호
t.scenario = sceanrioIdx + 1
}
drawTaikiDataArray.push(t)
}
이렇게 전체 시나리오의 모든 장수를 읽어왔다.
이제 위에서 쓰인 parseTaikiData를 통해 장수 데이터를 분석해 보자.
// parseTaikiData (index, data, isKor=true) {}
let pos = 0
// offset 0은 나타나게될 연도이다. (0 base)
const appearYear = data[pos++]
// offset 1은 혈연 관계에 있는 장수의 faceMainId이다. 즉 조합형 얼굴의 장수는 혈연 관계로 묶어 시나리오에 나타나게 할 수 없다.
// 신군주의 경우 faceMainId가 있는 완성형 얼굴이므로 특정 장수를 시나리오상에 등록 할 수 있는 것이다.
const familyFaceId = data[pos++]
// offset 2는 나타나게될 땅(Province) 번호이다. (0 base)
const appearProv = data[pos++]
// 위의 familyFaceId 값이 없는 경우에 appearyYear에 이 땅에서 탐색으로 찾을 수 있다.
// offset 3~6은 모름
const unknown1 = data.splice(pos, pos+4)
pos += 4
// offset 7은 장수의 지력
const int = data[pos++]
// offset 8은 장수의 무력
const war = data[pos++]
// offset 9는 장수의 매력
const chm = data[pos++]
// offset 10은 장수의 의리
const trust = data[pos++]
// offset 11은 장수의 인덕
const good = data[pos++]
// offset 12는 장수의 야망
const amb = data[pos++]
// offset 13은 군주의 번호, 당연히 소속전이므로 255이다.
let tmp = data[pos++]
const rulerNumber = tmp===15?254:tmp
// offset 14는 충성도이다. 당연히 값은 0이다.
const loy = data[pos++]
// offset 15는 사관(소속으로 종사한 년수), 당연히 값은 0이다.
const off = data[pos++]
// offset 16~17은 아직 모름
const unknown2 = data[pos++] | data[pos++] << 8
// offset 18은 장수의 상성 값 (1~100), 1은 위, 50은 촉, 100은 오에 가깝다.
const syn = data[pos++]
// offset 19~27은 아직 모름
const unknown3 = data.slice(pos, pos+9)
pos+=9
// offset 28은 태어난 연도
const born = data[pos++]
// offset 29~30은 faceMainId / faceSubId
const faceMainId = data[pos++]
const faceSubId = data[pos++]
// 조합형 얼굴번호
const fullFace = faceMainId | faceSubId << 8
// offset 31~36은 이름 (영문판은 31~43)
const name = data.slice(pos, pos+6)
pos += 6
// offset 37~38은 모름 (영문판은 44~45)
const unknown4 = data[pos++] | data[pos++] << 8
이렇게 시나리오의 장수 데이터를 분석해 보았다.
appearYear(1) | familyFaceId(1) | appearProv(1) | unknown1(4) | int(1) | war(1) | chm(1) | trust(1) | good(1) | amb(1) | rulerNum(1) | loy(1) | off(1) | unknown2(2) | syn(1) | unknown3(9) | born(1) | faceMainId(1) | faceSubId(1) | unknown4(2)
가져온 데이터를 페이지에 그려 본다. (Material-ui : Box, Table, TableHead, TableBody 등, 이미지는 canvas에 직접 그림)
** 번호 / 이름(시나리오번호) / 얼굴 / 혈연 / 상성 / 태어난연도 / 나타나는연도 / 나타나는땅번호 / 지력 / 무력 / 매력 / 의리 / 인덕 / 야망
지금까지 KAODATA.DAT, MONTAGE.DAT, save file, TAIKI.DAT를 분석 해 보았다.
다음은 각 시나리오 데이터가 저장되어 있는 SCENARIO.DAT를 분석 해 보자.