Path: blob/master/SonicMania/Objects/Helpers/GameProgress.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: GameProgress Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89// clang-format off10AchievementID achievementList[] = {11{ .idPS4 = 0, .idUnknown = 19, .id = "ACH_GOLD_MEDAL" },12{ .idPS4 = 1, .idUnknown = 20, .id = "ACH_SILVER_MEDAL" },13{ .idPS4 = 2, .idUnknown = 21, .id = "ACH_EMERALDS" },14{ .idPS4 = 3, .idUnknown = 22, .id = "ACH_GAME_CLEARED" },15{ .idPS4 = 4, .idUnknown = 23, .id = "ACH_STARPOST" },16{ .idPS4 = 5, .idUnknown = 24, .id = "ACH_SIGNPOST" },17{ .idPS4 = 6, .idUnknown = 25, .id = "ACH_GHZ" },18{ .idPS4 = 7, .idUnknown = 26, .id = "ACH_CPZ" },19{ .idPS4 = 8, .idUnknown = 27, .id = "ACH_SPZ" },20{ .idPS4 = 9, .idUnknown = 28, .id = "ACH_FBZ" },21{ .idPS4 = 10, .idUnknown = 29, .id = "ACH_PGZ" },22{ .idPS4 = 11, .idUnknown = 30, .id = "ACH_SSZ" },23{ .idPS4 = 12, .idUnknown = 31, .id = "ACH_HCZ" },24{ .idPS4 = 13, .idUnknown = 32, .id = "ACH_MSZ" },25{ .idPS4 = 14, .idUnknown = 33, .id = "ACH_OOZ" },26{ .idPS4 = 15, .idUnknown = 34, .id = "ACH_LRZ" },27{ .idPS4 = 16, .idUnknown = 35, .id = "ACH_MMZ" },28{ .idPS4 = 17, .idUnknown = 36, .id = "ACH_TMZ" },29};30// clang-format on3132ObjectGameProgress *GameProgress;3334void GameProgress_Update(void) {}3536void GameProgress_LateUpdate(void) {}3738void GameProgress_StaticUpdate(void) {}3940void GameProgress_Draw(void) {}4142void GameProgress_Create(void *data) {}4344void GameProgress_StageLoad(void) {}4546ProgressRAM *GameProgress_GetProgressRAM(void) { return (ProgressRAM *)&globals->saveRAM[0x900]; }4748int32 GameProgress_GetNotifStringID(int32 type)49{50switch (type) {51case GAMEPROGRESS_UNLOCK_TIMEATTACK: return STR_TAUNLOCKED;5253case GAMEPROGRESS_UNLOCK_COMPETITION: return STR_COMPUNLOCKED;5455case GAMEPROGRESS_UNLOCK_PEELOUT: return STR_PEELOUTUNLOCKED;5657case GAMEPROGRESS_UNLOCK_INSTASHIELD: return STR_INSTASHIELDUNLOCKED;5859case GAMEPROGRESS_UNLOCK_ANDKNUX: return STR_ANDKNUXUNLOCKED;6061case GAMEPROGRESS_UNLOCK_DEBUGMODE: return STR_DEBUGMODEUNLOCKED;6263case GAMEPROGRESS_UNLOCK_MEANBEAN: return STR_MBMUNLOCKED;6465case GAMEPROGRESS_UNLOCK_DAGARDEN: return STR_DAGARDENUNLOCKED;6667case GAMEPROGRESS_UNLOCK_BLUESPHERES: return STR_BLUESPHERESUNLOCKED;6869default: return STR_FEATUREUNIMPLIMENTED;70}71}7273void GameProgress_ShuffleBSSID(void)74{75ProgressRAM *progress = GameProgress_GetProgressRAM();7677int32 startID = globals->blueSpheresID;78if (progress) {79while (true) {80if (globals->blueSpheresInit) {81++globals->blueSpheresID;82globals->blueSpheresID %= GAMEPROGRESS_MEDAL_COUNT;83}84else {85globals->blueSpheresID = 0;86globals->blueSpheresInit = true;87}8889if (progress->goldMedalCount >= GAMEPROGRESS_MEDAL_COUNT)90break;9192bool32 rotatedBSS = false;93if (progress->silverMedalCount < GAMEPROGRESS_MEDAL_COUNT)94rotatedBSS = progress->medals[globals->blueSpheresID] == 0;95else96rotatedBSS = progress->medals[globals->blueSpheresID] < 2;9798if (rotatedBSS) {99LogHelpers_Print("Blue Spheres ID rotated by %d to %d", globals->blueSpheresID - startID, globals->blueSpheresID);100break;101}102}103}104else {105if (globals->blueSpheresInit) {106globals->blueSpheresID++;107globals->blueSpheresID %= GAMEPROGRESS_MEDAL_COUNT;108}109else {110globals->blueSpheresID = 0;111globals->blueSpheresInit = true;112}113114LogHelpers_Print("WARNING GameProgress Attempted to get BS ID before loading SaveGame file");115LogHelpers_Print("Blue Spheres ID rotated by %d to %d", globals->blueSpheresID - startID, globals->blueSpheresID);116}117}118119bool32 GameProgress_GetZoneUnlocked(int32 zoneID)120{121if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {122LogHelpers_Print("WARNING GameProgress Attempted to check zone clear before loading SaveGame file");123return false;124}125else {126ProgressRAM *progress = GameProgress_GetProgressRAM();127return progress->zoneCleared[zoneID];128}129}130131float GameProgress_GetCompletionPercent(ProgressRAM *progress)132{133int32 completeZones = 0;134int32 medalsGotten = 0;135int32 emeraldsGotten = 0;136137for (int32 i = 0; i < GAMEPROGRESS_MEDAL_COUNT; ++i) {138if (i < GAMEPROGRESS_EMERALD_COUNT)139emeraldsGotten += progress->emeraldObtained[i] == 1;140141if (i < ZONE_ERZ)142completeZones += progress->zoneCleared[i] == 1;143144medalsGotten += progress->medals[i];145}146147// get the count of the unlock148// then multiply by its completion weight (in this case zones are worth 55% of completion percent)149// then finally divide by the maximum count to normalize it150151float zonePercent = ((MIN(completeZones, GAMEPROGRESS_ZONE_COUNT) * 0.55) / (float)GAMEPROGRESS_ZONE_COUNT);152float medalPercent = ((MIN(medalsGotten, GAMEPROGRESS_MEDAL_COUNT * 2) * 0.35) / (float)(GAMEPROGRESS_MEDAL_COUNT * 2));153float specialPercent = ((MIN(emeraldsGotten, GAMEPROGRESS_EMERALD_COUNT) * 0.05) / (float)GAMEPROGRESS_EMERALD_COUNT);154float endingPercent = ((MIN(progress->unlockedEndingID, GAMEPROGRESS_ENDING_GOOD) * 0.05) / (float)GAMEPROGRESS_ENDING_GOOD);155return zonePercent + medalPercent + specialPercent + endingPercent;156}157158#if MANIA_USE_PLUS159void GameProgress_TrackGameProgress(void (*callback)(bool32 success))160#else161void GameProgress_TrackGameProgress(void (*callback)(void))162#endif163{164if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {165LogHelpers_Print("WARNING GameProgress Attempted to track progress before loading SaveGame file");166}167else {168ProgressRAM *progress = GameProgress_GetProgressRAM();169if (!progress->allSpecialCleared) {170float percent = GameProgress_GetCompletionPercent(progress);171#if MANIA_USE_PLUS172StatInfo stat;173memset(&stat, 0, sizeof(StatInfo));174stat.statID = 3;175stat.name = "GAME_PROGRESS";176stat.data[0] = FLOAT_TO_VOID(percent);177API.TryTrackStat(&stat);178#else179APICallback_TrackGameProgress(percent);180#endif181SaveGame_SaveFile(callback);182return;183}184}185186#if MANIA_USE_PLUS187if (callback)188callback(false);189#else190if (callback)191callback();192#endif193}194void GameProgress_ClearBSSSave(void)195{196if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {197LogHelpers_Print("WARNING GameProgress Attempted to clear BSS before loading SaveGame file");198return;199}200201ProgressRAM *progress = GameProgress_GetProgressRAM();202progress->allGoldMedals = false;203progress->allSilverMedals = false;204progress->goldMedalCount = 0;205progress->silverMedalCount = 0;206memset(progress->medals, 0, sizeof(progress->medals));207}208void GameProgress_UnlockAll(void)209{210if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {211LogHelpers_Print("WARNING GameProgress Attempted to unlock all before loading SaveGame file");212return;213}214215ProgressRAM *progress = GameProgress_GetProgressRAM();216217progress->allSpecialCleared = true;218progress->allEmeraldsObtained = true;219progress->unlockedEndingID = GAMEPROGRESS_ENDING_GOOD;220progress->silverMedalCount = GAMEPROGRESS_MEDAL_COUNT;221progress->goldMedalCount = GAMEPROGRESS_MEDAL_COUNT;222progress->allGoldMedals = true;223progress->allSilverMedals = true;224225for (int32 m = 0; m < GAMEPROGRESS_MEDAL_COUNT; ++m) {226if (m < GAMEPROGRESS_EMERALD_COUNT)227progress->emeraldObtained[m] = true;228229if (m < GAMEPROGRESS_ZONE_COUNT)230progress->zoneCleared[m] = true;231232progress->medals[m] = GAMEPROGRESS_MEDAL_GOLD;233}234}235236void GameProgress_LockAllSpecialClear(void)237{238if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {239LogHelpers_Print("WARNING GameProgress Attempted to lock special clear before loading SaveGame file");240}241else {242ProgressRAM *progress = GameProgress_GetProgressRAM();243progress->allSpecialCleared = false;244}245}246247void GameProgress_ClearProgress(void)248{249if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {250LogHelpers_Print("WARNING GameProgress Attempted to clear all before loading SaveGame file");251return;252}253254ProgressRAM *progress = GameProgress_GetProgressRAM();255256progress->allSpecialCleared = false;257progress->allEmeraldsObtained = false;258progress->unlockedEndingID = GAMEPROGRESS_ENDING_NONE;259progress->silverMedalCount = 0;260progress->goldMedalCount = 0;261progress->allGoldMedals = false;262progress->allSilverMedals = false;263264for (int32 m = 0; m < GAMEPROGRESS_MEDAL_COUNT; ++m) {265if (m < GAMEPROGRESS_EMERALD_COUNT)266progress->emeraldObtained[m] = false;267268if (m < GAMEPROGRESS_ZONE_COUNT)269progress->zoneCleared[m] = false;270271if (m < GAMEPROGRESS_EMERALD_COUNT)272progress->specialCleared[m] = false;273274if (m < GAMEPROGRESS_UNLOCK_COUNT)275progress->unreadNotifs[m] = false;276277progress->medals[m] = GAMEPROGRESS_MEDAL_NONE;278}279}280281void GameProgress_MarkZoneCompleted(int32 zoneID)282{283if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {284LogHelpers_Print("WARNING GameProgress Attempted to mark completed zone before loading SaveGame file");285return;286}287288if (zoneID > ZONE_INVALID) {289ProgressRAM *progress = GameProgress_GetProgressRAM();290for (int32 z = 0; z <= zoneID; ++z) {291if (!progress->zoneCleared[z]) {292LogHelpers_Print("PROGRESS Cleared zone %d", z);293progress->zoneCleared[z] = true;294}295}296}297}298299bool32 GameProgress_CheckZoneClear(void)300{301if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {302LogHelpers_Print("WARNING GameProgress Attempted to check zone clear before loading SaveGame file");303return false;304}305306ProgressRAM *progress = GameProgress_GetProgressRAM();307308for (int32 z = 0; z < GAMEPROGRESS_ZONE_COUNT; ++z) {309if (!progress->zoneCleared[z]) {310GameProgress_MarkZoneCompleted(z);311return true;312}313}314315return false;316}317318void GameProgress_GiveEmerald(int32 emeraldID)319{320if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {321LogHelpers_Print("WARNING GameProgress Attempted to get emerald before loading SaveGame file");322return;323}324325ProgressRAM *progress = GameProgress_GetProgressRAM();326327progress->emeraldObtained[emeraldID] = true;328bool32 allEmeralds = true;329for (int32 i = 0; i < GAMEPROGRESS_EMERALD_COUNT; ++i) {330allEmeralds = allEmeralds && progress->emeraldObtained[i];331}332333if (allEmeralds)334progress->allEmeraldsObtained = true;335}336337void GameProgress_GiveMedal(uint8 medalID, uint8 type)338{339if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {340LogHelpers_Print("WARNING GameProgress Attempted to get medallion before loading SaveGame file");341return;342}343344ProgressRAM *progress = GameProgress_GetProgressRAM();345int32 goldCount = 0;346int32 silverCount = 0;347for (int32 m = 0; m < GAMEPROGRESS_MEDAL_COUNT; ++m) {348if (m == medalID && type > progress->medals[m])349progress->medals[m] = type;350351if (progress->medals[m] >= GAMEPROGRESS_MEDAL_GOLD)352++goldCount;353354if (progress->medals[m] >= GAMEPROGRESS_MEDAL_SILVER)355++silverCount;356}357358progress->goldMedalCount = goldCount;359progress->silverMedalCount = silverCount;360361LogHelpers_Print("Get %d medallion #%d", type, medalID);362LogHelpers_Print("Gold: %d %d, Silver: %d %d", goldCount, goldCount >= GAMEPROGRESS_MEDAL_COUNT, silverCount,363silverCount >= GAMEPROGRESS_MEDAL_COUNT);364365if (goldCount >= GAMEPROGRESS_MEDAL_COUNT)366progress->allGoldMedals = true;367368if (silverCount >= GAMEPROGRESS_MEDAL_COUNT)369progress->allSilverMedals = true;370}371372void GameProgress_GiveEnding(uint8 ending)373{374if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {375LogHelpers_Print("WARNING GameProgress Attempted to get game ending before loading SaveGame file");376}377378ProgressRAM *progress = GameProgress_GetProgressRAM();379if (ending > progress->unlockedEndingID)380progress->unlockedEndingID = ending;381}382383void GameProgress_PrintSaveProgress(void)384{385if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {386LogHelpers_Print("WARNING GameProgress Attempted to dump before loading SaveGame file");387return;388}389390ProgressRAM *progress = GameProgress_GetProgressRAM();391392LogHelpers_Print("=========================");393LogHelpers_Print("Game Progress:\n");394395for (int32 e = 0; e < GAMEPROGRESS_EMERALD_COUNT; ++e) {396if (progress->emeraldObtained[e])397LogHelpers_Print("Emerald %d => TRUE", e);398else399LogHelpers_Print("Emerald %d => FALSE", e);400}401402if (progress->allEmeraldsObtained)403LogHelpers_Print("ALL EMERALDS!\n");404else405LogHelpers_Print("YOU'VE NOT ENOUGH EMERALDS!\n");406407for (int32 z = 0; z < GAMEPROGRESS_ZONE_COUNT; ++z) {408if (progress->zoneCleared[z])409LogHelpers_Print("Zone %d clear => TRUE", z);410else411LogHelpers_Print("Zone %d clear => FALSE", z);412}413414switch (progress->unlockedEndingID) {415default:416case GAMEPROGRESS_ENDING_NONE: LogHelpers_Print("NO ENDING!\n"); break;417418case GAMEPROGRESS_ENDING_BAD: LogHelpers_Print("BAD ENDING!\n"); break;419420case GAMEPROGRESS_ENDING_GOOD: LogHelpers_Print("GOOD ENDING!\n"); break;421}422423for (int32 m = 0; m < GAMEPROGRESS_MEDAL_COUNT; ++m) {424switch (progress->medals[m]) {425default:426case GAMEPROGRESS_MEDAL_GOLD: LogHelpers_Print("Medallion %d => GOLD", m); break;427428case GAMEPROGRESS_MEDAL_SILVER: LogHelpers_Print("Medallion %d => SILVER", m); break;429430case GAMEPROGRESS_MEDAL_NONE: LogHelpers_Print("Medallion %d => NULL", m); break;431}432}433434LogHelpers_Print("GOLD COUNT: %d", progress->goldMedalCount);435if (progress->allGoldMedals)436LogHelpers_Print("ALL GOLD MEDALLIONS!");437438LogHelpers_Print("SILVER COUNT: %d", progress->silverMedalCount);439if (progress->silverMedalCount)440LogHelpers_Print("ALL SILVER MEDALLIONS!");441442LogHelpers_Print("\n=========================");443}444int32 GameProgress_CountUnreadNotifs(void)445{446if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {447LogHelpers_Print("WARNING GameProgress Attempted to count unread notifs before loading SaveGame file");448return 0;449}450else {451int32 unreadCount = 0;452ProgressRAM *progress = GameProgress_GetProgressRAM();453for (int32 i = 0; i < GAMEPROGRESS_UNLOCK_COUNT; ++i) {454bool32 unlocked = progress->unreadNotifs[i];455bool32 notif = GameProgress_CheckUnlock(i);456457if (!unlocked && notif)458unreadCount++;459}460461return unreadCount;462}463}464int32 GameProgress_GetNextNotif(void)465{466if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {467LogHelpers_Print("WARNING GameProgress Attempted to get next unread notif before loading SaveGame file");468return -1;469}470else {471ProgressRAM *progress = GameProgress_GetProgressRAM();472for (int32 i = 0; i < GAMEPROGRESS_UNLOCK_COUNT; ++i) {473bool32 unlocked = progress->unreadNotifs[i];474bool32 notif = GameProgress_CheckUnlock(i);475476if (!unlocked && notif)477return i;478}479}480481return -1;482}483bool32 GameProgress_CheckUnlock(uint8 id)484{485if (SceneInfo->inEditor || API_GetNoSave() || globals->saveLoaded != STATUS_OK) {486LogHelpers_Print("WARNING GameProgress Attempted to check unlock before loading SaveGame file");487return false;488}489else {490ProgressRAM *progress = GameProgress_GetProgressRAM();491switch (id) {492case GAMEPROGRESS_UNLOCK_TIMEATTACK:493case GAMEPROGRESS_UNLOCK_COMPETITION: return progress->zoneCleared[0];494495case GAMEPROGRESS_UNLOCK_PEELOUT: return progress->silverMedalCount >= 1;496497case GAMEPROGRESS_UNLOCK_INSTASHIELD: return progress->silverMedalCount >= 6;498499case GAMEPROGRESS_UNLOCK_ANDKNUX: return progress->silverMedalCount >= 11;500501case GAMEPROGRESS_UNLOCK_DEBUGMODE: return progress->silverMedalCount >= 16;502503case GAMEPROGRESS_UNLOCK_MEANBEAN: return progress->silverMedalCount >= 21;504505case GAMEPROGRESS_UNLOCK_DAGARDEN: return progress->silverMedalCount >= 26;506507case GAMEPROGRESS_UNLOCK_BLUESPHERES: return progress->silverMedalCount >= GAMEPROGRESS_MEDAL_COUNT;508509default: return false;510}511}512}513514#if GAME_INCLUDE_EDITOR515void GameProgress_EditorDraw(void) {}516517void GameProgress_EditorLoad(void) {}518#endif519void GameProgress_Serialize(void) {}520521522