hostile-takeover/game/selectmission.cpp
2016-01-03 23:19:26 -08:00

418 lines
12 KiB
C++

#include "game/ht.h"
#include "base/format.h"
#include "yajl/wrapper/jsontypes.h"
#include "game/httppackinfomanager.h"
#include "game/completemanager.h"
namespace wi {
#define kcUnlockAhead 1
#define kfItemLocked 0x8000
// Should be moved into PackInfoManager, but in a better form,
// for getting specific properties without needing to know the key.
const char *GetString(const json::JsonMap *map, const char *key) {
const json::JsonObject *obj = map->GetObject(key);
if (obj == NULL || obj->type() != json::JSONTYPE_STRING) {
return NULL;
}
const json::JsonString *s = (json::JsonString *)obj;
bool fWhitespace = true;
char ch;
const char *psz = s->GetString();
while ((ch = *psz++) != 0) {
if (!isspace(ch)) {
fWhitespace = false;
break;
}
}
if (fWhitespace) {
return NULL;
}
return s->GetString();
}
SelectMissionForm::SelectMissionForm(MissionList *pml,
const MissionIdentifier *pmiidFind) {
m_pml = pml;
m_pmiidFind = pmiidFind;
m_mt = kmtStory;
m_cMagic = 0;
m_fMagicUnlock = false;
#ifdef DEBUG
m_fMagicUnlock = true;
#endif
memset(m_aplstc, 0, sizeof(m_aplstc));
}
bool SelectMissionForm::Init(FormMgr *pfrmm, IniReader *pini, word idf) {
if (!ShellForm::Init(pfrmm, pini, idf))
return false;
// Format the lists. 3 lists are used as a simple cache.
int aidcList[] = { kidcStoryList, kidcChallengeList, kidcAddOnList };
for (int i = 0; i < ARRAYSIZE(aidcList); i++) {
ListControl *plstc = (ListControl *)GetControlPtr(aidcList[i]);
m_aplstc[i] = plstc;
Rect rc;
plstc->GetRect(&rc);
Font *pfnt = gapfnt[kifntShadow];
int cxComplete = pfnt->GetTextExtent("Complete");
int xTitle = rc.Width() / 2 - cxComplete * 3 / 2;
int xRightComplete = rc.Width() - 10;
int xLeftComplete = xRightComplete - cxComplete - cxComplete / 2;
plstc->SetTabStops(xTitle, xLeftComplete, xRightComplete);
plstc->SetTabFlags(kfLstTabEllipsis, kfLstTabCenter, 0);
plstc->SetFlags(plstc->GetFlags() | kfLstcKeepInteriorPositioning);
}
// If asked to find a certain mission, find it first to see what
// type it is, and switch the radio button bar to that type.
int iPack = -1;
int iMission = -1;
int cMissions = m_pml->GetCount();
if (m_pmiidFind != NULL) {
for (int i = 0; i < cMissions; i++) {
MissionIdentifier miid;
m_pml->GetMissionIdentifier(i, &miid);
if (memcmp(&miid.packid, &m_pmiidFind->packid,
sizeof(miid.packid)) == 0) {
if (iPack == -1) {
iPack = i;
}
if (strcmp(miid.szLvlFilename,
m_pmiidFind->szLvlFilename) == 0) {
iMission = i;
break;
}
}
}
if (iMission == -1) {
iMission = iPack;
}
}
int iMissionSelect = iMission;
// Init the lists
MissionType mt = InitLists(iMissionSelect);
SwitchToMissionType(mt);
// Hide this label - only show it if there are no addon packs
GetControlPtr(kidcAddOnMessage)->Show(false);
return true;
}
int SelectMissionForm::IndexFromMissionType(MissionType mt) {
switch (mt) {
case kmtStory:
return 0;
case kmtChallenge:
return 1;
case kmtAddOn:
return 2;
default:
return -1;
}
}
MissionType SelectMissionForm::MissionTypeFromIndex(int i) {
switch (i) {
case 0:
return kmtStory;
case 1:
return kmtChallenge;
case 2:
return kmtAddOn;
default:
return kmtUnknown;
}
}
void SelectMissionForm::SwitchToMissionType(MissionType mt) {
m_mt = mt;
RadioButtonBarControl *prbbc =
(RadioButtonBarControl *)GetControlPtr(kidcCategories);
prbbc->SetSelectionIndex(IndexFromMissionType(mt));
for (int i = 0; i < ARRAYSIZE(m_aplstc); i++) {
bool fShow = false;
if (i == IndexFromMissionType(mt)) {
fShow = true;
}
m_aplstc[i]->Show(fShow);
}
UpdateDescription();
}
MissionType SelectMissionForm::InitLists(int iMissionSelect) {
// Fill in the lists, and along the way keep track of useful selection
// indexes.
int ailiFirstIncomplete[kmtUnknown + 1];
memset(ailiFirstIncomplete, 0xff, sizeof(ailiFirstIncomplete));
int iliLastCompleteStory = -1;
int iliSelectSpecial = -1;
MissionType mtSelectSpecial = kmtUnknown;
int cMissions = m_pml->GetCount();
for (int i = 0; i < cMissions; i++) {
MissionDescription md;
if (!m_pml->GetMissionDescription(i, &md)) {
continue;
}
if (md.mt != kmtStory && md.mt != kmtChallenge && md.mt != kmtAddOn) {
continue;
}
// The first locked mission is kcUnlockAhead missions ahead of the
// last complete story mission.
ListControl *plstc = m_aplstc[IndexFromMissionType(md.mt)];
bool fLocked = false;
if (md.mt == kmtStory) {
int iliMissionLocked = iliLastCompleteStory + 1 + kcUnlockAhead;
int iliNext = plstc->GetCount();
if (iliNext >= iliMissionLocked) {
fLocked = true;
}
}
// Get the status - LOCKED, Complete, or nothing
MissionIdentifier miid;
m_pml->GetMissionIdentifier(i, &miid);
dword dw = (dword)i;
const char *pszStatus = "";
if (fLocked) {
pszStatus = "LOCKED";
dw |= kfItemLocked;
} else {
if (gpcptm->IsComplete(&miid)) {
pszStatus = "Complete";
}
}
// Add the item
plstc->Add(base::Format::ToString("%s\t%s", md.szLvlTitle,
pszStatus), (void *)(pword)dw);
// Track the first incomplete for each mission type.
if (ailiFirstIncomplete[md.mt] == -1) {
if (!gpcptm->IsComplete(&miid)) {
ailiFirstIncomplete[md.mt] = plstc->GetCount() - 1;
}
}
// Track the last complete for story missions, for mission unlocking
if (md.mt == kmtStory) {
if (gpcptm->IsComplete(&miid)) {
iliLastCompleteStory = plstc->GetCount() - 1;
}
}
// This is passed in when the form needs to select a certain
// mission when it first shows.
if (i == iMissionSelect) {
iliSelectSpecial = plstc->GetCount() - 1;
mtSelectSpecial = md.mt;
}
}
// The initially selected missions are the first incomplete missions
// for each mission type.
MissionType mtSelect = kmtStory;
for (int i = 0; i < ARRAYSIZE(m_aplstc); i++) {
ListControl *plstc = m_aplstc[i];
// Is this the list that is awarded the special selection?
if (i == IndexFromMissionType(mtSelectSpecial)) {
plstc->Select(iliSelectSpecial, true, true);
mtSelect = mtSelectSpecial;
continue;
}
int iliSelect = ailiFirstIncomplete[MissionTypeFromIndex(i)];
if (iliSelect < 0) {
iliSelect = 0;
}
plstc->Select(iliSelect, true, true);
}
return mtSelect;
}
bool SelectMissionForm::OnPenEvent(Event *pevt) {
if (m_mt != kmtStory || pevt->eType != penUpEvent) {
return ShellForm::OnPenEvent(pevt);
}
Control *pctlCaptureBefore = GetControlCapture();
bool f = ShellForm::OnPenEvent(pevt);
Control *pctlCaptureAfter = GetControlCapture();
#define kcMagic 5
// Tap down on back, move your finger off so it unhighlights, then
// let up. Do this kcMagic times and get a play button.
if (pctlCaptureBefore != NULL && pctlCaptureAfter == NULL) {
if (pctlCaptureBefore->GetId() == kidcCancel) {
m_cMagic++;
if (m_cMagic >= kcMagic) {
m_cMagic = 0;
m_fMagicUnlock = true;
#ifdef BETA_TIMEOUT
GetControlPtr(kidcOk)->Show(true);
#endif
}
}
}
return f;
}
void SelectMissionForm::OnControlSelected(word idc) {
switch (idc) {
case kidcOk:
case kidcCancel:
EndForm(idc);
break;
case kidcSetupGame:
{
ShellForm *pfrm = (ShellForm *)gpmfrmm->LoadForm(gpiniForms,
kidfInGameOptions, new InGameOptionsForm());
if (pfrm != NULL) {
pfrm->DoModal();
delete pfrm;
}
}
break;
}
}
void SelectMissionForm::OnControlNotify(word idc, int nNotify) {
if (idc == kidcCategories) {
RadioButtonBarControl *prbbc =
(RadioButtonBarControl *)GetControlPtr(kidcCategories);
int iButtonSelected = prbbc->GetSelectionIndex();
if (iButtonSelected < 0) {
iButtonSelected = 0;
}
MissionType mtNew = MissionTypeFromIndex(iButtonSelected);
if (mtNew == m_mt) {
return;
}
SwitchToMissionType(mtNew);
// If in Add-On category, and there is nothing there, show this
// label, otherwise hide it
bool fShowLabel = false;
ListControl *plstc = m_aplstc[IndexFromMissionType(kmtAddOn)];
if (m_mt == kmtAddOn) {
if (plstc->GetCount() == 0) {
fShowLabel = true;
}
}
LabelControl *plbl = (LabelControl *)GetControlPtr(kidcAddOnMessage);
if (fShowLabel) {
plbl->Show(true);
if (m_mt == kmtAddOn) {
plstc->Show(false);
}
} else {
plbl->Show(false);
if (m_mt == kmtAddOn) {
plstc->Show(true);
}
}
}
if (idc == kidcStoryList || idc == kidcChallengeList ||
idc == kidcAddOnList) {
// Update the mission pack description
UpdateDescription();
}
// Handle button hiding
bool fShow = true;
ListControl *plstc = m_aplstc[IndexFromMissionType(m_mt)];
if (plstc->GetSelectedItemIndex() == -1) {
fShow = false;
}
if (m_mt == kmtStory) {
if (IsSelectedMissionLocked(plstc)) {
fShow = false;
}
}
if (m_fMagicUnlock) {
fShow = true;
}
GetControlPtr(kidcOk)->Show(fShow);
}
int SelectMissionForm::GetSelectedMissionIndex(ListControl *plstc) {
pword pw = (pword)plstc->GetSelectedItemData();
return (int)(pw & ~kfItemLocked);
}
bool SelectMissionForm::IsSelectedMissionLocked(ListControl *plstc) {
pword pw = (pword)plstc->GetSelectedItemData();
return (pw & kfItemLocked) != 0;
}
void SelectMissionForm::UpdateDescription() {
LabelControl *plbl = (LabelControl *)GetControlPtr(kidcMissionPackInfo);
ListControl *plstc = m_aplstc[IndexFromMissionType(m_mt)];
if (plstc->GetSelectedItemIndex() == -1) {
plbl->SetText("");
return;
}
int i = GetSelectedMissionIndex(plstc);
MissionIdentifier miid;
if (!m_pml->GetMissionIdentifier(i, &miid)) {
plbl->SetText("");
return;
}
json::JsonMap *map = gppim->GetInfoMap(&miid.packid);
if (map == NULL) {
MissionDescription md;
if (!m_pml->GetMissionDescription(i, &md)) {
plbl->SetText("");
return;
}
const char *s;
if (miid.packid.id == PACKID_MAIN) {
s = base::Format::ToString("%s by Spiffcode, Inc.", md.szPackName);
} else {
s = md.szPackName;
}
plbl->SetText(s);
return;
}
const char *szAuthor = GetString(map, "a");
const char *szTitle = GetString(map, "t");
const char *s = base::Format::ToString("%s by %s", szTitle, szAuthor);
plbl->SetText(s);
delete map;
}
bool SelectMissionForm::GetSelectedMission(MissionIdentifier *pmiid) {
ListControl *plstc = m_aplstc[IndexFromMissionType(m_mt)];
int i = GetSelectedMissionIndex(plstc);
return m_pml->GetMissionIdentifier(i, pmiid);
}
} // namespace wi