STUDIO HAZE · jeniapp
Topaz source
Open by house policy. Topaz is our own language.
Topaz 5.20.2 · 63 files
apps/secret-train/core/state.tpz
Topaz · 5869 B · Original file
1
// 비밀열차의 저장 상태와 그 문자열 형식입니다. 턴마다 바뀌는 사실만 담고 지도와 순찰 경로는 data.levels 에서 읽습니다.2
// 저장 문자열은 BT1|시드|레벨코드|턴|제한턴|x|y|방향|열쇠|가방|결말|경비단계|안내|버팀 이고 경비단계는 ; 로 잇습니다.3
// 경비는 순찰 단계만 저장하고 위치와 방향은 그 단계에서 다시 구하므로 같은 문자열은 늘 같은 상태가 됩니다.4
// 13칸보다 짧으면 첫 칸 처음으로 두고, 읽을 수 없는 숫자는 기본값으로 읽은 뒤 모든 값을 레벨과 범위 안으로 가둡니다. 첫 칸의 판 표시는 보지 않습니다.5
// Secret train save state and its BT1 save string format.7
import data.levels9
// 정상 플레이의 제한턴은 레벨 값이라 이 상한에 닿지 않습니다. 턴은 제한턴 아래로 가두므로 한 턴 뒤의 + 1 과 흔들림 예고의 + 흔들주기가 64비트를 넘지 않습니다.10
let 턴상한 = 100000000012
export type 결말종류 = "진행" | "탈출" | "발각" | "놓침"13
export type 안내종류 = "없음" | "열쇠" | "가방" | "승리" | "발각" | "놓침" | "버팀" | "다음칸"15
// 버팀은 이번 턴 좌석을 잡아 흔들림과 시야를 피했는지입니다.16
export type 상태 = {17
시드: string,18
레벨코드: string,19
턴: int,20
제한턴: int,21
x: int,22
y: int,23
방향: levels.방향,24
열쇠있음: bool,25
가방있음: bool,26
버팀: bool,27
결말: 결말종류,28
경비단계들: Array<int>,29
안내: 안내종류,30
}32
// 결말과 안내는 셸이 읽는 번호라 저장 문자열과 HUD 줄에서만 숫자로 씁니다. 모르는 번호는 진행과 없음으로 읽습니다.33
export function 결말번호(결말값: 결말종류) -> int {34
match 결말값 {35
case "진행" => 036
case "탈출" => 137
case "발각" => 238
case "놓침" => 339
}40
}42
function 결말읽기(번호: int) -> 결말종류 {43
match 번호 {44
case 1 => "탈출"45
case 2 => "발각"46
case 3 => "놓침"47
case _ => "진행"48
}49
}51
export function 안내번호(안내값: 안내종류) -> int {52
match 안내값 {53
case "없음" => 054
case "열쇠" => 155
case "가방" => 256
case "승리" => 357
case "발각" => 458
case "놓침" => 559
case "버팀" => 660
case "다음칸" => 761
}62
}64
function 안내읽기(번호: int) -> 안내종류 {65
match 번호 {66
case 1 => "열쇠"67
case 2 => "가방"68
case 3 => "승리"69
case 4 => "발각"70
case 5 => "놓침"71
case 6 => "버팀"72
case 7 => "다음칸"73
case _ => "없음"74
}75
}77
export function 레벨시작상태(시드: string, 레벨코드: string, 안내: 안내종류) -> 상태 {78
let 레벨 = levels.레벨얻기(레벨코드)79
{80
시드: 시드,81
레벨코드: 레벨코드,82
턴: 0,83
제한턴: 레벨.제한턴,84
x: 레벨.시작.x,85
y: 레벨.시작.y,86
방향: "아래",87
열쇠있음: false,88
가방있음: false,89
버팀: false,90
결말: "진행",91
경비단계들: 레벨.시작단계들,92
안내: 안내,93
}94
}96
export function 기본상태(시드: string) -> 상태 {97
레벨시작상태(시드, "L01", "없음")98
}100
export function 일또는영(참거짓: bool) -> int {101
if 참거짓 { 1 } else { 0 }102
}104
// 경비가 없어도 칸 수가 줄지 않게 - 를 적습니다.105
function 단계문자열(단계들: Array<int>) -> string {106
if 단계들.length == 0 { "-" } else { 단계들.map(단계 => "{단계}").join(";") }107
}109
export function 직렬화(현재: 상태) -> string {110
let 단계 = 단계문자열(현재.경비단계들)111
"BT1|{현재.시드}|{현재.레벨코드}|{현재.턴}|{현재.제한턴}|{현재.x}|{현재.y}|{levels.방향번호(현재.방향)}|{일또는영(현재.열쇠있음)}|{일또는영(현재.가방있음)}|{결말번호(현재.결말)}|{단계}|{안내번호(현재.안내)}|{일또는영(현재.버팀)}"112
}114
// 개수가 레벨의 경비 수와 다르면 그 레벨의 시작 단계로 두고, 각 단계는 그 경비의 순찰 길이 안으로 가둡니다.115
function 단계읽기(필드: string, 레벨: levels.레벨정보) -> Array<int> {116
let 조각들: Array<string> = if 필드 == "-" || 필드 == "" { [] } else { 필드.split(";") }117
if 조각들.length != 레벨.경비들.length { return 레벨.시작단계들 }118
[for i in 0..<조각들.length => (toInt(조각들[i]) ?? 0).atLeast(0).atMost(레벨.경비들[i].순찰.length - 1)]119
}121
function 참인가(필드: string) -> bool {122
(toInt(필드) ?? 0) == 1123
}125
export function 역직렬화(저장: string, 대체시드: string) -> 상태 {126
let 필드들 = 저장.split("|")127
if 필드들.length < 13 { return 기본상태(대체시드) }128
let 레벨 = levels.레벨얻기(필드들[2])129
let 제한턴 = (toInt(필드들[4]) ?? 레벨.제한턴).atLeast(1).atMost(턴상한)130
let x = toInt(필드들[5]) ?? 레벨.시작.x131
let y = toInt(필드들[6]) ?? 레벨.시작.y132
// 플레이어는 바닥으로만 움직이므로 바닥이 아닌 칸은 레벨 시작 칸으로 되돌립니다.133
let 바닥위 = levels.바닥인가(레벨, x, y)134
{135
시드: 필드들[1],136
레벨코드: levels.레벨코드(레벨),137
턴: (toInt(필드들[3]) ?? 0).atLeast(0).atMost(제한턴),138
제한턴: 제한턴,139
x: if 바닥위 { x } else { 레벨.시작.x },140
y: if 바닥위 { y } else { 레벨.시작.y },141
방향: levels.방향읽기(toInt(필드들[7]) ?? 2),142
열쇠있음: 참인가(필드들[8]),143
가방있음: 참인가(필드들[9]),144
// 버팀 칸이 없는 13칸 저장도 읽습니다.145
버팀: 필드들.length >= 14 && 참인가(필드들[13]),146
결말: 결말읽기(toInt(필드들[10]) ?? 0),147
경비단계들: 단계읽기(필드들[11], 레벨),148
안내: 안내읽기(toInt(필드들[12]) ?? 0),149
}150
}SHA256 39a2a8e78510f4e2c0aad0ec04f1fcc8a9fdd258d62e12528db2a43e6cb5ba0f