bool ScreenMissionSummary(CampaignOptions *c, struct MissionOptions *m) { // Save password MissionSave ms; MissionSaveInit(&ms); ms.Campaign = c->Entry; // Don't make password for next level if there is none int passwordIndex = m->index + 1; if (passwordIndex == c->Entry.NumMissions) { passwordIndex--; } strcpy(ms.Password, MakePassword(passwordIndex, 0)); ms.MissionsCompleted = m->index + 1; AutosaveAddMission(&gAutosave, &ms, ms.Campaign.BuiltinIndex); AutosaveSave(&gAutosave, GetConfigFilePath(AUTOSAVE_FILE)); // Calculate bonus scores // Bonuses only apply if at least one player has lived if (AreAnySurvived()) { int bonus = 0; // Objective bonuses for (int i = 0; i < (int)m->missionData->Objectives.size; i++) { const struct Objective *o = CArrayGet(&m->Objectives, i); const MissionObjective *mo = CArrayGet(&m->missionData->Objectives, i); if (o->done == mo->Count && o->done > mo->Required) { // Perfect bonus += PERFECT_BONUS; } } bonus += GetAccessBonus(m); bonus += GetTimeBonus(m, NULL); for (int i = 0; i < (int)gPlayerDatas.size; i++) { PlayerData *p = CArrayGet(&gPlayerDatas, i); ApplyBonuses(p, bonus); } } GameLoopWaitForAnyKeyOrButtonData wData; GameLoopData gData = GameLoopDataNew( &wData, GameLoopWaitForAnyKeyOrButtonFunc, m, MissionSummaryDraw); GameLoop(&gData); if (wData.IsOK) { SoundPlay(&gSoundDevice, StrSound("mg")); } return wData.IsOK; }
static void MissionSummaryDraw(void *data) { // This will only draw once const struct MissionOptions *m = data; GraphicsBlitBkg(&gGraphicsDevice); const int w = gGraphicsDevice.cachedConfig.Res.x; const int h = gGraphicsDevice.cachedConfig.Res.y; // Display password if (strlen(gAutosave.LastMission.Password) > 0) { char s[64]; sprintf(s, "Last password: %s", gAutosave.LastMission.Password); FontOpts opts = FontOptsNew(); opts.HAlign = ALIGN_CENTER; opts.VAlign = ALIGN_END; opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad.y = opts.Area.y / 12; FontStrOpt(s, Vec2iZero(), opts); } // Display objectives and bonuses Vec2i pos = Vec2iNew(w / 6, h / 2 + h / 10); int idx = 1; for (int i = 0; i < (int)m->missionData->Objectives.size; i++) { const struct Objective *o = CArrayGet(&m->Objectives, i); const MissionObjective *mo = CArrayGet(&m->missionData->Objectives, i); // Do not mention optional objectives with none completed if (o->done == 0 && mo->Required == 0) { continue; } // Objective icon DrawObjectiveInfo(m, i, Vec2iAdd(pos, Vec2iNew(-26, FontH()))); // Objective completion text char s[100]; sprintf(s, "Objective %d: %d of %d, %d required", idx, o->done, mo->Count, mo->Required); FontOpts opts = FontOptsNew(); opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad = pos; if (mo->Required == 0) { // Show optional objectives in purple opts.Mask = colorPurple; } FontStrOpt(s, Vec2iZero(), opts); // Objective status text opts = FontOptsNew(); opts.HAlign = ALIGN_END; opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad = pos; if (o->done < mo->Required) { opts.Mask = colorRed; FontStrOpt("Failed", Vec2iZero(), opts); } else if ( o->done == mo->Count && o->done > mo->Required && AreAnySurvived()) { opts.Mask = colorGreen; char buf[16]; sprintf(buf, "Perfect: %d", PERFECT_BONUS); FontStrOpt(buf, Vec2iZero(), opts); } else if (mo->Required > 0) { FontStrOpt("Done", Vec2iZero(), opts); } else { FontStrOpt("Bonus!", Vec2iZero(), opts); } pos.y += 15; idx++; } // Draw other bonuses if (AreAnySurvived()) { char s[64]; sprintf(s, "Access bonus: %d", GetAccessBonus(m)); FontStr(s, pos); pos.y += FontH() + 1; int seconds; const int timeBonus = GetTimeBonus(m, &seconds); sprintf(s, "Time bonus: %d secs x 25 = %d", seconds, timeBonus); FontStr(s, pos); } // Draw per-player summaries Vec2i size; switch (gPlayerDatas.size) { case 1: size = Vec2iNew(w, h / 2); DrawPlayerSummary(Vec2iZero(), size, CArrayGet(&gPlayerDatas, 0)); break; case 2: // side by side size = Vec2iNew(w / 2, h / 2); DrawPlayerSummary(Vec2iZero(), size, CArrayGet(&gPlayerDatas, 0)); DrawPlayerSummary( Vec2iNew(w / 2, 0), size, CArrayGet(&gPlayerDatas, 1)); break; case 3: // fallthrough case 4: // 2x2 size = Vec2iNew(w / 2, h / 4); DrawPlayerSummary(Vec2iZero(), size, CArrayGet(&gPlayerDatas, 0)); DrawPlayerSummary( Vec2iNew(w / 2, 0), size, CArrayGet(&gPlayerDatas, 1)); DrawPlayerSummary( Vec2iNew(0, h / 4), size, CArrayGet(&gPlayerDatas, 2)); if (gPlayerDatas.size == 4) { DrawPlayerSummary( Vec2iNew(w / 2, h / 4), size, CArrayGet(&gPlayerDatas, 3)); } break; default: CASSERT(false, "not implemented"); break; } }
static void MissionSummaryDraw( const menu_t *menu, GraphicsDevice *g, const Vec2i p, const Vec2i size, const void *data) { UNUSED(menu); UNUSED(p); UNUSED(size); const struct MissionOptions *m = data; const int w = gGraphicsDevice.cachedConfig.Res.x; const int h = gGraphicsDevice.cachedConfig.Res.y; // Display password if (strlen(gAutosave.LastMission.Password) > 0) { char s[64]; sprintf(s, "Last password: %s", gAutosave.LastMission.Password); FontOpts opts = FontOptsNew(); opts.HAlign = ALIGN_CENTER; opts.VAlign = ALIGN_END; opts.Area = g->cachedConfig.Res; opts.Pad.y = opts.Area.y / 12; FontStrOpt(s, Vec2iZero(), opts); } // Display objectives and bonuses Vec2i pos = Vec2iNew(w / 6, h / 2 + h / 10); int idx = 1; CA_FOREACH(const Objective, o, m->missionData->Objectives) // Do not mention optional objectives with none completed if (o->done == 0 && !ObjectiveIsRequired(o)) { continue; } // Objective icon DrawObjectiveInfo(o, Vec2iAdd(pos, Vec2iNew(-26, FontH()))); // Objective completion text char s[100]; sprintf(s, "Objective %d: %d of %d, %d required", idx, o->done, o->Count, o->Required); FontOpts opts = FontOptsNew(); opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad = pos; if (!ObjectiveIsRequired(o)) { // Show optional objectives in purple opts.Mask = colorPurple; } FontStrOpt(s, Vec2iZero(), opts); // Objective status text opts = FontOptsNew(); opts.HAlign = ALIGN_END; opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad = pos; if (!ObjectiveIsComplete(o)) { opts.Mask = colorRed; FontStrOpt("Failed", Vec2iZero(), opts); } else if (ObjectiveIsPerfect(o) && AreAnySurvived()) { opts.Mask = colorGreen; char buf[16]; sprintf(buf, "Perfect: %d", PERFECT_BONUS); FontStrOpt(buf, Vec2iZero(), opts); } else if (ObjectiveIsRequired(o)) { FontStrOpt("Done", Vec2iZero(), opts); } else { FontStrOpt("Bonus!", Vec2iZero(), opts); } pos.y += 15; idx++; CA_FOREACH_END() // Draw other bonuses if (AreAnySurvived()) { char s[64]; sprintf(s, "Access bonus: %d", GetAccessBonus(m)); FontStr(s, pos); pos.y += FontH() + 1; int seconds; const int timeBonus = GetTimeBonus(m, &seconds); sprintf(s, "Time bonus: %d secs x 25 = %d", seconds, timeBonus); FontStr(s, pos); } // Draw per-player summaries PlayerData *pds[MAX_LOCAL_PLAYERS]; idx = 0; CA_FOREACH(PlayerData, pd, gPlayerDatas) if (!pd->IsLocal) { continue; } pds[idx] = pd; idx++; CA_FOREACH_END() Vec2i playerSize; switch (idx) { case 1: playerSize = Vec2iNew(w, h / 2); DrawPlayerSummary(Vec2iZero(), playerSize, pds[0]); break; case 2: // side by side playerSize = Vec2iNew(w / 2, h / 2); DrawPlayerSummary(Vec2iZero(), playerSize, pds[0]); DrawPlayerSummary(Vec2iNew(w / 2, 0), playerSize, pds[1]); break; case 3: // fallthrough case 4: // 2x2 playerSize = Vec2iNew(w / 2, h / 4); DrawPlayerSummary(Vec2iZero(), playerSize, pds[0]); DrawPlayerSummary(Vec2iNew(w / 2, 0), playerSize, pds[1]); DrawPlayerSummary(Vec2iNew(0, h / 4), playerSize, pds[2]); if (idx == 4) { DrawPlayerSummary(Vec2iNew(w / 2, h / 4), playerSize, pds[3]); } break; default: CASSERT(false, "not implemented"); break; } }
bool ScreenMissionSummary( CampaignOptions *c, struct MissionOptions *m, const bool completed) { if (completed) { // Save password MissionSave ms; MissionSaveInit(&ms); ms.Campaign = c->Entry; // Don't make password for next level if there is none int passwordIndex = m->index + 1; if (passwordIndex == c->Entry.NumMissions) { passwordIndex--; } strcpy(ms.Password, MakePassword(passwordIndex, 0)); ms.MissionsCompleted = m->index + 1; AutosaveAddMission(&gAutosave, &ms); AutosaveSave(&gAutosave, GetConfigFilePath(AUTOSAVE_FILE)); } // Calculate bonus scores // Bonuses only apply if at least one player has lived if (AreAnySurvived()) { int bonus = 0; // Objective bonuses CA_FOREACH(const Objective, o, m->missionData->Objectives) if (ObjectiveIsPerfect(o)) { bonus += PERFECT_BONUS; } CA_FOREACH_END() bonus += GetAccessBonus(m); bonus += GetTimeBonus(m, NULL); CA_FOREACH(PlayerData, p, gPlayerDatas) ApplyBonuses(p, bonus); CA_FOREACH_END() } MenuSystem ms; const int h = FontH() * 10; MenuSystemInit( &ms, &gEventHandlers, &gGraphicsDevice, Vec2iNew(0, gGraphicsDevice.cachedConfig.Res.y - h), Vec2iNew(gGraphicsDevice.cachedConfig.Res.x, h)); ms.current = ms.root = MenuCreateNormal("", "", MENU_TYPE_NORMAL, 0); // Use return code 0 for whether to continue the game if (completed) { MenuAddSubmenu(ms.root, MenuCreateReturn("Continue", 0)); } else { MenuAddSubmenu(ms.root, MenuCreateReturn("Replay mission", 0)); MenuAddSubmenu(ms.root, MenuCreateReturn("Back to menu", 1)); } ms.allowAborts = true; MenuAddExitType(&ms, MENU_TYPE_RETURN); MenuSystemAddCustomDisplay(&ms, MissionSummaryDraw, m); MenuLoop(&ms); return ms.current->u.returnCode == 0; }