@@ -686,6 +686,40 @@ void MOD_ChangeLevel(const char* szLevelName, ACP_tdxBool bSaveGame) {
686686 GAM_fn_vAskToChangeLevel (szLevelName , bSaveGame );
687687}
688688
689+ /** Counts a series of lum collectables. */
690+ int CountCollectibleLums (int * values , int * superValues , int superLums , int count ) {
691+ HIE_tdstSuperObject * pGlobal = HIE_fn_p_stFindObjectByName ("global" );
692+ int total = 0 ;
693+ if (pGlobal ) {
694+ for (int i = 0 ; i < (count - superLums * 5 ); i ++ ) {
695+ if (AI_fn_bGetBooleanInArray (pGlobal , 42 , values [i ])) {
696+ total ++ ;
697+ }
698+ }
699+ for (int i = 0 ; i < superLums ; i ++ ) {
700+ if (AI_fn_bGetBooleanInArray (pGlobal , 42 , superValues [i ])) {
701+ total += 5 ;
702+ }
703+ }
704+ }
705+ return total ;
706+ }
707+
708+ /** Counts a series of cage collectables. */
709+ int CountCollectibleCages (int * values , int count ) {
710+ HIE_tdstSuperObject * pGlobal = HIE_fn_p_stFindObjectByName ("global" );
711+ int total = 0 ;
712+ if (pGlobal ) {
713+ for (int i = 0 ; i < count ; i ++ ) {
714+ if (AI_fn_bGetBooleanInArray (pGlobal , 42 , values [i ])) {
715+ total ++ ;
716+ }
717+ }
718+
719+ }
720+ return total ;
721+ }
722+
689723/** Sets the value of a DSG variable. */
690724BOOL AI_fn_bSetDsgVar (HIE_tdstSuperObject * p_stSuperObj , unsigned char ucDsgVarId , void * * p_pValue_In ) {
691725 if (!HIE_M_bSuperObjectIsActor (p_stSuperObj ))
@@ -1197,6 +1231,87 @@ void MOD_ToggleDeathLink() {
11971231 }
11981232}
11991233
1234+ /** Crawls through the level chains and appends to the output list. */
1235+ void CrawlLevelInfo (int chainId , int currentLevel , LevelInfo * * info , int * length , int depth ) {
1236+ // Determine the level to place here
1237+ int chainLength = MOD_LevelChainsLengths [chainId ];
1238+ if (currentLevel < 0 || currentLevel >= chainLength ) return ;
1239+
1240+ // Extend the length and array with this new level
1241+ * length = * length + 1 ;
1242+ LevelInfo * tmp = realloc (* info , * length * sizeof (LevelInfo ));
1243+ if (!tmp ) return ;
1244+ * info = tmp ;
1245+
1246+ // Prepare the level data for this level
1247+ LevelInfo * level = & (* info )[* length - 1 ];
1248+ memset (level , 0 , sizeof (LevelInfo ));
1249+
1250+ level -> depth = depth ;
1251+
1252+ // Determine the level in this spot
1253+ int levelId = MOD_LevelChainContents [chainId ][currentLevel ];
1254+ char * levelName = MOD_LevelIds [levelId ];
1255+
1256+ // Determine the lums/cages of this level
1257+ if (compareStringCaseInsensitive (levelName , "Learn_30" ) == 0 ) {
1258+ strcpy (level -> name , "Fairy Glade 1" );
1259+ level -> lumsMax = 9 ;
1260+ level -> cagesMax = 2 ;
1261+ level -> lums = CountCollectibleLums ((int []) { 6 , 7 , 8 , 12 }, (int []) { 1 }, 1 , level -> lumsMax );
1262+ level -> cages = CountCollectibleCages ((int []) { 842 , 843 }, level -> cagesMax );
1263+ } else if (compareStringCaseInsensitive (levelName , "learn_31" ) == 0 ) {
1264+ strcpy (level -> name , "Fairy Glade 2" );
1265+ level -> lumsMax = 1 ;
1266+ level -> cagesMax = 0 ;
1267+ level -> lums = CountCollectibleLums ((int []) { 11 }, (int []) { 0 }, 0 , level -> lumsMax );
1268+ level -> cages = CountCollectibleCages ((int []) { 0 }, level -> cagesMax );
1269+ } else if (compareStringCaseInsensitive (levelName , "Learn_32" ) == 0 ) {
1270+ strcpy (level -> name , "Fairy Glade - Revisit" );
1271+ level -> lumsMax = 2 ;
1272+ level -> cagesMax = 1 ;
1273+ level -> lums = CountCollectibleLums ((int []) { 9 , 10 }, (int []) { 0 }, 0 , level -> lumsMax );
1274+ level -> cages = CountCollectibleCages ((int []) { 844 }, level -> cagesMax );
1275+ } else if (compareStringCaseInsensitive (levelName , "bast_20" ) == 0 ) {
1276+ strcpy (level -> name , "Fairy Glade 3" );
1277+ level -> lumsMax = 17 ;
1278+ level -> cagesMax = 2 ;
1279+ level -> lums = CountCollectibleLums ((int []) { 27 , 26 , 25 , 29 , 28 , 23 , 24 }, (int []) { 13 , 18 }, 2 , level -> lumsMax );
1280+ level -> cages = CountCollectibleCages ((int []) { 845 , 846 }, level -> cagesMax );
1281+ } else if (compareStringCaseInsensitive (levelName , "bast_22" ) == 0 ) {
1282+ strcpy (level -> name , "Fairy Glade 4" );
1283+ level -> lumsMax = 4 ;
1284+ level -> cagesMax = 0 ;
1285+ level -> lums = CountCollectibleLums ((int []) { 31 , 30 , 32 , 33 }, (int []) { 0 }, 0 , level -> lumsMax );
1286+ level -> cages = CountCollectibleCages ((int []) { 0 }, level -> cagesMax );
1287+ } else if (compareStringCaseInsensitive (levelName , "learn_60" ) == 0 ) {
1288+ strcpy (level -> name , "Fairy Glade 5" );
1289+ level -> lumsMax = 17 ;
1290+ level -> cagesMax = 2 ;
1291+ level -> lums = CountCollectibleLums ((int []) { 34 , 35 , 36 , 37 , 48 , 49 , 50 , 38 , 42 , 45 , 44 , 43 , 39 , 46 , 47 , 41 , 40 }, (int []) { 0 }, 0 , level -> lumsMax );
1292+ level -> cages = CountCollectibleCages ((int []) { 847 , 848 }, level -> cagesMax );
1293+ } else if (compareStringCaseInsensitive (levelName , "cask_10" ) == 0 ) {
1294+ strcpy (level -> name , "Echoing Caves 1" );
1295+ level -> lumsMax = 15 ;
1296+ level -> cagesMax = 2 ;
1297+ level -> lums = CountCollectibleLums ((int []) { 421 , 422 , 423 , 430 , 431 , 432 , 428 , 429 , 424 , 425 , 426 , 427 , 433 , 434 , 435 }, (int []) {0 }, 0 , level -> lumsMax );
1298+ level -> cages = CountCollectibleCages ((int []) {887 , 888 }, level -> cagesMax );
1299+ } else {
1300+ strcpy (level -> name , levelName );
1301+ level -> lumsMax = 0 ;
1302+ level -> cagesMax = 0 ;
1303+ }
1304+
1305+ // Crawl for the next level, if this is Sanc of Stone and Fire or Echoing Caves we include the revisit area!
1306+ // The other three have their own portals which show their contents.
1307+ if (compareStringCaseInsensitive (levelName , "cask_10" ) == 0 ) {
1308+ CrawlLevelInfo (CHAIN_FAIRY_REVISIT , 0 , info , length , depth + 1 );
1309+ } else if (compareStringCaseInsensitive (levelName , "plum_00" ) == 0 ) {
1310+ CrawlLevelInfo (CHAIN_SIDE_TEMPLE , 0 , info , length , depth + 1 );
1311+ }
1312+ CrawlLevelInfo (chainId , currentLevel + 1 , info , length , depth );
1313+ }
1314+
12001315/** Draws text to the screen with the recent screen text and progression statistics. */
12011316void CALLBACK MOD_vTextCallback (SPTXT_tdstTextInfo * pInfo ) {
12021317 // Determine the current time
@@ -1225,22 +1340,170 @@ void CALLBACK MOD_vTextCallback(SPTXT_tdstTextInfo* pInfo) {
12251340 SPTXT_vPrint (screen );
12261341 }
12271342
1228- // Draw the current Archipelago progression to the bottom in the hall of doors or on the pause screen
1229- const char * szLevelName = GAM_fn_p_szGetLevelName ();
1230- if (MOD_Connected && (compareStringCaseInsensitive (szLevelName , "mapmonde" ) == 0 || * AI_g_bInGameMenu )) {
1231- pInfo -> xSize = 6 ;
1232- pInfo -> bRightAlign = TRUE;
1233- long lineHeight = SPTXT_fn_lGetCharHeight (pInfo -> xSize );
1234-
1235- pInfo -> X = 995 ;
1236- pInfo -> Y = 990 - 4 * lineHeight ;
1237- SPTXT_vPrintFmtLine ("/o200:Archipelago Received" );
1238- pInfo -> Y = 990 - 3 * lineHeight ;
1239- SPTXT_vPrintFmtLine ("/o400:Lums /o0:%d of 1000/o400:, Cages /o0:%d of 80" , MOD_Lums , MOD_Cages );
1240- pInfo -> Y = 990 - 2 * lineHeight ;
1241- SPTXT_vPrintFmtLine ("/o400:Masks /o0:%d of 4/o400:, Power /o0:%d of 2" , MOD_Masks , MOD_Upgrades );
1242- pInfo -> Y = 990 - lineHeight ;
1243- SPTXT_vPrintFmtLine ("/o400:Elixir %s/o400:, Knowledge %s" , MOD_Elixir ? "/o0:Yes" : "/o200:No" , MOD_Knowledge ? "/o0:Yes" : "/o200:No" );
1343+ if (MOD_Connected ) {
1344+ // Draw the current Archipelago progression to the bottom in the hall of doors or on the pause screen
1345+ const char * szLevelName = GAM_fn_p_szGetLevelName ();
1346+ const auto inMapMonde = compareStringCaseInsensitive (szLevelName , "mapmonde" ) == 0 ;
1347+ if (inMapMonde || * AI_g_bInGameMenu ) {
1348+ pInfo -> xSize = 6 ;
1349+ pInfo -> bRightAlign = TRUE;
1350+ long lineHeight = SPTXT_fn_lGetCharHeight (pInfo -> xSize );
1351+
1352+ pInfo -> X = 995 ;
1353+ pInfo -> Y = 990 - 4 * lineHeight ;
1354+ SPTXT_vPrintFmtLine ("/o200:Archipelago Received" );
1355+ SPTXT_vPrintFmtLine ("/o400:Lums /o0:%d of 1000/o400:, Cages /o0:%d of 80" , MOD_Lums , MOD_Cages );
1356+ SPTXT_vPrintFmtLine ("/o400:Masks /o0:%d of 4/o400:, Power /o0:%d of 2" , MOD_Masks , MOD_Upgrades );
1357+ SPTXT_vPrintFmtLine ("/o400:Elixir %s/o400:, Knowledge %s" , MOD_Elixir ? "/o0:Yes" : "/o200:No" , MOD_Knowledge ? "/o0:Yes" : "/o200:No" );
1358+ }
1359+
1360+ // When hovering over a portal in mapmonde we show information on the level chain inside
1361+ if (inMapMonde ) {
1362+ HIE_tdstSuperObject * pLums = HIE_fn_p_stFindObjectByName ("YAM_Lums_I1" );
1363+ HIE_tdstSuperObject * pGlobal = HIE_fn_p_stFindObjectByName ("global" );
1364+ if (pLums && pGlobal ) {
1365+ // This variable stores the fade time on the UI box, so 255
1366+ // means that we've been at a portal for enough time to show
1367+ // the UI.
1368+ int * p_stInt ;
1369+ AI_fn_bGetDsgVar (pLums , 19 , NULL , & p_stInt );
1370+ if (* p_stInt == 255 ) {
1371+ // Load the currently highlighted portal into a variable
1372+ HIE_tdstSuperObject * * pPastille ;
1373+ AI_fn_bGetDsgVar (pLums , 5 , NULL , & pPastille );
1374+
1375+ if (* pPastille ) {
1376+ // Dsg var 2 on portals stores their level offset relative to 960
1377+ int * p_stLevelId ;
1378+ AI_fn_bGetDsgVar (* pPastille , 2 , NULL , & p_stLevelId );
1379+
1380+ // Draw information based on the chain
1381+ int chainId = -1 ;
1382+ int nextLevelValue = 960 ;
1383+ int portal = 1 ;
1384+
1385+ // Determine which chain this is and what the next level is for checking if this was completed
1386+ if (* p_stLevelId == 1 ) {
1387+ chainId = CHAIN_FAIRY_GLADE ;
1388+ nextLevelValue += 4 ;
1389+ } else if (* p_stLevelId == 4 ) {
1390+ chainId = CHAIN_MARSHES ;
1391+ nextLevelValue += 7 ;
1392+ portal = 2 ;
1393+ } else if (* p_stLevelId == 6 ) {
1394+ chainId = CHAIN_COBD ;
1395+ nextLevelValue = 1123 ; // We show info when you have the Elixir of Life!
1396+ portal = 3 ;
1397+ } else if (* p_stLevelId == 7 ) {
1398+ chainId = CHAIN_BAYOU ;
1399+ nextLevelValue += 10 ;
1400+ portal = 4 ;
1401+ } else if (* p_stLevelId == 9 ) {
1402+ chainId = CHAIN_WALK_LIFE ;
1403+ nextLevelValue += 0 ; // Walk is always visible!
1404+ portal = 5 ;
1405+ } else if (* p_stLevelId == 10 ) {
1406+ chainId = CHAIN_SANC_WATER ;
1407+ nextLevelValue += 12 ;
1408+ portal = 6 ;
1409+ } else if (* p_stLevelId == 12 ) {
1410+ chainId = CHAIN_MENHIR ;
1411+ nextLevelValue += 16 ;
1412+ portal = 7 ;
1413+ } else if (* p_stLevelId == 16 ) {
1414+ chainId = CHAIN_CANOPY ;
1415+ nextLevelValue += 19 ;
1416+ portal = 8 ;
1417+ } else if (* p_stLevelId == 19 ) {
1418+ chainId = CHAIN_WHALE ;
1419+ nextLevelValue += 21 ;
1420+ portal = 9 ;
1421+ } else if (* p_stLevelId == 21 ) {
1422+ chainId = CHAIN_SANC_STONE ;
1423+ nextLevelValue += 15 ;
1424+ portal = 10 ;
1425+ } else if (* p_stLevelId == 15 ) {
1426+ chainId = CHAIN_ECHOING ;
1427+ nextLevelValue += 25 ;
1428+ portal = 11 ;
1429+ } else if (* p_stLevelId == 25 ) {
1430+ chainId = CHAIN_PRECIPICE ;
1431+ nextLevelValue += 28 ;
1432+ portal = 12 ;
1433+ } else if (* p_stLevelId == 28 ) {
1434+ chainId = CHAIN_TOP ;
1435+ nextLevelValue += 30 ;
1436+ portal = 13 ;
1437+ } else if (* p_stLevelId == 32 ) {
1438+ chainId = CHAIN_WALK_POWER ;
1439+ nextLevelValue += 0 ; // Walk is always visible!
1440+ portal = 14 ;
1441+ } else if (* p_stLevelId == 30 ) {
1442+ chainId = CHAIN_SANC_ROCK ;
1443+ nextLevelValue += 33 ;
1444+ portal = 15 ;
1445+ } else if (* p_stLevelId == 33 ) {
1446+ chainId = CHAIN_BENEATH ;
1447+ nextLevelValue += 47 ;
1448+ portal = 16 ;
1449+ } else if (* p_stLevelId == 47 ) {
1450+ chainId = CHAIN_TOMB ;
1451+ nextLevelValue += 40 ;
1452+ portal = 17 ;
1453+ } else if (* p_stLevelId == 40 ) {
1454+ chainId = CHAIN_IRON_MOUNT ;
1455+ nextLevelValue += 42 ;
1456+ portal = 18 ;
1457+ } else if (* p_stLevelId == 42 ) {
1458+ chainId = CHAIN_PRISON ;
1459+ nextLevelValue += 0 ; // Prison Ship is always visible because we have no reliable checks and it's the last level anyway so you can process of elimination it.
1460+ portal = 19 ;
1461+ }
1462+
1463+ if (chainId != -1 ) {
1464+ pInfo -> xSize = 7 ;
1465+ pInfo -> bRightAlign = FALSE;
1466+ pInfo -> X = 15 ;
1467+
1468+ long lineHeight = SPTXT_fn_lGetCharHeight (pInfo -> xSize );
1469+ ACP_tdxBool isCompleted = AI_fn_bGetBooleanInArray (pGlobal , 42 , nextLevelValue );
1470+
1471+ if (!isCompleted ) {
1472+ int lines = 1 ;
1473+ pInfo -> Y = 550 - lines * lineHeight ;
1474+ SPTXT_vPrintFmtLine ("/o200:Unlock the next level to reveal rooms!" );
1475+ } else {
1476+ // Determine the level contents!
1477+ LevelInfo * levelInfo = NULL ;
1478+ int length = 0 ;
1479+ CrawlLevelInfo (chainId , 0 , & levelInfo , & length , 0 );
1480+
1481+ // Draw the level info in a list, start with a header showing portal number and room count
1482+ long spacer = lineHeight - 2 ;
1483+ pInfo -> Y = 320 ;
1484+ SPTXT_vPrintFmtLine ("/o200:Portal nr. %d" , portal );
1485+ pInfo -> X = 22 ;
1486+ SPTXT_vPrintFmtLine ("/o0:%d rooms" , length );
1487+ pInfo -> Y = pInfo -> Y + spacer ;
1488+
1489+ for (int i = 0 ; i < length ; i ++ ) {
1490+ LevelInfo info = levelInfo [i ];
1491+ pInfo -> X = 15 + info .depth * 10 ;
1492+ SPTXT_vPrintFmtLine ("/o400:%s" , info .name );
1493+ pInfo -> X = 22 + info .depth * 10 ;
1494+ if (info .cagesMax > 0 ) {
1495+ SPTXT_vPrintFmtLine ("/o400:Lums /o0:%d of %d/o400:" , info .lums , info .lumsMax );
1496+ } else {
1497+ SPTXT_vPrintFmtLine ("/o400:Lums /o0:%d of %d/o400:, Cages /o0:%d of %d" , info .lums , info .lumsMax , info .cages , info .cagesMax );
1498+ }
1499+ pInfo -> Y = pInfo -> Y + spacer ;
1500+ }
1501+ }
1502+ }
1503+ }
1504+ }
1505+ }
1506+ }
12441507 }
12451508 SPTXT_vResetTextInfo (pInfo );
12461509}
0 commit comments