void CDesignCollection::GetEnabledExtensions (TArray<CExtension *> *retExtensionList) // GetEnabledExtensions // // Returns the list of enabled extensions { int i; retExtensionList->DeleteAll(); for (i = 0; i < GetExtensionCount(); i++) { CExtension *pEntry = GetExtension(i); if (pEntry->GetType() == extExtension) retExtensionList->Insert(pEntry); } }
ALERROR CDesignCollection::BindDesign (const TArray<CExtension *> &BindOrder, bool bNewGame, bool bNoResources, CString *retsError) // BindDesign // // Binds the design collection to the set of design types in the given list of // extensions. { DEBUG_TRY ALERROR error; int i; // Unbind everything DEBUG_TRY CShipClass::UnbindGlobal(); for (i = 0; i < m_AllTypes.GetCount(); i++) m_AllTypes.GetEntry(i)->UnbindDesign(); m_AllTypes.DeleteAll(); DEBUG_CATCH_MSG("Crash unbinding types."); // Reset the bind tables for (i = 0; i < designCount; i++) m_ByType[i].DeleteAll(); m_CreatedTypes.DeleteAll(true); m_OverrideTypes.DeleteAll(); // Reset m_pTopology = NULL; m_pAdventureExtension = NULL; // Create a design load context SDesignLoadCtx Ctx; Ctx.bBindAsNewGame = bNewGame; Ctx.bNoResources = bNoResources; // Loop over the bind list in order and add appropriate types to m_AllTypes // (The order guarantees that the proper types override) for (i = 0; i < BindOrder.GetCount(); i++) { CExtension *pExtension = BindOrder[i]; try { const CDesignTable &Types = pExtension->GetDesignTypes(); #ifdef DEBUG_BIND ::OutputDebugString(strPatternSubst(CONSTLIT("EXTENSION %s\n"), pExtension->GetName())); for (int j = 0; j < Types.GetCount(); j++) { ::OutputDebugString(strPatternSubst(CONSTLIT("%08x: %s\n"), Types.GetEntry(j)->GetUNID(), Types.GetEntry(j)->GetTypeName())); } #endif // Run globals for the extension if (error = pExtension->ExecuteGlobals(Ctx)) { *retsError = Ctx.sError; return error; } // Add the types m_AllTypes.Merge(Types, &m_OverrideTypes); // If this is the adventure, then remember it if (pExtension->GetType() == extAdventure) { m_pAdventureExtension = pExtension; m_pAdventureDesc = pExtension->GetAdventureDesc(); } // If this is an adventure or the base extension then take the // topology. if (pExtension->GetType() == extAdventure || pExtension->GetType() == extBase) m_pTopology = &pExtension->GetTopology(); } catch (...) { ::kernelDebugLogMessage("Crash processing extension:"); CExtension::DebugDump(pExtension, true); throw; } } // If this is a new game, then create all the Template types if (bNewGame) { DEBUG_TRY m_DynamicUNIDs.DeleteAll(); m_DynamicTypes.DeleteAll(); if (error = FireOnGlobalTypesInit(Ctx)) { *retsError = Ctx.sError; return error; } if (error = CreateTemplateTypes(Ctx)) { *retsError = Ctx.sError; return error; } DEBUG_CATCH_MSG("Crash defining dynamic types."); } // Add all the dynamic types. These came either from the saved game file or // from the Template types above. m_AllTypes.Merge(m_DynamicTypes, &m_OverrideTypes); // Now resolve all overrides and inheritance if (error = ResolveOverrides(Ctx)) { *retsError = Ctx.sError; return error; } // Initialize the byType lists DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); m_ByType[pEntry->GetType()].AddEntry(pEntry); } DEBUG_CATCH_MSG("Crash initializing byType lists."); // Set our adventure desc as current; since adventure descs are always // loaded this is the only thing that we can use to tell if we should // call global events. // // This must happen after Unbind (because that clears it) and before // PrepareBindDesign. // // NOTE: m_pAdventureDesc can be NULL (e.g., in the intro screen). DEBUG_TRY if (m_pAdventureDesc) m_pAdventureDesc->SetCurrentAdventure(); DEBUG_CATCH_MSG("Crash setting current adventure."); // Cache a map between currency name and economy type // We need to do this before Bind because some types will lookup // a currency name during Bind. DEBUG_TRY m_EconomyIndex.DeleteAll(); for (i = 0; i < GetCount(designEconomyType); i++) { CEconomyType *pEcon = CEconomyType::AsType(GetEntry(designEconomyType, i)); const CString &sName = pEcon->GetSID(); bool bUnique; CEconomyType **ppDest = m_EconomyIndex.SetAt(sName, &bUnique); if (!bUnique) { pEcon->ComposeLoadError(Ctx, CONSTLIT("Currency ID must be unique")); *retsError = Ctx.sError; return ERR_FAIL; } *ppDest = pEcon; } DEBUG_CATCH_MSG("Crash initializing economies."); // Prepare to bind. This is used by design elements that need two passes // to bind. We also use it to set up the inheritence hierarchy, which means // that we rely on the map from UNID to valid design type (m_AllTypes) m_DisplayAttribs.DeleteAll(); DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->PrepareBindDesign(Ctx)) { *retsError = Ctx.sError; return error; } // We take this opportunity to build a list of display attributes // defined by each type. const CDisplayAttributeDefinitions &Attribs = pEntry->GetDisplayAttributes(); if (!Attribs.IsEmpty()) m_DisplayAttribs.Append(Attribs); } DEBUG_CATCH_MSG("Crash in PrepareBind."); // Now call Bind on all active design entries for (i = 0; i < evtCount; i++) m_EventsCache[i]->DeleteAll(); DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->BindDesign(Ctx)) { *retsError = Ctx.sError; return error; } // Cache some global events. We keep track of the global events for // all types so that we can access them faster. CacheGlobalEvents(pEntry); } DEBUG_CATCH_MSG("Crash in BindDesign."); // Finish binding. This pass is used by design elements // that need to do stuff after all designs are bound. DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->FinishBindDesign(Ctx)) { *retsError = Ctx.sError; return error; } } DEBUG_CATCH_MSG("Crash in FinishBind."); // Remember what we bound m_BoundExtensions = BindOrder; return NOERROR; DEBUG_CATCH }