-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlunistice.split
More file actions
175 lines (155 loc) · 4.75 KB
/
Copy pathlunistice.split
File metadata and controls
175 lines (155 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/// The attached Lunistice edition selected from its managed metadata shape.
enum Edition {
/// The original game, whose level is stored as a numeric index.
BaseGame,
/// The DLC demo, whose current scene is stored as a managed string.
DlcDemo,
}
/// High-level state encoded by Lunistice's managed `GameState` integer.
enum GameState: i32 {
Mission = 0,
TitleScreen = 1,
Menu = 2,
Cutscene = 3,
Death = 4,
Respawn = 5,
Results = 6,
Load = 7,
}
/// Attachment-static edition inferred from the managed metadata shape.
let edition: Edition
struct LevelTimeParts {
minutes: f32,
seconds: f32,
hundredths: f32,
}
/// Managed gameplay state shared by the original game and DLC demo.
image "Assembly-CSharp" {
class GameManager {
/// The live game-manager singleton.
static GameManager instance from "Instance";
/// The current high-level game state.
GameState gameState from ["gameState", "<GameState>k__BackingField"];
/// Points collected in this run.
u32 points from "_points";
/// Deaths accumulated in this run.
u32 deaths from "_deaths";
if edition == Edition.BaseGame {
/// The original game's numeric level index.
i32 level from "currentLevel";
} else {
/// The DLC demo's current managed scene name.
String scene from "_currentScene";
}
}
class Timer {
/// The live timer singleton across known game versions.
static Timer instance from ["Instance", "_instance"];
/// Elapsed time in the current level.
f32 levelTime from "currentLevelTime";
/// Display digits maintained by the game's timer UI.
LevelTimeParts levelTimeParts from "currentLevelTimeVector";
/// Whether the in-game timer is stopped.
bool stopped from "timerStopped";
/// The currently selected playable character.
u32 character;
}
}
state Unity.il2cpp(Il2CppProfile.unity2022_2_0f1X64()) ["Lunistice.exe", "Lunistice-Demo.exe"] {
gameManager: GameManager = GameManager.instance?.snapshot()?;
timer: Timer = Timer.instance?.snapshot()?;
}
let runTimeSeconds
let beyondFirstLevel
onStart {
runTimeSeconds = 0
beyondFirstLevel = false
}
fn twoDigits(value) {
if value < 10 {
return `0{value}`
}
return value as String
}
fn LevelTimeParts.toString() {
return `{self.minutes as u32}:{twoDigits(self.seconds as u32)}.{twoDigits(self.hundredths
as u32)}`
}
fn levelText(level) {
let uncappedStage = level / 2 + 1
let stage = uncappedStage.min(7)
let act = if level == 14 {
"X"
} else if level & 1 == 0 {
"1"
} else {
"2"
}
return `{stage}-{act}`
}
fn characterName(character, dlcDemo) {
return match character {
0 => "Hana",
1 => "Toree",
2 => "Toukie",
3 if dlcDemo => "Accel",
3 => "Erika",
4 if dlcDemo => "Five",
4 => "Lea",
5 if !dlcDemo => "Null",
6 if dlcDemo => "Cres",
7 if dlcDemo => "BoxBuddy",
_ => "Unknown",
}
}
whileAttached {
setVariable("Points", current.gameManager.points)
setVariable("Resets", current.gameManager.deaths)
setVariable("Level Time", current.timer.levelTimeParts)
if edition == Edition.BaseGame {
setVariable("Level", levelText(current.gameManager.level))
} else {
setVariable("Scene", current.gameManager.scene)
}
setVariable(
"Character",
characterName(current.timer.character, edition == Edition.DlcDemo),
)
}
start {
let isFirstLevel = if edition == Edition.BaseGame {
current.gameManager.level == 0
} else {
current.gameManager.scene == "Shrine01"
}
if old.timer.stopped != current.timer.stopped && !current.timer.stopped && isFirstLevel {
return true
}
}
reset {
if current.timer.levelTime < old.timer.levelTime && !beyondFirstLevel {
return true
}
}
split {
let enteredResults = old.gameManager.gameState != GameState.Results
&& current.gameManager.gameState == GameState.Results
let creditsTransition = edition == Edition.BaseGame
&& old.gameManager.level >= 13
&& current.gameManager.level == 2
if enteredResults || creditsTransition {
beyondFirstLevel = true
return true
}
}
// ASR pauses game time once the run starts and supplies the accumulated game
// time explicitly. Returning true keeps LiveSplit's game-time clock paused.
isLoading {
return true
}
gameTime {
if current.timer.levelTime < old.timer.levelTime && beyondFirstLevel {
runTimeSeconds += old.timer.levelTime
}
return Duration.fromSeconds(runTimeSeconds + current.timer.levelTime)
}