diff --git a/profiles/cclcc/savedata.lua b/profiles/cclcc/savedata.lua index 7847fe1d9..959f4c666 100644 --- a/profiles/cclcc/savedata.lua +++ b/profiles/cclcc/savedata.lua @@ -156,4 +156,21 @@ root.SaveData = { {{0x20B}}, {{0x20C}}, } -}; \ No newline at end of file +}; + +local scriptIds = { + KN01 = 38, + KN17 = 54, + KN18 = 55, +}; + +root.SaveData.EquivalentLines = { + { + {ScriptId = scriptIds.KN01, StartLineId = 387, EndLineId = 397}, + {ScriptId = scriptIds.KN01, StartLineId = 483, EndLineId = 493}, + }, + { + {ScriptId = scriptIds.KN17, StartLineId = 0, EndLineId = 40}, + {ScriptId = scriptIds.KN18, StartLineId = 0, EndLineId = 40}, + }, +}; diff --git a/profiles/chlcc/equivalentlines.lua b/profiles/chlcc/equivalentlines.lua new file mode 100644 index 000000000..09b3984ee --- /dev/null +++ b/profiles/chlcc/equivalentlines.lua @@ -0,0 +1,725 @@ +local scriptIds = { + AA08 = 12, + AA09 = 13, + AA14 = 18, + AY03 = 27, + KO05 = 38, + NA02 = 45, + NA03 = 46, + RI01 = 53, + YU02A = 70, + YU02B = 71, + YU03A = 72, + YU03B = 73, + YU04A = 74, + YU04B = 75, + YU05A = 76, + YU05B = 77, + YU06A = 78, + YU06B = 79, + YU07A = 80, + YU07B = 81, + YU08A = 82, + YU08B = 83, + YU09A = 84, + YU09B = 85, +}; + +root.SaveData.EquivalentLines = { + { + {ScriptId = scriptIds.AA08, StartLineId = 80, EndLineId = 87}, + {ScriptId = scriptIds.AA08, StartLineId = 217, EndLineId = 224}, + }, + { + {ScriptId = scriptIds.AA08, StartLineId = 88, EndLineId = 96}, + {ScriptId = scriptIds.AA08, StartLineId = 231, EndLineId = 239}, + }, + { + {ScriptId = scriptIds.AA09, StartLineId = 205, EndLineId = 220}, + {ScriptId = scriptIds.AA09, StartLineId = 296, EndLineId = 311}, + }, + { + {ScriptId = scriptIds.AA14, StartLineId = 442, EndLineId = 449}, + {ScriptId = scriptIds.AA14, StartLineId = 500, EndLineId = 507}, + }, + { + {ScriptId = scriptIds.AY03, StartLineId = 22, EndLineId = 35}, + {ScriptId = scriptIds.KO05, StartLineId = 18, EndLineId = 31}, + }, + { + {ScriptId = scriptIds.AY03, StartLineId = 51, EndLineId = 57}, + {ScriptId = scriptIds.NA03, StartLineId = 249, EndLineId = 255}, + }, + { + {ScriptId = scriptIds.NA02, StartLineId = 340, EndLineId = 346}, + {ScriptId = scriptIds.RI01, StartLineId = 184, EndLineId = 190}, + }, + { + {ScriptId = scriptIds.YU02A, StartLineId = 0, EndLineId = 2}, + {ScriptId = scriptIds.YU02B, StartLineId = 0, EndLineId = 2}, + }, + { + {ScriptId = scriptIds.YU02A, StartLineId = 4, EndLineId = 98}, + {ScriptId = scriptIds.YU02B, StartLineId = 3, EndLineId = 97}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 0, EndLineId = 14}, + {ScriptId = scriptIds.YU03B, StartLineId = 0, EndLineId = 14}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 16, EndLineId = 24}, + {ScriptId = scriptIds.YU03B, StartLineId = 16, EndLineId = 24}, + }, + { + {ScriptId = scriptIds.YU03A, LineId = 26}, + {ScriptId = scriptIds.YU03B, LineId = 26}, + }, + { + {ScriptId = scriptIds.YU03A, LineId = 28}, + {ScriptId = scriptIds.YU03B, LineId = 28}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 31, EndLineId = 33}, + {ScriptId = scriptIds.YU03B, StartLineId = 31, EndLineId = 33}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 35, EndLineId = 36}, + {ScriptId = scriptIds.YU03B, StartLineId = 35, EndLineId = 36}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 38, EndLineId = 39}, + {ScriptId = scriptIds.YU03B, StartLineId = 38, EndLineId = 39}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 41, EndLineId = 42}, + {ScriptId = scriptIds.YU03B, StartLineId = 41, EndLineId = 42}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 44, EndLineId = 46}, + {ScriptId = scriptIds.YU03B, StartLineId = 44, EndLineId = 46}, + }, + { + {ScriptId = scriptIds.YU03A, LineId = 49}, + {ScriptId = scriptIds.YU03B, LineId = 49}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 53, EndLineId = 57}, + {ScriptId = scriptIds.YU03B, StartLineId = 53, EndLineId = 57}, + }, + { + {ScriptId = scriptIds.YU03A, LineId = 60}, + {ScriptId = scriptIds.YU03B, LineId = 60}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 62, EndLineId = 71}, + {ScriptId = scriptIds.YU03B, StartLineId = 62, EndLineId = 71}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 73, EndLineId = 95}, + {ScriptId = scriptIds.YU03B, StartLineId = 73, EndLineId = 95}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 97, EndLineId = 125}, + {ScriptId = scriptIds.YU03B, StartLineId = 97, EndLineId = 125}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 129, EndLineId = 154}, + {ScriptId = scriptIds.YU03B, StartLineId = 129, EndLineId = 154}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 155, EndLineId = 160}, + {ScriptId = scriptIds.YU03B, StartLineId = 156, EndLineId = 161}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 162, EndLineId = 169}, + {ScriptId = scriptIds.YU03B, StartLineId = 163, EndLineId = 170}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 171, EndLineId = 184}, + {ScriptId = scriptIds.YU03B, StartLineId = 172, EndLineId = 185}, + }, + { + {ScriptId = scriptIds.YU03A, LineId = 186}, + {ScriptId = scriptIds.YU03B, LineId = 187}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 188, EndLineId = 216}, + {ScriptId = scriptIds.YU03B, StartLineId = 188, EndLineId = 216}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 218, EndLineId = 229}, + {ScriptId = scriptIds.YU03B, StartLineId = 218, EndLineId = 229}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 231, EndLineId = 250}, + {ScriptId = scriptIds.YU03B, StartLineId = 231, EndLineId = 250}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 252, EndLineId = 254}, + {ScriptId = scriptIds.YU03B, StartLineId = 252, EndLineId = 254}, + }, + { + {ScriptId = scriptIds.YU03A, StartLineId = 257, EndLineId = 259}, + {ScriptId = scriptIds.YU03B, StartLineId = 257, EndLineId = 259}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 0, EndLineId = 8}, + {ScriptId = scriptIds.YU04B, StartLineId = 0, EndLineId = 8}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 11, EndLineId = 23}, + {ScriptId = scriptIds.YU04B, StartLineId = 11, EndLineId = 23}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 26}, + {ScriptId = scriptIds.YU04B, LineId = 26}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 28}, + {ScriptId = scriptIds.YU04B, LineId = 28}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 30}, + {ScriptId = scriptIds.YU04B, LineId = 30}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 32}, + {ScriptId = scriptIds.YU04B, LineId = 32}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 34, EndLineId = 51}, + {ScriptId = scriptIds.YU04B, StartLineId = 34, EndLineId = 51}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 53, EndLineId = 65}, + {ScriptId = scriptIds.YU04B, StartLineId = 53, EndLineId = 65}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 68, EndLineId = 70}, + {ScriptId = scriptIds.YU04B, StartLineId = 68, EndLineId = 70}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 72, EndLineId = 88}, + {ScriptId = scriptIds.YU04B, StartLineId = 72, EndLineId = 88}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 90, EndLineId = 93}, + {ScriptId = scriptIds.YU04B, StartLineId = 90, EndLineId = 93}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 95, EndLineId = 96}, + {ScriptId = scriptIds.YU04B, StartLineId = 95, EndLineId = 96}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 99, EndLineId = 102}, + {ScriptId = scriptIds.YU04B, StartLineId = 98, EndLineId = 101}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 104}, + {ScriptId = scriptIds.YU04B, LineId = 103}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 106, EndLineId = 107}, + {ScriptId = scriptIds.YU04B, StartLineId = 105, EndLineId = 106}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 109, EndLineId = 112}, + {ScriptId = scriptIds.YU04B, StartLineId = 108, EndLineId = 111}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 116, EndLineId = 118}, + {ScriptId = scriptIds.YU04B, StartLineId = 114, EndLineId = 116}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 120}, + {ScriptId = scriptIds.YU04B, LineId = 118}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 122, EndLineId = 124}, + {ScriptId = scriptIds.YU04B, StartLineId = 120, EndLineId = 122}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 127, EndLineId = 130}, + {ScriptId = scriptIds.YU04B, StartLineId = 125, EndLineId = 128}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 134, EndLineId = 135}, + {ScriptId = scriptIds.YU04B, StartLineId = 132, EndLineId = 133}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 152}, + {ScriptId = scriptIds.YU04B, LineId = 149}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 155, EndLineId = 158}, + {ScriptId = scriptIds.YU04B, StartLineId = 153, EndLineId = 156}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 160}, + {ScriptId = scriptIds.YU04B, LineId = 158}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 163, EndLineId = 164}, + {ScriptId = scriptIds.YU04B, StartLineId = 161, EndLineId = 162}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 166}, + {ScriptId = scriptIds.YU04B, LineId = 164}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 170, EndLineId = 172}, + {ScriptId = scriptIds.YU04B, StartLineId = 168, EndLineId = 170}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 176, EndLineId = 177}, + {ScriptId = scriptIds.YU04B, StartLineId = 174, EndLineId = 175}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 179}, + {ScriptId = scriptIds.YU04B, LineId = 177}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 181, EndLineId = 185}, + {ScriptId = scriptIds.YU04B, StartLineId = 179, EndLineId = 183}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 193}, + {ScriptId = scriptIds.YU04B, LineId = 190}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 196, EndLineId = 202}, + {ScriptId = scriptIds.YU04B, StartLineId = 193, EndLineId = 199}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 204, EndLineId = 205}, + {ScriptId = scriptIds.YU04B, StartLineId = 201, EndLineId = 202}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 209}, + {ScriptId = scriptIds.YU04B, LineId = 207}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 212}, + {ScriptId = scriptIds.YU04B, LineId = 210}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 214, EndLineId = 215}, + {ScriptId = scriptIds.YU04B, StartLineId = 212, EndLineId = 213}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 217, EndLineId = 226}, + {ScriptId = scriptIds.YU04B, StartLineId = 215, EndLineId = 224}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 228}, + {ScriptId = scriptIds.YU04B, LineId = 226}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 231}, + {ScriptId = scriptIds.YU04B, LineId = 229}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 234}, + {ScriptId = scriptIds.YU04B, LineId = 232}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 236, EndLineId = 239}, + {ScriptId = scriptIds.YU04B, StartLineId = 234, EndLineId = 237}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 241, EndLineId = 247}, + {ScriptId = scriptIds.YU04B, StartLineId = 239, EndLineId = 245}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 251, EndLineId = 258}, + {ScriptId = scriptIds.YU04B, StartLineId = 248, EndLineId = 255}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 260, EndLineId = 262}, + {ScriptId = scriptIds.YU04B, StartLineId = 257, EndLineId = 259}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 264}, + {ScriptId = scriptIds.YU04B, LineId = 261}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 266, EndLineId = 267}, + {ScriptId = scriptIds.YU04B, StartLineId = 263, EndLineId = 264}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 269, EndLineId = 271}, + {ScriptId = scriptIds.YU04B, StartLineId = 266, EndLineId = 268}, + }, + { + {ScriptId = scriptIds.YU04A, LineId = 273}, + {ScriptId = scriptIds.YU04B, LineId = 270}, + }, + { + {ScriptId = scriptIds.YU04A, StartLineId = 275, EndLineId = 287}, + {ScriptId = scriptIds.YU04B, StartLineId = 272, EndLineId = 284}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 0, EndLineId = 23}, + {ScriptId = scriptIds.YU05B, StartLineId = 0, EndLineId = 23}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 26, EndLineId = 29}, + {ScriptId = scriptIds.YU05B, StartLineId = 26, EndLineId = 29}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 31, EndLineId = 38}, + {ScriptId = scriptIds.YU05B, StartLineId = 31, EndLineId = 38}, + }, + { + {ScriptId = scriptIds.YU05A, LineId = 40}, + {ScriptId = scriptIds.YU05B, LineId = 40}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 43, EndLineId = 45}, + {ScriptId = scriptIds.YU05B, StartLineId = 43, EndLineId = 45}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 48, EndLineId = 60}, + {ScriptId = scriptIds.YU05B, StartLineId = 48, EndLineId = 60}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 62, EndLineId = 74}, + {ScriptId = scriptIds.YU05B, StartLineId = 62, EndLineId = 74}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 76, EndLineId = 77}, + {ScriptId = scriptIds.YU05B, StartLineId = 76, EndLineId = 77}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 79, EndLineId = 85}, + {ScriptId = scriptIds.YU05B, StartLineId = 79, EndLineId = 85}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 87, EndLineId = 91}, + {ScriptId = scriptIds.YU05B, StartLineId = 87, EndLineId = 91}, + }, + { + {ScriptId = scriptIds.YU05A, LineId = 93}, + {ScriptId = scriptIds.YU05B, LineId = 93}, + }, + { + {ScriptId = scriptIds.YU05A, LineId = 95}, + {ScriptId = scriptIds.YU05B, LineId = 95}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 99, EndLineId = 100}, + {ScriptId = scriptIds.YU05B, StartLineId = 99, EndLineId = 100}, + }, + { + {ScriptId = scriptIds.YU05A, LineId = 102}, + {ScriptId = scriptIds.YU05B, LineId = 102}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 105, EndLineId = 106}, + {ScriptId = scriptIds.YU05B, StartLineId = 105, EndLineId = 106}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 108, EndLineId = 121}, + {ScriptId = scriptIds.YU05B, StartLineId = 109, EndLineId = 122}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 124, EndLineId = 127}, + {ScriptId = scriptIds.YU05B, StartLineId = 125, EndLineId = 128}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 129, EndLineId = 132}, + {ScriptId = scriptIds.YU05B, StartLineId = 130, EndLineId = 133}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 134, EndLineId = 148}, + {ScriptId = scriptIds.YU05B, StartLineId = 135, EndLineId = 149}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 150, EndLineId = 152}, + {ScriptId = scriptIds.YU05B, StartLineId = 151, EndLineId = 153}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 154, EndLineId = 157}, + {ScriptId = scriptIds.YU05B, StartLineId = 155, EndLineId = 158}, + }, + { + {ScriptId = scriptIds.YU05A, LineId = 159}, + {ScriptId = scriptIds.YU05B, LineId = 160}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 161, EndLineId = 165}, + {ScriptId = scriptIds.YU05B, StartLineId = 162, EndLineId = 166}, + }, + { + {ScriptId = scriptIds.YU05A, StartLineId = 168, EndLineId = 176}, + {ScriptId = scriptIds.YU05B, StartLineId = 169, EndLineId = 177}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 0, EndLineId = 6}, + {ScriptId = scriptIds.YU06B, StartLineId = 0, EndLineId = 6}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 8, EndLineId = 9}, + {ScriptId = scriptIds.YU06B, StartLineId = 8, EndLineId = 9}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 20, EndLineId = 22}, + {ScriptId = scriptIds.YU06B, StartLineId = 23, EndLineId = 25}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 24, EndLineId = 32}, + {ScriptId = scriptIds.YU06B, StartLineId = 27, EndLineId = 35}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 34}, + {ScriptId = scriptIds.YU06B, LineId = 37}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 36, EndLineId = 54}, + {ScriptId = scriptIds.YU06B, StartLineId = 39, EndLineId = 57}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 56}, + {ScriptId = scriptIds.YU06B, LineId = 59}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 58}, + {ScriptId = scriptIds.YU06B, LineId = 61}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 60}, + {ScriptId = scriptIds.YU06B, LineId = 63}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 62, EndLineId = 66}, + {ScriptId = scriptIds.YU06B, StartLineId = 65, EndLineId = 69}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 68, EndLineId = 84}, + {ScriptId = scriptIds.YU06B, StartLineId = 71, EndLineId = 87}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 86, EndLineId = 87}, + {ScriptId = scriptIds.YU06B, StartLineId = 89, EndLineId = 90}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 89, EndLineId = 90}, + {ScriptId = scriptIds.YU06B, StartLineId = 92, EndLineId = 93}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 92}, + {ScriptId = scriptIds.YU06B, LineId = 95}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 94}, + {ScriptId = scriptIds.YU06B, LineId = 97}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 96}, + {ScriptId = scriptIds.YU06B, LineId = 99}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 98, EndLineId = 102}, + {ScriptId = scriptIds.YU06B, StartLineId = 101, EndLineId = 105}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 108, EndLineId = 111}, + {ScriptId = scriptIds.YU06B, StartLineId = 111, EndLineId = 114}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 115, EndLineId = 118}, + {ScriptId = scriptIds.YU06B, StartLineId = 118, EndLineId = 121}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 120}, + {ScriptId = scriptIds.YU06B, LineId = 123}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 122, EndLineId = 127}, + {ScriptId = scriptIds.YU06B, StartLineId = 125, EndLineId = 130}, + }, + { + {ScriptId = scriptIds.YU06A, StartLineId = 129, EndLineId = 138}, + {ScriptId = scriptIds.YU06B, StartLineId = 132, EndLineId = 141}, + }, + { + {ScriptId = scriptIds.YU06A, LineId = 140}, + {ScriptId = scriptIds.YU06B, LineId = 143}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 0, EndLineId = 1}, + {ScriptId = scriptIds.YU07B, StartLineId = 0, EndLineId = 1}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 3, EndLineId = 5}, + {ScriptId = scriptIds.YU07B, StartLineId = 3, EndLineId = 5}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 7, EndLineId = 9}, + {ScriptId = scriptIds.YU07B, StartLineId = 7, EndLineId = 9}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 13, EndLineId = 17}, + {ScriptId = scriptIds.YU07B, StartLineId = 14, EndLineId = 18}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 19, EndLineId = 24}, + {ScriptId = scriptIds.YU07B, StartLineId = 20, EndLineId = 25}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 29, EndLineId = 33}, + {ScriptId = scriptIds.YU07B, StartLineId = 33, EndLineId = 37}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 35, EndLineId = 38}, + {ScriptId = scriptIds.YU07B, StartLineId = 39, EndLineId = 42}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 41, EndLineId = 99}, + {ScriptId = scriptIds.YU07B, StartLineId = 47, EndLineId = 105}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 102, EndLineId = 105}, + {ScriptId = scriptIds.YU07B, StartLineId = 108, EndLineId = 111}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 106, EndLineId = 108}, + {ScriptId = scriptIds.YU07B, StartLineId = 113, EndLineId = 115}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 111, EndLineId = 112}, + {ScriptId = scriptIds.YU07B, StartLineId = 118, EndLineId = 119}, + }, + { + {ScriptId = scriptIds.YU07A, LineId = 116}, + {ScriptId = scriptIds.YU07B, LineId = 123}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 118, EndLineId = 119}, + {ScriptId = scriptIds.YU07B, StartLineId = 125, EndLineId = 126}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 121, EndLineId = 129}, + {ScriptId = scriptIds.YU07B, StartLineId = 128, EndLineId = 136}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 132, EndLineId = 146}, + {ScriptId = scriptIds.YU07B, StartLineId = 140, EndLineId = 154}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 148, EndLineId = 152}, + {ScriptId = scriptIds.YU07B, StartLineId = 156, EndLineId = 160}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 155, EndLineId = 159}, + {ScriptId = scriptIds.YU07B, StartLineId = 163, EndLineId = 167}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 161, EndLineId = 163}, + {ScriptId = scriptIds.YU07B, StartLineId = 169, EndLineId = 171}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 167, EndLineId = 179}, + {ScriptId = scriptIds.YU07B, StartLineId = 175, EndLineId = 187}, + }, + { + {ScriptId = scriptIds.YU07A, StartLineId = 181, EndLineId = 198}, + {ScriptId = scriptIds.YU07B, StartLineId = 189, EndLineId = 206}, + }, + { + {ScriptId = scriptIds.YU08A, StartLineId = 0, EndLineId = 26}, + {ScriptId = scriptIds.YU08B, StartLineId = 0, EndLineId = 26}, + }, + { + {ScriptId = scriptIds.YU08A, StartLineId = 28, EndLineId = 30}, + {ScriptId = scriptIds.YU08B, StartLineId = 28, EndLineId = 30}, + }, + { + {ScriptId = scriptIds.YU08A, LineId = 32}, + {ScriptId = scriptIds.YU08B, LineId = 32}, + }, + { + {ScriptId = scriptIds.YU08A, StartLineId = 34, EndLineId = 54}, + {ScriptId = scriptIds.YU08B, StartLineId = 33, EndLineId = 53}, + }, + { + {ScriptId = scriptIds.YU08A, StartLineId = 57, EndLineId = 62}, + {ScriptId = scriptIds.YU08B, StartLineId = 56, EndLineId = 61}, + }, + { + {ScriptId = scriptIds.YU08A, LineId = 64}, + {ScriptId = scriptIds.YU08B, LineId = 63}, + }, + { + {ScriptId = scriptIds.YU08A, LineId = 67}, + {ScriptId = scriptIds.YU08B, LineId = 66}, + }, + { + {ScriptId = scriptIds.YU08A, StartLineId = 70, EndLineId = 71}, + {ScriptId = scriptIds.YU08B, StartLineId = 69, EndLineId = 70}, + }, + { + {ScriptId = scriptIds.YU08A, LineId = 73}, + {ScriptId = scriptIds.YU08B, LineId = 72}, + }, + { + {ScriptId = scriptIds.YU08A, LineId = 75}, + {ScriptId = scriptIds.YU08B, LineId = 74}, + }, + { + {ScriptId = scriptIds.YU08A, StartLineId = 77, EndLineId = 83}, + {ScriptId = scriptIds.YU08B, StartLineId = 76, EndLineId = 82}, + }, + { + {ScriptId = scriptIds.YU09A, StartLineId = 0, EndLineId = 9}, + {ScriptId = scriptIds.YU09B, StartLineId = 0, EndLineId = 9}, + }, + { + {ScriptId = scriptIds.YU09A, LineId = 11}, + {ScriptId = scriptIds.YU09B, LineId = 11}, + }, + { + {ScriptId = scriptIds.YU09A, LineId = 13}, + {ScriptId = scriptIds.YU09B, LineId = 13}, + }, + { + {ScriptId = scriptIds.YU09A, StartLineId = 16, EndLineId = 20}, + {ScriptId = scriptIds.YU09B, StartLineId = 16, EndLineId = 20}, + }, + { + {ScriptId = scriptIds.YU09A, LineId = 28}, + {ScriptId = scriptIds.YU09B, LineId = 30}, + }, + { + {ScriptId = scriptIds.YU09A, StartLineId = 30, EndLineId = 35}, + {ScriptId = scriptIds.YU09B, StartLineId = 32, EndLineId = 37}, + }, + { + {ScriptId = scriptIds.YU09A, LineId = 41}, + {ScriptId = scriptIds.YU09B, LineId = 43}, + }, + { + {ScriptId = scriptIds.YU09A, LineId = 43}, + {ScriptId = scriptIds.YU09B, LineId = 45}, + }, + { + {ScriptId = scriptIds.YU09A, StartLineId = 45, EndLineId = 46}, + {ScriptId = scriptIds.YU09B, StartLineId = 47, EndLineId = 48}, + }, + { + {ScriptId = scriptIds.YU09A, StartLineId = 48, EndLineId = 49}, + {ScriptId = scriptIds.YU09B, StartLineId = 50, EndLineId = 51}, + }, + { + {ScriptId = scriptIds.YU09A, StartLineId = 51, EndLineId = 52}, + {ScriptId = scriptIds.YU09B, StartLineId = 53, EndLineId = 54}, + }, + { + {ScriptId = scriptIds.YU09A, StartLineId = 54, EndLineId = 58}, + {ScriptId = scriptIds.YU09B, StartLineId = 56, EndLineId = 60}, + }, + { + {ScriptId = scriptIds.YU09A, LineId = 61}, + {ScriptId = scriptIds.YU09B, LineId = 66}, + }, +}; diff --git a/profiles/chlcc/savedata.lua b/profiles/chlcc/savedata.lua index 1bfddc036..70f91a995 100644 --- a/profiles/chlcc/savedata.lua +++ b/profiles/chlcc/savedata.lua @@ -1,7 +1,7 @@ root.SaveData = { Type = SaveDataType.CHLCC, SaveFilePath = root.BasePaths.RootSavesDir .. "/chlcc/jpn/SYSTEM.DAT", - ThumbnailFilePath = "games/chlcc/savedata/THUMNAIL.DAT", + ThumbnailFilePath = root.BasePaths.RootSavesDir .. "/chlcc/jpn/THUMNAIL.DAT", ScriptMessageData = { -- Pairs of line count and offset into read flag array {0x008f, 0x0000}, {0x00a5, 0x008f}, {0x01fe, 0x0134}, {0x0000, 0x0332}, {0x00d2, 0x0332}, {0x01b4, 0x0404}, @@ -154,5 +154,7 @@ root.SaveData = { {{416, 415}}, {{418, 417}}, {{419}} - } -}; \ No newline at end of file + }, +}; + +include(root.BasePaths.RootProfilesDir .. "/chlcc/equivalentlines.lua"); diff --git a/src/data/savesystem.cpp b/src/data/savesystem.cpp index 4909fdd7d..5b619f768 100644 --- a/src/data/savesystem.cpp +++ b/src/data/savesystem.cpp @@ -203,17 +203,55 @@ void SetTipStatus(size_t tipId, bool isLocked, bool isUnread, bool isNew) { "{:s}: save system not implemented\n", __func__); } -void SetLineRead(int scriptId, int lineId) { - if (Implementation) return Implementation->SetLineRead(scriptId, lineId); - ImpLog(LogLevel::Warning, LogChannel::VMStub, - "{:s}: save system not implemented\n", __func__); +std::optional GetLineBitOffset(const size_t scriptId, + const size_t lineId) { + if (ScriptMessageData.size() < scriptId) { + ImpLog(LogLevel::Error, LogChannel::General, "Script ID {:d} out of bounds", + scriptId); + return std::nullopt; + } + + const bool isAdded = lineId >= ScriptMessageData[scriptId].LineCount; + if (isAdded && !AddedLinesData.has_value()) { + ImpLog(LogLevel::Warning, LogChannel::General, + "Encountered an added line without AddedLineData being supplied in " + "the profile."); + return std::nullopt; + } + + return isAdded ? AddedLinesData->BitFieldOffset + + AddedLinesData->AddedLinesPerScript * scriptId + + (lineId - ScriptMessageData[scriptId].LineCount) + : ScriptMessageData[scriptId].SaveDataOffset + lineId; } -bool IsLineRead(int scriptId, int lineId) { - if (Implementation) return Implementation->IsLineRead(scriptId, lineId); - ImpLog(LogLevel::Warning, LogChannel::VMStub, - "{:s}: save system not implemented, returing false\n", __func__); - return false; +void SetLineRead(const size_t scriptId, const size_t lineId) { + if (Implementation == nullptr) { + ImpLog(LogLevel::Warning, LogChannel::VMStub, + "{:s}: save system not implemented\n", __func__); + return; + } + + const std::vector> equivalentLines = + GetEquivalentLines(scriptId, lineId); + for (const auto& [curScriptId, curLineId] : equivalentLines) { + Implementation->SetLineRead(curScriptId, curLineId); + } +} + +bool IsLineRead(const size_t scriptId, const size_t lineId) { + if (Implementation == nullptr) { + ImpLog(LogLevel::Warning, LogChannel::VMStub, + "{:s}: save system not implemented, returning false\n", __func__); + return false; + } + + const std::vector> equivalentLines = + GetEquivalentLines(scriptId, lineId); + return std::ranges::any_of( + equivalentLines, [](std::pair line) { + return Implementation->IsLineRead(line.first, line.second); + }); } void GetReadMessagesCount(int* totalMessageCount, int* readMessageCount) { diff --git a/src/data/savesystem.h b/src/data/savesystem.h index 6a89c4618..8506b8943 100644 --- a/src/data/savesystem.h +++ b/src/data/savesystem.h @@ -125,8 +125,8 @@ class SaveSystemBase { virtual uint32_t GetTipStatus(size_t tipId) const = 0; virtual void SetTipStatus(size_t tipId, bool isLocked, bool isUnread, bool isNew) = 0; - virtual void SetLineRead(int scriptId, int lineId) = 0; - virtual bool IsLineRead(int scriptId, int MessageId) const = 0; + virtual void SetLineRead(size_t scriptId, size_t lineId) = 0; + virtual bool IsLineRead(size_t scriptId, size_t lineId) const = 0; virtual void GetReadMessagesCount(int* totalMessageCount, int* readMessageCount) const = 0; virtual void GetViewedEVsCount(int* totalEVCount, @@ -201,8 +201,9 @@ uint8_t GetSaveStatus(SaveType type, int id); int GetSaveTitle(SaveType type, int id); uint32_t GetTipStatus(size_t tipId); void SetTipStatus(size_t tipId, bool isLocked, bool isUnread, bool isNew); -void SetLineRead(int scriptId, int lineId); -bool IsLineRead(int scriptId, int lineId); +std::optional GetLineBitOffset(size_t scriptId, size_t lineId); +void SetLineRead(size_t scriptId, size_t lineId); +bool IsLineRead(size_t scriptId, size_t lineId); void GetReadMessagesCount(int* totalMessageCount, int* readMessageCount); void GetViewedEVsCount(int* totalEVCount, int* viewedEVCount); void GetEVStatus(int evId, int* totalVariations, int* viewedVariations); diff --git a/src/games/cclcc/savesystem.cpp b/src/games/cclcc/savesystem.cpp index 504a1f7d5..ffc26a848 100644 --- a/src/games/cclcc/savesystem.cpp +++ b/src/games/cclcc/savesystem.cpp @@ -857,25 +857,23 @@ void SaveSystem::SetTipStatus(size_t tipId, bool isLocked, bool isUnread, } } -void SaveSystem::SetLineRead(int scriptId, int lineId) { - if (scriptId >= 255) return; - - uint32_t offset = ScriptMessageData[scriptId].SaveDataOffset + lineId; - if (offset == 0xFFFFFFFF) return; +void SaveSystem::SetLineRead(const size_t scriptId, const size_t lineId) { + const std::optional offset = GetLineBitOffset(scriptId, lineId); + if (!offset.has_value()) return; // TODO: update some ScrWorks (2003, 2005 & 2006) - MessageFlags[offset >> 3] |= Flbit[offset & 0b111]; + MessageFlags[*offset >> 3] |= Flbit[*offset & 0b111]; } -bool SaveSystem::IsLineRead(int scriptId, int lineId) const { - if (scriptId >= 255) return false; +bool SaveSystem::IsLineRead(const size_t scriptId, const size_t lineId) const { + const std::optional offset = GetLineBitOffset(scriptId, lineId); + if (!offset.has_value()) return false; - uint32_t offset = ScriptMessageData[scriptId].SaveDataOffset + lineId; - uint8_t flbit = Flbit[offset & 0b111]; - uint8_t viewed = MessageFlags[offset >> 3]; + const uint8_t flbit = Flbit[*offset & 0b111]; + const uint8_t viewed = MessageFlags[*offset >> 3]; - return (bool)(flbit & viewed); + return static_cast(flbit & viewed); } void SaveSystem::GetReadMessagesCount(int* totalMessageCount, @@ -883,12 +881,12 @@ void SaveSystem::GetReadMessagesCount(int* totalMessageCount, *totalMessageCount = 0; *readMessageCount = 0; - for (int scriptId = 0; scriptId < StoryScriptCount; scriptId++) { + for (size_t scriptId = 0; scriptId < ScriptMessageData.size(); scriptId++) { ScriptMessageDataPair script = ScriptMessageData[scriptId]; *totalMessageCount += script.LineCount; for (size_t lineId = 0; lineId < script.LineCount; lineId++) { - *readMessageCount += IsLineRead(scriptId, (int)lineId); + *readMessageCount += IsLineRead(scriptId, lineId); } } } diff --git a/src/games/cclcc/savesystem.h b/src/games/cclcc/savesystem.h index 76c5aac2b..3bfeb6eec 100644 --- a/src/games/cclcc/savesystem.h +++ b/src/games/cclcc/savesystem.h @@ -67,8 +67,8 @@ class SaveSystem : public SaveSystemBase { void SetTipStatus(size_t tipId, bool isLocked, bool isUnread, bool isNew) override; - void SetLineRead(int scriptId, int lineId) override; - bool IsLineRead(int scriptId, int lineId) const override; + void SetLineRead(size_t scriptId, size_t lineId) override; + bool IsLineRead(size_t scriptId, size_t lineId) const override; void GetReadMessagesCount(int* totalMessageCount, int* readMessageCount) const override; diff --git a/src/games/chlcc/savesystem.cpp b/src/games/chlcc/savesystem.cpp index a7ffce915..926273320 100644 --- a/src/games/chlcc/savesystem.cpp +++ b/src/games/chlcc/savesystem.cpp @@ -1064,25 +1064,23 @@ void SaveSystem::SetTipStatus(size_t tipId, bool isLocked, bool isUnread, } } -void SaveSystem::SetLineRead(int scriptId, int lineId) { - if (std::ssize(ScriptMessageData) <= scriptId) return; - - uint32_t offset = ScriptMessageData[scriptId].SaveDataOffset + lineId; - if (offset == 0xFFFFFFFF) return; +void SaveSystem::SetLineRead(const size_t scriptId, const size_t lineId) { + const std::optional offset = GetLineBitOffset(scriptId, lineId); + if (!offset.has_value()) return; // TODO: update some ScrWorks (2003, 2005 & 2006) - MessageFlags[offset >> 3] |= Flbit[offset & 0b111]; + MessageFlags[*offset >> 3] |= Flbit[*offset & 0b111]; } -bool SaveSystem::IsLineRead(int scriptId, int lineId) const { - if (std::ssize(ScriptMessageData) <= scriptId) return false; +bool SaveSystem::IsLineRead(const size_t scriptId, const size_t lineId) const { + const std::optional offset = GetLineBitOffset(scriptId, lineId); + if (!offset.has_value()) return false; - uint32_t offset = ScriptMessageData[scriptId].SaveDataOffset + lineId; - uint8_t flbit = Flbit[offset & 0b111]; - uint8_t viewed = MessageFlags[offset >> 3]; + const uint8_t flbit = Flbit[*offset & 0b111]; + const uint8_t viewed = MessageFlags[*offset >> 3]; - return (bool)(flbit & viewed); + return static_cast(flbit & viewed); } void SaveSystem::GetReadMessagesCount(int* totalMessageCount, @@ -1090,12 +1088,12 @@ void SaveSystem::GetReadMessagesCount(int* totalMessageCount, *totalMessageCount = 0; *readMessageCount = 0; - for (int scriptId = 0; scriptId < StoryScriptCount; scriptId++) { + for (size_t scriptId = 0; scriptId < ScriptMessageData.size(); scriptId++) { ScriptMessageDataPair script = ScriptMessageData[scriptId]; *totalMessageCount += script.LineCount; for (size_t lineId = 0; lineId < script.LineCount; lineId++) { - *readMessageCount += IsLineRead(scriptId, (int)lineId); + *readMessageCount += IsLineRead(scriptId, lineId); } } } diff --git a/src/games/chlcc/savesystem.h b/src/games/chlcc/savesystem.h index 36f246847..49f832f2c 100644 --- a/src/games/chlcc/savesystem.h +++ b/src/games/chlcc/savesystem.h @@ -64,8 +64,8 @@ class SaveSystem : public SaveSystemBase { void SetTipStatus(size_t tipId, bool isLocked, bool isUnread, bool isNew) override; - void SetLineRead(int scriptId, int lineId) override; - bool IsLineRead(int scriptId, int lineId) const override; + void SetLineRead(size_t scriptId, size_t lineId) override; + bool IsLineRead(size_t scriptId, size_t lineId) const override; void GetReadMessagesCount(int* totalMessageCount, int* readMessageCount) const override; diff --git a/src/games/mo6tw/savesystem.cpp b/src/games/mo6tw/savesystem.cpp index 8aaa02201..ae6bf95b6 100644 --- a/src/games/mo6tw/savesystem.cpp +++ b/src/games/mo6tw/savesystem.cpp @@ -545,27 +545,23 @@ void SaveSystem::SetTipStatus(size_t tipId, bool isLocked, bool isUnread, } } -void SaveSystem::SetLineRead(int scriptId, int lineId) { - if (scriptId >= StoryScriptCount.value()) return; - - uint32_t offset = - ScriptMessageData[StoryScriptIDs[scriptId]].SaveDataOffset + lineId; - if (offset == 0xFFFFFFFF) return; +void SaveSystem::SetLineRead(const size_t scriptId, const size_t lineId) { + const std::optional offset = GetLineBitOffset(scriptId, lineId); + if (!offset.has_value()) return; // TODO: update some ScrWorks (2003, 2005 & 2006) - MessageFlags[offset >> 3] |= Flbit[offset & 0b111]; + MessageFlags[*offset >> 3] |= Flbit[*offset & 0b111]; } -bool SaveSystem::IsLineRead(int scriptId, int lineId) const { - if (scriptId >= StoryScriptCount.value()) return false; +bool SaveSystem::IsLineRead(const size_t scriptId, const size_t lineId) const { + const std::optional offset = GetLineBitOffset(scriptId, lineId); + if (!offset.has_value()) return false; - uint32_t offset = - ScriptMessageData[StoryScriptIDs[scriptId]].SaveDataOffset + lineId; - uint8_t flbit = Flbit[offset & 0b111]; - uint8_t viewed = MessageFlags[offset >> 3]; + const uint8_t flbit = Flbit[*offset & 0b111]; + const uint8_t viewed = MessageFlags[*offset >> 3]; - return (bool)(flbit & viewed); + return static_cast(flbit & viewed); } void SaveSystem::GetReadMessagesCount(int* totalMessageCount, @@ -573,12 +569,12 @@ void SaveSystem::GetReadMessagesCount(int* totalMessageCount, *totalMessageCount = 0; *readMessageCount = 0; - for (int scriptId = 0; scriptId < StoryScriptCount; scriptId++) { + for (size_t scriptId = 0; scriptId < StoryScriptIDs.size(); scriptId++) { ScriptMessageDataPair script = ScriptMessageData[StoryScriptIDs[scriptId]]; *totalMessageCount += script.LineCount; for (size_t lineId = 0; lineId < script.LineCount; lineId++) { - *readMessageCount += IsLineRead(scriptId, (int)lineId); + *readMessageCount += IsLineRead(scriptId, lineId); } } } diff --git a/src/games/mo6tw/savesystem.h b/src/games/mo6tw/savesystem.h index 8553b3a8c..dc43bfca0 100644 --- a/src/games/mo6tw/savesystem.h +++ b/src/games/mo6tw/savesystem.h @@ -38,8 +38,8 @@ class SaveSystem : public SaveSystemBase { uint32_t GetTipStatus(size_t tipId) const override; void SetTipStatus(size_t tipId, bool isLocked, bool isUnread, bool isNew) override; - void SetLineRead(int scriptId, int lineId) override; - bool IsLineRead(int scriptId, int lineId) const override; + void SetLineRead(size_t scriptId, size_t lineId) override; + bool IsLineRead(size_t scriptId, size_t lineId) const override; void GetReadMessagesCount(int* totalMessageCount, int* readMessageCount) const override; void GetViewedEVsCount(int* totalEVCount, int* viewedEVCount) const override; diff --git a/src/profile/data/savesystem.cpp b/src/profile/data/savesystem.cpp index e8d89e5f9..37c443223 100644 --- a/src/profile/data/savesystem.cpp +++ b/src/profile/data/savesystem.cpp @@ -9,10 +9,100 @@ namespace Impacto { namespace Profile { + +template <> +struct TryGetImpl { + static std::optional Call() { + if (!lua_istable(LuaState, -1)) return std::nullopt; + + const std::optional bitFieldOffset = + TryGetMember("BitFieldOffset"); + if (!bitFieldOffset.has_value()) { + ImpLog(LogLevel::Fatal, LogChannel::Profile, "Missing BitFieldOffset"); + return std::nullopt; + } + + const std::optional addedLinesPerScript = + TryGetMember("AddedLinesPerScript"); + if (!addedLinesPerScript.has_value()) { + ImpLog(LogLevel::Fatal, LogChannel::Profile, + "Missing AddedLinesPerScript"); + return std::nullopt; + } + + return SaveSystem::AddedLinesDataStruct{ + .BitFieldOffset = *bitFieldOffset, + .AddedLinesPerScript = *addedLinesPerScript, + }; + } +}; + namespace SaveSystem { +struct LineRange { + size_t ScriptId; + size_t StartLineId; + size_t EndLineId; + + size_t EquivalentLineRangesIdx = 0; + + bool Intersects(const LineRange& other) const { + return ScriptId == other.ScriptId && + !(other.EndLineId < StartLineId || EndLineId < other.StartLineId); + } +}; +} // namespace SaveSystem + +template <> +struct TryGetImpl { + static std::optional Call() { + if (!lua_istable(LuaState, -1)) return std::nullopt; + + const std::optional scriptId = TryGetMember("ScriptId"); + if (!scriptId.has_value()) { + ImpLog(LogLevel::Fatal, LogChannel::Profile, + "Missing ScriptId in equivalent line range"); + return std::nullopt; + } + std::optional startLineId = TryGetMember("StartLineId"); + std::optional endLineId; + if (!startLineId.has_value()) { + startLineId = TryGetMember("LineId"); + + if (!startLineId.has_value()) { + ImpLog(LogLevel::Fatal, LogChannel::Profile, + "Missing LineId in equivalent line range"); + return std::nullopt; + } + + endLineId = startLineId; + } else { + endLineId = TryGetMember("EndLineId"); + + if (!endLineId.has_value()) { + ImpLog(LogLevel::Fatal, LogChannel::Profile, + "Missing EndLineId in equivalent line range"); + return std::nullopt; + } + } + + return SaveSystem::LineRange{ + .ScriptId = *scriptId, + .StartLineId = *startLineId, + .EndLineId = *endLineId, + }; + } +}; + +namespace SaveSystem { using namespace Impacto::SaveSystem; +// EquivalentRanges holds all equivalent classes between ranges. +// ScriptRanges allows one to fetch all equivalent classes pertaining to an +// individual script ID, for faster lookups. +static std::vector> EquivalentLineRanges; +static std::map> ScriptLineRanges; + void Configure() { EnsurePushMemberOfType("SaveData", LUA_TTABLE); @@ -39,20 +129,7 @@ void Configure() { SaveFilePath = EnsureGetMember("SaveFilePath"); - if (TryPushMember("StoryScriptIDs")) { - AssertIs(LUA_TTABLE); - - StoryScriptCount = (int)lua_rawlen(LuaState, -1); - StoryScriptIDs.resize(*StoryScriptCount); - PushInitialIndex(); - while (PushNextTableElement() != 0) { - int i = EnsureGetKey() - 1; - StoryScriptIDs[i] = EnsureGetArrayElement(); - Pop(); - } - - Pop(); - } + TryGetMember>("StoryScriptIDs", StoryScriptIDs); if (TryPushMember("ScriptMessageData")) { AssertIs(LUA_TTABLE); @@ -136,9 +213,95 @@ void Configure() { Pop(); } + AddedLinesData = TryGetMember("AddedLinesData"); + + if (TryPushMember("EquivalentLines")) { + ForEachProfileArray([](const uint32_t index) { + std::vector& equivalentRangeList = + EquivalentLineRanges.emplace_back( + EnsureGet>()); + if (equivalentRangeList.size() < 2) { + ImpLog(LogLevel::Warning, LogChannel::Profile, + "Equivalent range list of size < 2 loaded from the profile"); + EquivalentLineRanges.pop_back(); + return; + } + + const size_t rangeLength = equivalentRangeList.front().EndLineId - + equivalentRangeList.front().StartLineId; + for (auto curIt = equivalentRangeList.begin(); + curIt != equivalentRangeList.end(); curIt++) { + if (curIt->EndLineId < curIt->StartLineId) { + throw std::runtime_error(fmt::format( + "EndLineId < StartLineId for equivalent line range [{:d}, " + "{:d}] of script {:d}", + curIt->StartLineId, curIt->EndLineId, curIt->ScriptId)); + } + + if (curIt->EndLineId - curIt->StartLineId != rangeLength) { + throw std::runtime_error(fmt::format( + "Expected range length {:d} for equivalent line range [{:d}, " + "{:d}] of script {:d}", + rangeLength, curIt->StartLineId, curIt->EndLineId, + curIt->ScriptId)); + } + + // Ranges may not intersect because a single binary search pass is used + // to identify the equivalent lines + std::vector& scriptVector = + ScriptLineRanges.try_emplace(curIt->ScriptId).first->second; + if (const auto intersected = + std::ranges::find_if(scriptVector, + [curIt](const auto& other) { + return curIt->Intersects(other); + }); + intersected != scriptVector.end()) { + throw std::runtime_error(fmt::format( + "Line range [{:d}, {:d}] of script {:d} intersects with line " + "range [{:d}, {:d}]", + curIt->StartLineId, curIt->EndLineId, curIt->ScriptId, + intersected->StartLineId, intersected->EndLineId)); + } + + curIt->EquivalentLineRangesIdx = EquivalentLineRanges.size() - 1; + scriptVector.emplace_back(*curIt); + } + }); + + // Sort the ranges in ScriptLineRanges to be able to binary search + for (auto& [scriptId, lineRanges] : ScriptLineRanges) { + std::ranges::sort(lineRanges, std::less(), &LineRange::EndLineId); + } + + Pop(); + } + Pop(); } +std::vector> GetEquivalentLines(const size_t scriptId, + const size_t lineId) { + const auto scriptLineRangesIt = ScriptLineRanges.find(scriptId); + if (scriptLineRangesIt == ScriptLineRanges.end()) return {{scriptId, lineId}}; + + const std::vector& scriptLineRanges = scriptLineRangesIt->second; + const auto lineRange = std::ranges::lower_bound( + scriptLineRanges, lineId, std::less(), &LineRange::EndLineId); + if (lineRange == scriptLineRanges.end() || lineId < lineRange->StartLineId) { + return {{scriptId, lineId}}; + } + + const size_t offset = lineId - lineRange->StartLineId; + std::vector> equivalentLines; + std::ranges::transform( + EquivalentLineRanges[lineRange->EquivalentLineRangesIdx], + std::back_inserter(equivalentLines), [offset](const auto& range) { + return std::pair{range.ScriptId, range.StartLineId + offset}; + }); + + return equivalentLines; +} + } // namespace SaveSystem } // namespace Profile } // namespace Impacto \ No newline at end of file diff --git a/src/profile/data/savesystem.h b/src/profile/data/savesystem.h index adaaa3a87..e67b1ddc0 100644 --- a/src/profile/data/savesystem.h +++ b/src/profile/data/savesystem.h @@ -18,12 +18,20 @@ inline Impacto::SaveSystem::SaveDataType Type = inline std::string SaveFilePath; inline std::optional ThumbnailFilePath; inline std::vector StoryScriptIDs; -inline std::optional StoryScriptCount; inline std::vector ScriptMessageData; inline uint16_t AlbumEvData[MaxAlbumEntries][MaxAlbumSubEntries]; inline uint16_t AlbumData[MaxAlbumEntries][MaxAlbumSubEntries][MaxCGSprites]; +struct AddedLinesDataStruct { + size_t BitFieldOffset; + size_t AddedLinesPerScript; +}; +inline std::optional AddedLinesData; + +std::vector> GetEquivalentLines(size_t scriptId, + size_t lineId); + void Configure(); } // namespace SaveSystem diff --git a/src/vm/inst_dialogue.cpp b/src/vm/inst_dialogue.cpp index e20c2941b..5d9848772 100644 --- a/src/vm/inst_dialogue.cpp +++ b/src/vm/inst_dialogue.cpp @@ -33,13 +33,15 @@ VmInstruction(InstMesViewFlag) { case 0: { // Set PopExpression(scriptId); PopExpression(lineId); - SaveSystem::SetLineRead(scriptId, lineId); + SaveSystem::SetLineRead(static_cast(scriptId), + static_cast(lineId)); } break; case 1: { // Check PopExpression(scrWorkEntry); PopExpression(scriptId); PopExpression(lineId); - ScrWork[scrWorkEntry] = SaveSystem::IsLineRead(scriptId, lineId); + ScrWork[scrWorkEntry] = SaveSystem::IsLineRead( + static_cast(scriptId), static_cast(lineId)); } break; } } @@ -137,8 +139,9 @@ static bool InstMesSyncMain(int pageId, SyncType type) { currentPage.PushBacklogEntry(); } - SaveSystem::SetLineRead(ScrWork[currentPage.Id * 2 + SW_SCRIPTID], - ScrWork[currentPage.Id * 2 + SW_LINEID]); + SaveSystem::SetLineRead( + static_cast(ScrWork[currentPage.Id * 2 + SW_SCRIPTID]), + static_cast(ScrWork[currentPage.Id * 2 + SW_LINEID])); return false; } @@ -154,8 +157,9 @@ static bool InstMesSyncMain(int pageId, SyncType type) { case Hidden: currentPage.PushBacklogEntry(); SetFlag(SF_MESCLEAR0 + currentPage.Id, true); - SaveSystem::SetLineRead(ScrWork[currentPage.Id * 2 + SW_SCRIPTID], - ScrWork[currentPage.Id * 2 + SW_LINEID]); + SaveSystem::SetLineRead( + static_cast(ScrWork[currentPage.Id * 2 + SW_SCRIPTID]), + static_cast(ScrWork[currentPage.Id * 2 + SW_LINEID])); return false; default: break; @@ -482,8 +486,9 @@ VmInstruction(InstMesCls) { SetFlag(SF_SHOWWAITICON + pageId, false); SetFlag(SF_MESCLEAR0 + pageId, true); - SaveSystem::SetLineRead(ScrWork[SW_SCRIPTID + pageId * 2], - ScrWork[SW_LINEID + pageId * 2]); + SaveSystem::SetLineRead( + static_cast(ScrWork[SW_SCRIPTID + pageId * 2]), + static_cast(ScrWork[SW_LINEID + pageId * 2])); if (!GetFlag(SF_REVADDDISABLE)) { page.PushBacklogEntry(); @@ -614,8 +619,9 @@ VmInstruction(InstMesMain) { SetFlag(SF_MESCLEAR0 + currentPage.Id, true); - SaveSystem::SetLineRead(ScrWork[currentPage.Id * 2 + SW_SCRIPTID], - ScrWork[currentPage.Id * 2 + SW_LINEID]); + SaveSystem::SetLineRead( + static_cast(ScrWork[currentPage.Id * 2 + SW_SCRIPTID]), + static_cast(ScrWork[currentPage.Id * 2 + SW_LINEID])); return; } @@ -668,8 +674,9 @@ VmInstruction(InstMesMain) { SetFlag(SF_MESCLEAR0 + currentPage.Id, true); } - SaveSystem::SetLineRead(ScrWork[currentPage.Id * 2 + SW_SCRIPTID], - ScrWork[currentPage.Id * 2 + SW_LINEID]); + SaveSystem::SetLineRead( + static_cast(ScrWork[currentPage.Id * 2 + SW_SCRIPTID]), + static_cast(ScrWork[currentPage.Id * 2 + SW_LINEID])); currentPage.PushBacklogEntry();