void GenerateShipTable (CUniverse &Universe, CXMLElement *pCmdLine, CIDTable &EntityTable) { int i, j; // Some options bool bAllClasses = (pCmdLine->GetAttributeBool(CONSTLIT("allClasses")) || pCmdLine->GetAttributeBool(CONSTLIT("all"))); // Get the criteria from the command line. Always append 's' because we // want ship classes. CString sCriteria = strPatternSubst(CONSTLIT("%s s"), pCmdLine->GetAttribute(CONSTLIT("criteria"))); CDesignTypeCriteria Criteria; if (CDesignTypeCriteria::ParseCriteria(sCriteria, &Criteria) != NOERROR) { printf("ERROR: Unable to parse criteria.\n"); return; } // Generate a list of columns to display TArray<CString> Cols; Cols.Insert(FIELD_LEVEL); Cols.Insert(FIELD_NAME); for (i = 0; i < pCmdLine->GetAttributeCount(); i++) { CString sAttrib = pCmdLine->GetAttributeName(i); if (strEquals(sAttrib, FIELD_BALANCE)) { Cols.Insert(CONSTLIT("balanceType")); Cols.Insert(CONSTLIT("combatStrength")); Cols.Insert(CONSTLIT("damage")); Cols.Insert(CONSTLIT("defenseStrength")); } else if (!IsMainCommandParam(sAttrib) && !strEquals(sAttrib, CONSTLIT("shiptable"))) { CString sValue = pCmdLine->GetAttribute(i); if (!strEquals(sValue, CONSTLIT("true"))) Cols.Insert(strPatternSubst(CONSTLIT("%s:%s"), sAttrib, sValue)); else Cols.Insert(sAttrib); } } // Output the header for (j = 0; j < Cols.GetCount(); j++) { if (j != 0) printf("\t"); printf(Cols[j].GetASCIIZPointer()); } printf("\n"); // Generate a table CSymbolTable Table(FALSE, TRUE); // Loop over all items that match and add them to // a sorted table. for (i = 0; i < Universe.GetShipClassCount(); i++) { CShipClass *pClass = Universe.GetShipClass(i); // Only include generic classes unless otherwise specified if (!bAllClasses && !pClass->HasLiteralAttribute(CONSTLIT("genericClass"))) continue; if (!pClass->MatchesCriteria(Criteria)) continue; // Figure out the sort order char szBuffer[1024]; wsprintf(szBuffer, "%04d%s%d", pClass->GetLevel(), pClass->GetNounPhrase(0).GetASCIIZPointer(), pClass->GetUNID()); Table.AddEntry(CString(szBuffer), (CObject *)pClass); } // Output table for (i = 0; i < Table.GetCount(); i++) { CShipClass *pClass = (CShipClass *)Table.GetValue(i); // Output each row for (j = 0; j < Cols.GetCount(); j++) { if (j != 0) printf("\t"); const CString &sField = Cols[j]; CString sValue; if (strEquals(sField, FIELD_ENTITY)) { CString *pValue; if (EntityTable.Lookup(pClass->GetUNID(), (CObject **)&pValue) == NOERROR) sValue = *pValue; else sValue = CONSTLIT("?"); } else sValue = pClass->GetDataField(sField); if (strEquals(sField, FIELD_MANEUVER) || strEquals(sField, FIELD_THRUST_TO_WEIGHT)) printf("%.1f", strToInt(sValue, 0, NULL) / 1000.0); else if (strEquals(sField, FIELD_SCORE_CALC)) printf("%d", pClass->CalcScore()); else printf(sValue.GetASCIIZPointer()); } printf("\n"); } printf("\n"); }
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"); } } }
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); }