ALERROR CDesignCollection::AddDynamicType (SExtensionDesc *pExtension, DWORD dwUNID, const CString &sSource, bool bNewGame, CString *retsError) // AddDynamicType // // Adds a dynamic type at runtime { ALERROR error; // If we're pass game-create, the UNID must not already exist if (!bNewGame && FindEntry(dwUNID)) { if (retsError) *retsError = strPatternSubst(CONSTLIT("Type already exists: %x"), dwUNID); return ERR_FAIL; } // Add it to the dynamics table CDesignType *pType; if (error = m_DynamicTypes.DefineType(pExtension, dwUNID, sSource, &pType, retsError)) return error; // Make sure that the type can be created at this point. // For example, we can't create SystemMap types after the game has started. switch (pType->GetType()) { case designAdventureDesc: case designGlobals: case designImage: case designSound: case designEconomyType: case designTemplateType: { m_DynamicTypes.Delete(dwUNID); if (retsError) *retsError = CONSTLIT("Dynamic design type not supported."); return ERR_FAIL; } case designSystemType: case designSystemTable: case designSystemMap: { if (!bNewGame) { m_DynamicTypes.Delete(dwUNID); if (retsError) *retsError = CONSTLIT("Dynamic design type not supported after new game created."); return ERR_FAIL; } } } // Since we've already bound, we need to simulate that here (although we // [obviously] don't allow existing types to bind to dynamic types). // // We start by adding the type to the AllTypes list m_AllTypes.AddOrReplaceEntry(pType); // If this is new game time, then it means that we are inside of BindDesign. In // that case, we don't do anything more (since BindDesign will take care of // it). if (!bNewGame) { // Next we add it to the specific type tables m_ByType[pType->GetType()].AddEntry(pType); // Bind SDesignLoadCtx Ctx; Ctx.pExtension = pExtension; Ctx.bNewGame = bNewGame; if (error = pType->PrepareBindDesign(Ctx)) { m_AllTypes.Delete(dwUNID); m_ByType[pType->GetType()].Delete(dwUNID); m_DynamicTypes.Delete(dwUNID); if (retsError) *retsError = Ctx.sError; return error; } if (error = pType->BindDesign(Ctx)) { m_AllTypes.Delete(dwUNID); m_ByType[pType->GetType()].Delete(dwUNID); m_DynamicTypes.Delete(dwUNID); if (retsError) *retsError = Ctx.sError; return error; } // Cache some global events CacheGlobalEvents(pType); // Done binding if (error = pType->FinishBindDesign(Ctx)) { m_AllTypes.Delete(dwUNID); m_ByType[pType->GetType()].Delete(dwUNID); m_DynamicTypes.Delete(dwUNID); if (retsError) *retsError = Ctx.sError; return error; } } return NOERROR; }
ALERROR CDesignCollection::CreateTemplateTypes (SDesignLoadCtx &Ctx) // CreateTemplateTypes // // This is called inside of BindDesign to create all template types { ALERROR error; int i; // Create an appropriate context for running code CCodeChainCtx CCCtx; // Loop over all active types looking for templates. // NOTE: We cannot use the type-specific arrays because they have not been // set up yet (remember that we are inside of BindDesign). for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pTemplate = m_AllTypes.GetEntry(i); if (pTemplate->GetType() != designTemplateType) continue; // Get the function to generate the type source CString sSource; SEventHandlerDesc Event; if (pTemplate->FindEventHandler(GET_TYPE_SOURCE_EVENT, &Event)) { ICCItem *pResult = CCCtx.Run(Event); if (pResult->IsError()) { Ctx.sError = strPatternSubst(CONSTLIT("GetTypeSource (%x): %s"), pTemplate->GetUNID(), pResult->GetStringValue()); return ERR_FAIL; } else if (pResult->IsNil()) sSource = NULL_STR; else sSource = pResult->GetStringValue(); CCCtx.Discard(pResult); } // Define the type if (!sSource.IsBlank()) { if (error = AddDynamicType(pTemplate->GetExtension(), pTemplate->GetUNID(), sSource, true, &Ctx.sError)) return error; } } return NOERROR; }
bool CSpaceObject::GetArmorRepairPrice (const CItem &Item, int iHPToRepair, DWORD dwFlags, int *retiPrice) // GetArmorRepairPrice // // Returns the price to repair the given number of HP for the given armor item. { if (IsAbandoned()) return false; // See if we have an override CTradingDesc *pTradeOverride = GetTradeDescOverride(); if (pTradeOverride && pTradeOverride->GetArmorRepairPrice(this, Item, iHPToRepair, dwFlags, retiPrice)) return true; // Otherwise, ask our design type CDesignType *pType = GetType(); if (pType == NULL) return false; CTradingDesc *pTrade = pType->GetTradingDesc(); if (pTrade && pTrade->GetArmorRepairPrice(this, Item, iHPToRepair, dwFlags, retiPrice)) return true; // For compatibility, any ship prior to version 23 has a default. // [For API Version 23 and above, ships must have a <Trade> descriptor.] if (pType->GetAPIVersion() < 23 && pType->GetType() == designShipClass) { if (retiPrice) *retiPrice = CTradingDesc::CalcPriceForService(serviceRepairArmor, this, Item, iHPToRepair, dwFlags); return true; } // Otherwise, we do not repair return false; }
CAdventureDesc *CDesignCollection::FindAdventureForExtension (DWORD dwUNID) const // FindAdventureForExtension // // Returns the adventure desc that belongs to the given extension. // (Or NULL if not found). { int i; SExtensionDesc *pExtension = FindExtension(dwUNID); if (pExtension == NULL || pExtension->iType != extAdventure) return NULL; for (i = 0; i < pExtension->Table.GetCount(); i++) { CDesignType *pType = pExtension->Table.GetEntry(i); if (pType->GetType() == designAdventureDesc) return CAdventureDesc::AsType(pType); } return NULL; }
void OutputByShipClass (SItemTableCtx &Ctx, const SItemTypeList &ItemList, bool bShowUsage) { int i, j; // Make a map of ship classes for each item TSortMap<DWORD, TArray<CShipClass *>> ItemToShipClass; for (i = 0; i < g_pUniverse->GetShipClassCount(); i++) { CShipClass *pClass = g_pUniverse->GetShipClass(i); // Skip non-generic ones if (!pClass->HasLiteralAttribute(CONSTLIT("genericClass"))) continue; // Add the list of types used by the ship TSortMap<DWORD, bool> TypesUsed; pClass->AddTypesUsed(&TypesUsed); // For each item type, add it to the map for (j = 0; j < TypesUsed.GetCount(); j++) { CDesignType *pType = g_pUniverse->FindDesignType(TypesUsed.GetKey(j)); if (pType && pType->GetType() == designItemType) { TArray<CShipClass *> *pList = ItemToShipClass.SetAt(pType->GetUNID()); pList->Insert(pClass); } } } // If we want to show usage, then we print each item along with the // ship classes using each item. if (bShowUsage) { for (i = 0; i < ItemList.GetCount(); i++) { CItemType *pType = ItemList[i]; printf("%s\n", (LPSTR)pType->GetNounPhrase()); TArray<CShipClass *> *pList = ItemToShipClass.SetAt(pType->GetUNID()); for (j = 0; j < pList->GetCount(); j++) printf("\t%s\n", (LPSTR)pList->GetAt(j)->GetName()); if (pList->GetCount() == 0) printf("\t(none)\n"); printf("\n"); } } // Otherwise we categorize by ship class else { // Now make a list of all ship classes that have our items SByShipClassTypeList ByShipClassTable; for (i = 0; i < ItemList.GetCount(); i++) { const CString &sKey = ItemList.GetKey(i); CItemType *pType = ItemList[i]; // Loop over all ship classes TArray<CShipClass *> *pList = ItemToShipClass.SetAt(pType->GetUNID()); for (j = 0; j < pList->GetCount(); j++) { CString sClassName = pList->GetAt(j)->GetName(); bool bNew; SShipClassEntry *pEntry = ByShipClassTable.SetAt(sClassName, &bNew); if (bNew) pEntry->sShipClassName = sClassName; pEntry->ItemTable.Insert(sKey, pType); } // If no ship class if (pList->GetCount() == 0) { bool bNew; SShipClassEntry *pEntry = ByShipClassTable.SetAt(CONSTLIT("(none)"), &bNew); if (bNew) pEntry->sShipClassName = CONSTLIT("(none)"); pEntry->ItemTable.Insert(sKey, pType); } } // Now loop over all attributes for (i = 0; i < ByShipClassTable.GetCount(); i++) { const SShipClassEntry &Entry = ByShipClassTable[i]; printf("%s\n\n", Entry.sShipClassName.GetASCIIZPointer()); OutputHeader(Ctx); OutputTable(Ctx, Entry.ItemTable); printf("\n"); } } }
CWeaponFireDesc *CWeaponFireDesc::FindWeaponFireDescFromFullUNID (const CString &sUNID) // FindWeaponFireDesc // // Finds the descriptor by name { char *pPos = sUNID.GetPointer(); // Get the UNID of the type DWORD dwUNID = (DWORD)strParseInt(pPos, 0, &pPos); if (dwUNID == 0) return NULL; // Get the type CDesignType *pType = g_pUniverse->FindDesignType(dwUNID); if (pType == NULL) return NULL; // If this is an item, then it must be a weapon if (pType->GetType() == designItemType) { CItemType *pItemType = CItemType::AsType(pType); ASSERT(pItemType); CDeviceClass *pDevice = pItemType->GetDeviceClass(); if (pDevice == NULL) return NULL; CWeaponClass *pClass = pDevice->AsWeaponClass(); if (pClass == NULL) return NULL; // Get the ordinal ASSERT(*pPos == '/'); pPos++; int iOrdinal = strParseInt(pPos, 0, &pPos); // Get the weapon fire desc of the ordinal CWeaponFireDesc *pDesc = pClass->GetVariant(iOrdinal); if (pDesc == NULL) return NULL; // Continue parsing return pDesc->FindWeaponFireDesc(CString(pPos)); } // If this is an effect, then get it from that else if (pType->GetType() == designEffectType) { CEffectCreator *pEffectType = CEffectCreator::AsType(pType); ASSERT(pEffectType); // Expect /d ASSERT(*pPos == '/'); pPos++; ASSERT(*pPos == 'd'); pPos++; CWeaponFireDesc *pDesc = pEffectType->GetDamageDesc(); if (pDesc == NULL) return NULL; // Continue parsing return pDesc->FindWeaponFireDesc(CString(pPos)); } // Otherwise, we don't know else return NULL; }
void GenerateImageChart (CUniverse &Universe, CXMLElement *pCmdLine) { int i; enum OrderTypes { orderSmallest = 1, orderLargest = 2, orderName = 3, orderLevel = 4, orderSovereign = 5, orderManufacturer = 6, }; // Item criteria bool bHasItemCriteria; CString sCriteria; CItemCriteria ItemCriteria; if (bHasItemCriteria = pCmdLine->FindAttribute(CONSTLIT("itemCriteria"), &sCriteria)) CItem::ParseCriteria(sCriteria, &ItemCriteria); else CItem::InitCriteriaAll(&ItemCriteria); // Get the criteria from the command line. CDesignTypeCriteria Criteria; if (pCmdLine->FindAttribute(CONSTLIT("criteria"), &sCriteria)) { if (CDesignTypeCriteria::ParseCriteria(sCriteria, &Criteria) != NOERROR) { printf("ERROR: Unable to parse criteria.\n"); return; } } else if (bHasItemCriteria) { if (CDesignTypeCriteria::ParseCriteria(CONSTLIT("i"), &Criteria) != NOERROR) { printf("ERROR: Unable to parse criteria.\n"); return; } } else { printf("ERROR: Expected criteria.\n"); return; } bool bAll = pCmdLine->GetAttributeBool(CONSTLIT("all")); // Options bool bTextBoxesOnly = pCmdLine->GetAttributeBool(CONSTLIT("textBoxesOnly")); bool bFieldUNID = pCmdLine->GetAttributeBool(CONSTLIT("unid")); // Figure out what order we want CString sOrder = pCmdLine->GetAttribute(CONSTLIT("sort")); int iOrder; if (strEquals(sOrder, CONSTLIT("smallest"))) iOrder = orderSmallest; else if (strEquals(sOrder, CONSTLIT("largest"))) iOrder = orderLargest; else if (strEquals(sOrder, CONSTLIT("level"))) iOrder = orderLevel; else if (strEquals(sOrder, CONSTLIT("sovereign"))) iOrder = orderSovereign; else if (strEquals(sOrder, CONSTLIT("manufacturer"))) iOrder = orderManufacturer; else iOrder = orderName; bool b3DGrid = pCmdLine->GetAttributeBool(CONSTLIT("3DGrid")); bool bDockingPorts = pCmdLine->GetAttributeBool(CONSTLIT("portPos")); bool bDevicePos = pCmdLine->GetAttributeBool(CONSTLIT("devicePos")); // Image size int cxDesiredWidth; if (pCmdLine->FindAttributeInteger(CONSTLIT("width"), &cxDesiredWidth)) cxDesiredWidth = Max(512, cxDesiredWidth); else cxDesiredWidth = 1280; // Spacing int cxSpacing = pCmdLine->GetAttributeInteger(CONSTLIT("xSpacing")); int cxExtraMargin = pCmdLine->GetAttributeInteger(CONSTLIT("xMargin")); int cxImageMargin = 2 * pCmdLine->GetAttributeInteger(CONSTLIT("xImageMargin")); // Font for text CString sTypeface; int iSize; bool bBold; bool bItalic; if (!CG16bitFont::ParseFontDesc(pCmdLine->GetAttribute(CONSTLIT("font")), &sTypeface, &iSize, &bBold, &bItalic)) { sTypeface = CONSTLIT("Arial"); iSize = 10; bBold = false; bItalic = false; } CG16bitFont NameFont; NameFont.Create(sTypeface, -PointsToPixels(iSize), bBold, bItalic); CG32bitPixel rgbNameColor = CG32bitPixel(255, 255, 255); // Rotation int iRotation = pCmdLine->GetAttributeInteger(CONSTLIT("rotation")); // Output file CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("output")); if (!sFilespec.IsBlank()) sFilespec = pathAddExtensionIfNecessary(sFilespec, CONSTLIT(".bmp")); // Generate a sorted table of types TSortMap<CString, SEntryDesc> Table; for (i = 0; i < Universe.GetDesignTypeCount(); i++) { CDesignType *pType = Universe.GetDesignType(i); SEntryDesc NewEntry; // Make sure we match the criteria if (!pType->MatchesCriteria(Criteria)) continue; // Figure stuff stuff out based on the specific design type switch (pType->GetType()) { case designItemType: { CItemType *pItemType = CItemType::AsType(pType); CItem Item(pItemType, 1); // Skip if not in item criteria if (!Item.MatchesCriteria(ItemCriteria)) continue; // Skip virtual classes if (pItemType->IsVirtual()) continue; // Initialize the entry NewEntry.pType = pType; NewEntry.sName = pItemType->GetNounPhrase(0); NewEntry.pImage = &pItemType->GetImage(); NewEntry.iSize = RectWidth(NewEntry.pImage->GetImageRect()); break; } case designShipClass: { CShipClass *pClass = CShipClass::AsType(pType); // Skip non-generic classess if (!bAll && !pClass->HasLiteralAttribute(CONSTLIT("genericClass"))) continue; // Initialize the entry NewEntry.pType = pType; NewEntry.sName = pClass->GetNounPhrase(0); NewEntry.iSize = RectWidth(pClass->GetImage().GetImageRect()); NewEntry.pImage = &pClass->GetImage(); NewEntry.iRotation = pClass->Angle2Direction(iRotation); NewEntry.sSovereignName = (pClass->GetDefaultSovereign() ? pClass->GetDefaultSovereign()->GetTypeNounPhrase() : NULL_STR); break; } case designStationType: { CStationType *pStationType = CStationType::AsType(pType); // Skip generic classes if (!bAll && !pStationType->HasLiteralAttribute(CONSTLIT("generic"))) continue; NewEntry.pType = pType; NewEntry.sName = pStationType->GetNounPhrase(0); NewEntry.iSize = pStationType->GetSize(); NewEntry.sSovereignName = (pStationType->GetSovereign() ? pStationType->GetSovereign()->GetTypeNounPhrase() : NULL_STR); InitStationTypeImage(NewEntry, pStationType); break; } default: // Don't know how to handle this type continue; break; } // Adjust name if (bFieldUNID) NewEntry.sName = strPatternSubst(CONSTLIT("%s (%x)"), NewEntry.sName, NewEntry.pType->GetUNID()); // Compute the sort key char szBuffer[1024]; switch (iOrder) { case orderLargest: wsprintf(szBuffer, "%09d%s%x", 1000000 - NewEntry.iSize, NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderLevel: wsprintf(szBuffer, "%09d%s%x", pType->GetLevel(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderSmallest: wsprintf(szBuffer, "%09d%s%x", NewEntry.iSize, NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderSovereign: wsprintf(szBuffer, "%s|%s|%x", NewEntry.sSovereignName.GetASCIIZPointer(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); NewEntry.sCategorize = NewEntry.sSovereignName; break; case orderManufacturer: { CString sManufacturer = NewEntry.pType->GetPropertyString(CONSTLIT("manufacturer")); wsprintf(szBuffer, "%s|%s|%x", sManufacturer.GetASCIIZPointer(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); NewEntry.sCategorize = sManufacturer; break; } default: wsprintf(szBuffer, "%s%x", NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; } // Add to list Table.Insert(CString(szBuffer), NewEntry); } // Allocate an arranger that tracks where to paint each world. CImageArranger Arranger; // Settings for the overall arrangement CImageArranger::SArrangeDesc Desc; Desc.cxDesiredWidth = Max(512, cxDesiredWidth - (2 * (cxSpacing + cxExtraMargin))); Desc.cxSpacing = cxSpacing; Desc.cxExtraMargin = cxExtraMargin; Desc.pHeader = &NameFont; // Generate a table of cells for the arranger TArray<CCompositeImageSelector> Selectors; Selectors.InsertEmpty(Table.GetCount()); CString sLastCategory; TArray<CImageArranger::SCellDesc> Cells; for (i = 0; i < Table.GetCount(); i++) { SEntryDesc &Entry = Table[i]; CImageArranger::SCellDesc *pNewCell = Cells.Insert(); pNewCell->cxWidth = (Entry.pImage ? RectWidth(Entry.pImage->GetImageRect()) : 0) + cxImageMargin; pNewCell->cyHeight = (Entry.pImage ? RectHeight(Entry.pImage->GetImageRect()) : 0) + cxImageMargin; pNewCell->sText = Entry.sName; if (!strEquals(sLastCategory, Entry.sCategorize)) { sLastCategory = Entry.sCategorize; pNewCell->bStartNewRow = true; } } // Arrange Arranger.ArrangeByRow(Desc, Cells); // Create a large image CG32bitImage Output; int cxWidth = Max(cxDesiredWidth, Arranger.GetWidth()); int cyHeight = Arranger.GetHeight(); Output.Create(cxWidth, cyHeight); printf("Creating %dx%d image.\n", cxWidth, cyHeight); // Paint the images for (i = 0; i < Table.GetCount(); i++) { SEntryDesc &Entry = Table[i]; int x = Arranger.GetX(i); int y = Arranger.GetY(i); // Paint if (x != -1) { int xCenter = x + (Arranger.GetWidth(i) / 2); int yCenter = y + (Arranger.GetHeight(i) / 2); int xOffset; int yOffset; Entry.pImage->GetImageOffset(0, Entry.iRotation, &xOffset, &yOffset); int cxImage = RectWidth(Entry.pImage->GetImageRect()); int cyImage = RectHeight(Entry.pImage->GetImageRect()); // Paint image if (!bTextBoxesOnly && Entry.pImage) { Entry.pImage->PaintImageUL(Output, x + (Arranger.GetWidth(i) - cxImage) / 2, y + (Arranger.GetHeight(i) - cyImage) / 2, 0, Entry.iRotation); } // Paint type specific stuff switch (Entry.pType->GetType()) { case designStationType: { CStationType *pStationType = CStationType::AsType(Entry.pType); int xStationCenter = xCenter - xOffset; int yStationCenter = yCenter - yOffset; if (bDockingPorts) pStationType->PaintDockPortPositions(Output, xStationCenter, yStationCenter); if (bDevicePos) pStationType->PaintDevicePositions(Output, xStationCenter, yStationCenter); // If we have docking or device positions, mark the center of the station if (bDockingPorts || bDevicePos) { const int LINE_HALF_LENGTH = 24; const CG32bitPixel RGB_CENTER_CROSS(255, 255, 0); Output.DrawLine(xStationCenter - LINE_HALF_LENGTH, yStationCenter, xStationCenter + LINE_HALF_LENGTH, yStationCenter, 1, RGB_CENTER_CROSS); Output.DrawLine(xStationCenter, yStationCenter - LINE_HALF_LENGTH, xStationCenter, yStationCenter + LINE_HALF_LENGTH, 1, RGB_CENTER_CROSS); } break; } } // Paint the 3D grid, if necessary if (b3DGrid) { int iScale = Entry.pImage->GetImageViewportSize(); Metric rMaxRadius = g_KlicksPerPixel * cxImage * 0.5; const Metric rGridSize = LIGHT_SECOND; Metric rRadius; for (rRadius = rGridSize; rRadius <= rMaxRadius; rRadius += rGridSize) { int iRadius = (int)((rRadius / g_KlicksPerPixel) + 0.5); const int iGridAngle = 8; int iPrevAngle = 0; int iAngle; for (iAngle = iGridAngle; iAngle <= 360; iAngle += iGridAngle) { int xFrom, yFrom; C3DConversion::CalcCoord(iScale, iPrevAngle, iRadius, 0, &xFrom, &yFrom); int xTo, yTo; C3DConversion::CalcCoord(iScale, iAngle, iRadius, 0, &xTo, &yTo); Output.DrawLine(xFrom + xCenter, yFrom + yCenter, xTo + xCenter, yTo + yCenter, 1, CG32bitPixel(255, 255, 0)); iPrevAngle = iAngle; } } } // Paint name int xText = Arranger.GetTextX(i); int yText = Arranger.GetTextY(i); if (xText != -1) { if (bTextBoxesOnly) Output.Fill(xText, yText, Arranger.GetTextWidth(i), Arranger.GetTextHeight(i), 0xffff); if (!bTextBoxesOnly) { Output.FillColumn(xCenter, y + Arranger.GetHeight(i), yText - (y + Arranger.GetHeight(i)), rgbNameColor); NameFont.DrawText(Output, xText, yText, rgbNameColor, Entry.sName); } } } } // Write to file or clipboard OutputImage(Output, sFilespec); }
void GenerateTypeIslands (CUniverse &Universe, CXMLElement *pCmdLine) { int i, j; bool bExcludeImages = true; printf("TYPE ISLANDS\n"); printf("------------\n\n"); // Make a list of default types #if 0 g_DefaultTypes.SetAt(0x00001001, true); // independent sovereign g_DefaultTypes.SetAt(0x00001002, true); // Commonwealth sovereign g_DefaultTypes.SetAt(0x00001003, true); // independent sovereign g_DefaultTypes.SetAt(0x00001007, true); // ares sovereign g_DefaultTypes.SetAt(0x0000100c, true); // sung slavers sovereign g_DefaultTypes.SetAt(0x0000100f, true); // auton sovereign g_DefaultTypes.SetAt(0x00001011, true); // corporate hierarchy g_DefaultTypes.SetAt(0x00004027, true); // container of frozen supplies g_DefaultTypes.SetAt(0x0000402c, true); // pteracnium ore g_DefaultTypes.SetAt(0x000040ae, true); // helium3 reactor assembly g_DefaultTypes.SetAt(0x000040af, true); // pteracnium fuel g_DefaultTypes.SetAt(0x000040ca, true); // lancer cannon g_DefaultTypes.SetAt(0x000040e2, true); // worldship armor g_DefaultTypes.SetAt(0x00004100, true); // xenotite ore g_DefaultTypes.SetAt(0x00004109, true); // SN2500 reactor g_DefaultTypes.SetAt(0x00004167, true); // tetramite ore g_DefaultTypes.SetAt(0x00005004, true); // wreck ejecta g_DefaultTypes.SetAt(0x0000500c, true); // blast explosion 2 g_DefaultTypes.SetAt(0x0000500d, true); // blast explosion 3 g_DefaultTypes.SetAt(0x0000500e, true); // blast explosion 4 g_DefaultTypes.SetAt(0x0000500f, true); // thermo explosion 1 g_DefaultTypes.SetAt(0x00005011, true); // thermo explosion 3 g_DefaultTypes.SetAt(0x00005012, true); // thermo explosion 4 g_DefaultTypes.SetAt(0x00009004, true); // shield effect g_DefaultTypes.SetAt(0x00009007, true); // explosion effect g_DefaultTypes.SetAt(0x0000900a, true); // fire effect g_DefaultTypes.SetAt(0x0000A003, true); // dsAbandonedStation g_DefaultTypes.SetAt(0x0000a017, true); // dock screen? g_DefaultTypes.SetAt(0x001a200c, true); // wreck of the CSC Europa g_DefaultTypes.SetAt(0x001a200e, true); // sandstorm wreck g_DefaultTypes.SetAt(0x001c1002, true); // ares sect in Heretic g_DefaultTypes.SetAt(0x08020102, true); // huari empire sovereign g_DefaultTypes.SetAt(0x08040140, true); // gaian processor station #endif // Create a reverse index of all type dependencies ReverseIndexMap ReverseIndex; for (i = 0; i < Universe.GetDesignTypeCount(); i++) { CDesignType *pType = Universe.GetDesignType(i); // Get the list of UNIDs that this type uses TSortMap<DWORD, bool> TypesUsed; pType->AddTypesUsed(&TypesUsed); for (j = 0; j < TypesUsed.GetCount(); j++) { CDesignType *pRequired = Universe.FindDesignType(TypesUsed.GetKey(j)); if (pRequired == NULL) continue; // Add to reverse index TArray<DWORD> *pList = ReverseIndex.SetAt(pRequired->GetUNID()); pList->Insert(pType->GetUNID()); } } // We create a list of islands. In each island, all the types refer to // each other and don't refer to types on any other island. TArray<IslandMap> AllIslands; // Loop over all types and add them to an island. for (i = 0; i < Universe.GetDesignTypeCount(); i++) { CDesignType *pType = Universe.GetDesignType(i); // Exclude images if (bExcludeImages && pType->GetType() == designImage) continue; if (pType->GetType() == designShipTable) continue; // Exclude default types if (g_DefaultTypes.Find(pType->GetUNID())) continue; // If this type is already on one of the islands, then we skip it. #if 0 bool bFound = false; for (j = 0; j < AllIslands.GetCount(); j++) if (AllIslands[j].Find(pType->GetUNID())) { bFound = true; break; } if (bFound) continue; #endif // Since this type is not on any island, we add start a new island and // add all related types to it. IslandMap *pIsland = AllIslands.Insert(); AddTypeToIsland(Universe, ReverseIndex, pIsland, pType); // Print printf("ISLAND %s\n", (char *)GetTypeDesc(pType)); for (j = 0; j < pIsland->GetCount(); j++) { CDesignType *pType = Universe.FindDesignType(pIsland->GetKey(j)); if (pType == NULL) continue; printf("%s\n", (char *)GetTypeDesc(pType)); } printf("\n"); } }
int CSpaceObject::GetSellPrice (const CItem &Item, DWORD dwFlags) // GetSellPrice // // Returns the price at which the station will sell the given // item. Returns 0 if the station cannot or will not sell the // item. { bool bHasTradeDirective = false; int iPrice = -1; if (IsAbandoned()) return false; // See if we have an override price CTradingDesc *pTradeOverride = GetTradeDescOverride(); if (pTradeOverride) { pTradeOverride->Sells(this, Item, dwFlags, &iPrice); bHasTradeDirective = true; } // See if our type has a price CDesignType *pType = GetType(); if (iPrice == -1) { CTradingDesc *pTrade = (pType ? pType->GetTradingDesc() : NULL); if (pTrade) { pTrade->Sells(this, Item, dwFlags, &iPrice); bHasTradeDirective = true; } } // If we still have no price, then try to figure out a default. if (iPrice == -1) { // If we have Trade directives and they specify no price, then we can't // sell any. if (bHasTradeDirective) return 0; // For compatibility, any ship prior to version 23 has a default. // [For API Version 23 and above, ships must have a <Trade> descriptor.] else if (pType && pType->GetAPIVersion() < 23 && pType->GetType() == designShipClass) iPrice = CTradingDesc::CalcPriceForService(serviceSell, this, Item, 1, dwFlags); // Otherwise, get the price from the item itself else iPrice = (int)GetDefaultEconomy()->Exchange(Item.GetCurrencyType(), Item.GetTradePrice(this)); } // If we don't have any of the item, then we don't sell any if (!(dwFlags & CTradingDesc::FLAG_NO_INVENTORY_CHECK)) { CItemListManipulator ItemList(GetItemList()); if (!ItemList.SetCursorAtItem(Item)) return 0; } // Return the price return iPrice; }
bool CSpaceObject::GetRefuelItemAndPrice (CSpaceObject *pObjToRefuel, CItemType **retpItemType, int *retiPrice) // GetRefuelItemAndPrice // // Returns the appropriate item to use for refueling (based on the trading // directives). { int i; if (IsAbandoned()) return false; // See if we have an override CTradingDesc *pTradeOverride = GetTradeDescOverride(); if (pTradeOverride && pTradeOverride->GetRefuelItemAndPrice(this, pObjToRefuel, 0, retpItemType, retiPrice)) return true; // Otherwise, ask our design type CDesignType *pType = GetType(); if (pType == NULL) return false; CTradingDesc *pTrade = pType->GetTradingDesc(); if (pTrade && pTrade->GetRefuelItemAndPrice(this, pObjToRefuel, 0, retpItemType, retiPrice)) return true; // For compatibility, any ship prior to version 23 has a default. // [For API Version 23 and above, ships must have a <Trade> descriptor.] if (pType->GetAPIVersion() < 23 && pType->GetType() == designShipClass) { // Get the ship CShip *pShipToRefuel = pObjToRefuel->AsShip(); if (pShipToRefuel == NULL) return false; // Find the highest-level item that can be used by the ship int iBestLevel = 0; int iBestPrice = 0; CItemType *pBestItem = NULL; for (i = 0; i < g_pUniverse->GetItemTypeCount(); i++) { CItemType *pType = g_pUniverse->GetItemType(i); CItem Item(pType, 1); if (pShipToRefuel->IsFuelCompatible(Item)) { if (pBestItem == NULL || pType->GetLevel() > iBestPrice) { // Compute the price, because if we don't sell it, then we // skip it. // // NOTE: Unlike selling, we allow 0 prices because some // stations give fuel for free. int iPrice = CTradingDesc::CalcPriceForService(serviceRefuel, this, Item, 1, 0); if (iPrice >= 0) { pBestItem = pType; iBestLevel = pType->GetLevel(); iBestPrice = iPrice; } } } } if (pBestItem == NULL) return false; // Done if (retpItemType) *retpItemType = pBestItem; if (retiPrice) *retiPrice = iBestPrice; return true; } // Otherwise, we do not refuel return false; }
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 }
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; // Reset the bind tables m_AllTypes.RemoveAll(); for (i = 0; i < designCount; i++) m_ByType[i].RemoveAll(); // 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++) m_AllTypes.AddOrReplaceEntry(pExtension->Table.GetEntry(j)); // 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) { // 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); } } } } // Initialize the byType lists for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); m_ByType[pEntry->GetType()].AddEntry(pEntry); } // Now call Bind on all active design entries for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->BindDesign(Ctx)) return error; } // Check to make sure we have at least one topology node if (m_pTopology->GetRootNodeCount() == 0) { Ctx.sError = CONSTLIT("No topology nodes found"); return ERR_FAIL; } return NOERROR; }