ALERROR GetEconomyUNIDOrDefault (CCodeChain &CC, ICCItem *pItem, DWORD *retdwUNID) { if (pItem == NULL || pItem->IsNil()) { if (retdwUNID) *retdwUNID = 0; } else if (pItem->IsInteger()) { CDesignType *pType = g_pUniverse->FindDesignType(pItem->GetIntegerValue()); if (pType == NULL) return ERR_FAIL; if (retdwUNID) *retdwUNID = pType->GetUNID(); } else { CEconomyType *pEconomy = g_pUniverse->FindEconomyType(pItem->GetStringValue()); if (pEconomy == NULL) return ERR_FAIL; if (retdwUNID) *retdwUNID = pEconomy->GetUNID(); } return NOERROR; }
CurrencyValue CCurrencyBlock::IncCredits (const CString &sCurrency, CurrencyValue iInc) // IncCredits // // Increments/decrements credits { ASSERT(!sCurrency.IsBlank()); CEconomyType *pEcon = g_pUniverse->FindEconomyType(sCurrency); if (pEcon == NULL) return 0; return IncCredits(pEcon->GetUNID(), iInc); }
CurrencyValue CCurrencyBlock::GetCredits (const CString &sCurrency) // GetCredits // // Returns the number of credits available in the given currency { ASSERT(!sCurrency.IsBlank()); CEconomyType *pEcon = g_pUniverse->FindEconomyType(sCurrency); if (pEcon == NULL) return 0; return GetCredits(pEcon->GetUNID()); }
void CCurrencyBlock::SetCredits (const CString &sCurrency, CurrencyValue iValue) // SetCredits // // Sets the credit value for the given currency { ASSERT(!sCurrency.IsBlank()); CEconomyType *pEcon = g_pUniverse->FindEconomyType(sCurrency); if (pEcon == NULL) return; SetCredits(pEcon->GetUNID(), iValue); }
void CompileTradeData (CSpaceObject *pObj, SStationData *retAllStations, SItemData *retAllItems) { int i; CDesignType *pType = pObj->GetType(); CStationType *pStationType = CStationType::AsType(pType); if (pStationType == NULL || pStationType->GetTradingDesc() == NULL) return; // All prices in default currency (credits) CEconomyType *pCurrency = CEconomyType::AsType(g_pUniverse->FindDesignType(DEFAULT_ECONOMY_UNID)); // Get the entry bool bNew; SStationTypeInfo *pStationInfo = retAllStations->SetAt(pStationType, &bNew); if (bNew) pStationInfo->pType = pStationType; // Loop over all item types and see if that station buys or sells. for (i = 0; i < g_pUniverse->GetItemTypeCount(); i++) { CItemType *pItemType = g_pUniverse->GetItemType(i); CItem AnItem(pItemType, 1); SItemTypeInfo *pItemInfo = NULL; // See if the stations buys this int iBuyPrice = (int)pCurrency->Exchange(pObj->GetDefaultEconomy(), pObj->GetBuyPrice(AnItem, CTradingDesc::FLAG_NO_DONATION)); if (iBuyPrice > 0) { // Add an entry for the station type recording that we buy this // item type at the given price. SItemTradeInfo *pItemEntry = pStationInfo->Buys.SetAt(pItemType, &bNew); if (bNew) pItemEntry->pItem = pItemType; pItemEntry->Records.Insert(iBuyPrice); // Add an entry for the item type recording that this station type // buys the given item. pItemInfo = retAllItems->SetAt(pItemType, &bNew); if (bNew) pItemInfo->pItem = pItemType; SStationTradeInfo *pStationEntry = pItemInfo->BoughtBy.SetAt(pStationType, &bNew); if (bNew) pStationEntry->pStation = pStationType; pStationEntry->Records.Insert(iBuyPrice); } // See if the station sells this int iSellPrice = (int)pCurrency->Exchange(pObj->GetDefaultEconomy(), pObj->GetSellPrice(AnItem, 0)); if (iSellPrice > 0) { // Add an entry for the station type recording that we sell this // item type at the given price. SItemTradeInfo *pItemEntry = pStationInfo->Sells.SetAt(pItemType, &bNew); if (bNew) pItemEntry->pItem = pItemType; pItemEntry->Records.Insert(iSellPrice); // Add an entry for the item type recording that this station type // buys the given item. if (pItemInfo == NULL) { pItemInfo = retAllItems->SetAt(pItemType, &bNew); if (bNew) pItemInfo->pItem = pItemType; } SStationTradeInfo *pStationEntry = pItemInfo->SoldAt.SetAt(pStationType, &bNew); if (bNew) pStationEntry->pStation = pStationType; pStationEntry->Records.Insert(iSellPrice); } } }
ALERROR CDesignCollection::BindDesign (SDesignLoadCtx &Ctx) // BindDesign // // Bind the design collection so that design types point the appropriate // pointers by UNID { ALERROR error; int i, j; // Unbind everything for (i = 0; i < m_AllTypes.GetCount(); i++) m_AllTypes.GetEntry(i)->UnbindDesign(); m_AllTypes.DeleteAll(); // Reset the bind tables for (i = 0; i < designCount; i++) m_ByType[i].DeleteAll(); // We start with all the base types for (i = 0; i < m_Base.GetCount(); i++) m_AllTypes.AddEntry(m_Base.GetEntry(i)); // Start with base topology m_pTopology = &m_BaseTopology; m_pAdventureExtension = NULL; // Now add all enabled extensions for (i = 0; i < GetExtensionCount(); i++) { SExtensionDesc *pExtension = GetExtension(i); if (pExtension->bEnabled) { // Add design elements in extension for (j = 0; j < pExtension->Table.GetCount(); j++) { CDesignType *pEntry = pExtension->Table.GetEntry(j); m_AllTypes.AddOrReplaceEntry(pEntry); } // Handle adventure extensions if (pExtension->iType == extAdventure) { // Keep track of extension m_pAdventureExtension = pExtension; // Add topology m_pTopology = &pExtension->Topology; } } else { if (pExtension->iType == extAdventure) { DWORD dwCoverImage = 0; // Adventure desc elements are added even if not enabled for (j = 0; j < pExtension->Table.GetCount(); j++) { CDesignType *pEntry = pExtension->Table.GetEntry(j); if (pEntry->GetType() == designAdventureDesc) { m_AllTypes.AddOrReplaceEntry(pEntry); // Get the cover image used by the adventure, because // we need to load that too. CAdventureDesc *pDesc = CAdventureDesc::AsType(pEntry); dwCoverImage = pDesc->GetBackgroundUNID(); } } // Make sure we load the cover image if (dwCoverImage) { for (j = 0; j < pExtension->Table.GetCount(); j++) { CDesignType *pEntry = pExtension->Table.GetEntry(j); if (pEntry->GetUNID() == dwCoverImage) m_AllTypes.AddOrReplaceEntry(pEntry); } } } } } // If this is a new game, then create all the Template types if (Ctx.bNewGame) { m_DynamicUNIDs.DeleteAll(); m_DynamicTypes.DeleteAll(); if (error = FireOnGlobalTypesInit(Ctx)) return error; if (error = CreateTemplateTypes(Ctx)) return error; } // Add all the dynamic types. These came either from the saved game file or // from the Template types above. for (i = 0; i < m_DynamicTypes.GetCount(); i++) m_AllTypes.AddOrReplaceEntry(m_DynamicTypes.GetType(i)); // Initialize the byType lists for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); m_ByType[pEntry->GetType()].AddEntry(pEntry); } // 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). if (m_pAdventureDesc) m_pAdventureDesc->SetCurrentAdventure(); // 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. 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) return pEcon->ComposeLoadError(Ctx, CONSTLIT("Currency ID must be unique")); *ppDest = pEcon; } // Prepare to bind. This is used by design elements // that need two passes to bind. for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->PrepareBindDesign(Ctx)) return error; } // Now call Bind on all active design entries for (i = 0; i < evtCount; i++) m_EventsCache[i]->DeleteAll(); for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->BindDesign(Ctx)) 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); } // Finish binding. This pass is used by design elements // that need to do stuff after all designs are bound. for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->FinishBindDesign(Ctx)) return error; } return NOERROR; }
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 }