void GenerateWeaponEffectChart (CUniverse &Universe, CXMLElement *pCmdLine) { int i; // Compute the list of weapons to show, making sure we filter to weapons // and missiles only. CItemTypeTable Selection; if (!Selection.Filter(pCmdLine->GetAttribute(CRITERIA_ATTRIB)) || (Selection.IsAll() && !Selection.Filter(CONSTLIT("wm")))) { printf("No entries match criteria.\n"); return; } Selection.Sort(); // Ship to use DWORD dwPlatformUNID; if (!pCmdLine->FindAttributeInteger(SHIP_UNID_ATTRIB, (int *)&dwPlatformUNID)) dwPlatformUNID = WEAPON_PLATFORM_UNID; // Compute some metrics int iFramesPerItem = 10; int cxFrameHorzMargin = 10; int cxMaxDistPerTick = (int)(STD_SECONDS_PER_UPDATE * (LIGHT_SECOND / g_KlicksPerPixel)); int cyFrame = 64; int cxFrame = (2 * cxFrameHorzMargin) + (iFramesPerItem * cxMaxDistPerTick); int iHitEffectFramesPerItem = 5; int cxHitEffect = 128; int cyHitEffect = 128; int cyRowTitle = 20; int cyRow = cyRowTitle + Max(ITEM_ICON_HEIGHT, cyFrame * iFramesPerItem); int cxRow = ITEM_ICON_WIDTH + cxFrame; int iColumns = Max(1, mathSqrt(Selection.GetCount())); int iRows = (Selection.GetCount() + (iColumns - 1)) / iColumns; int cxImage = cxRow * iColumns; int cyImage = cyRow * iRows; // Initialize the output COutputChart Output; Output.SetContentSize(cxImage, cyImage); Output.SetOutputFilespec(pCmdLine->GetAttribute(CONSTLIT("output"))); // Initialize fonts Output.SetStyleFont(STYLE_TITLE, pCmdLine->GetAttribute(CONSTLIT("font"))); Output.SetStyleColor(STYLE_TITLE, CG32bitPixel(0xFF, 0xFF, 0xFF)); // Prepare the universe CSystem *pSystem; if (Universe.CreateEmptyStarSystem(&pSystem) != NOERROR) { printf("ERROR: Unable to create empty star system.\n"); return; } // Create a target in the center of the system CSpaceObject *pStation; CStationType *pTargetType = Universe.FindStationType(TARGET_UNID); if (pTargetType == NULL || pSystem->CreateStation(pTargetType, NULL, CVector(), &pStation) != NOERROR) { printf("ERROR: Unable to create station.\n"); return; } // Create the weapon platform some distance away CSovereign *pPlatformSovereign = Universe.FindSovereign(PLAYER_SOVEREIGN_UNID); CShip *pPlatform; if (pPlatformSovereign == NULL || pSystem->CreateShip(dwPlatformUNID, NULL, NULL, pPlatformSovereign, CVector(-5.0 * LIGHT_SECOND, 0.), CVector(), 0, NULL, NULL, &pPlatform) != NOERROR) { printf("ERROR: Unable to create weapons platform.\n"); return; } // Set the attacker to hold IShipController *pController = pPlatform->GetController(); if (pController == NULL) { printf("ERROR: No controller for ship.\n"); return; } pController->AddOrder(IShipController::orderHold, NULL, IShipController::SData()); pPlatform->SetControllerEnabled(false); // Install the largest possible reactor on the ship CItemType *pReactorType = Universe.FindItemType(REACTOR_UNID); if (pReactorType) { CItem ReactorItem(pReactorType, 1); CItemListManipulator ItemList(pPlatform->GetItemList()); ItemList.AddItem(ReactorItem); pPlatform->OnComponentChanged(comCargo); pPlatform->ItemsModified(); pPlatform->InvalidateItemListAddRemove(); pPlatform->InstallItemAsDevice(ItemList); } // Set the POV Universe.SetPOV(pStation); pSystem->SetPOVLRS(pStation); // Prepare system Universe.UpdateExtended(); Universe.GarbageCollectLibraryBitmaps(); Universe.StartGame(true); // Output each weapon int xOrigin; int yOrigin; CG32bitImage &Image = Output.GetOutputImage(&xOrigin, &yOrigin); const CG16bitFont &TitleFont = Output.GetStyleFont(STYLE_TITLE); CG32bitPixel rgbTitleColor = Output.GetStyleColor(STYLE_TITLE); for (i = 0; i < Selection.GetCount(); i++) { CItemType *pType = Selection.GetItemType(i); // Compute the metrics of this row int xRow = xOrigin + (i % iColumns) * cxRow; int yRow = yOrigin + (i / iColumns) * cyRow; // Paint the weapon title Image.Fill(xRow, yRow, cxRow, cyRow, CG32bitPixel(0x40, 0x40, 0x40)); TitleFont.DrawText(Image, xRow + 8, yRow, rgbTitleColor, pType->GetNounPhrase()); // Paint the frames PaintWeaponFrames(Image, pType, pPlatform, iFramesPerItem, xRow + ITEM_ICON_WIDTH + cxFrameHorzMargin, yRow + cyRowTitle, cxMaxDistPerTick, cyFrame); } // Done Output.Output(); }
void GenerateShieldStats (CUniverse &Universe, CXMLElement *pCmdLine) { int i; CString sUNID = pCmdLine->GetAttribute(CONSTLIT("unid")); DWORD dwUNID = strToInt(sUNID, 0, NULL); CItemType *pItem = Universe.FindItemType(dwUNID); if (pItem == NULL) { CItemCriteria Crit; CItem::InitCriteriaAll(&Crit); CItem Item = CItem::CreateItemByName(sUNID, Crit); pItem = Item.GetType(); if (pItem == NULL) { printf("ERROR: Unknown item '%s'\n", sUNID.GetASCIIZPointer()); return; } } if (pItem->GetCategory() != itemcatShields) { printf("ERROR: Item '%s' is not a shield generator\n", pItem->GetNounPhrase().GetASCIIZPointer()); return; } bool bVerbose = pCmdLine->GetAttributeBool(CONSTLIT("verbose")); bool bEval = pCmdLine->GetAttributeBool(CONSTLIT("eval")); // Get the stats for the shield Metric rHP = (Metric)pItem->GetDataFieldInteger(FIELD_HP); Metric rHPRegenPerTick = pItem->GetDataFieldInteger(FIELD_REGEN) / 1000.0; int iDamageAdj[damageCount]; CString sDamageAdj = pItem->GetDataField(CONSTLIT("damageAdj")); char *pPos = sDamageAdj.GetASCIIZPointer(); int iCount = 0; while (iCount < damageCount) { iDamageAdj[iCount] = strParseInt(pPos, 0, &pPos, NULL); if (*pPos != '\0') pPos++; iCount++; } // Print header printf("%s\n\n", pItem->GetNounPhrase().GetASCIIZPointer()); // Loop over all weapons and sort them by level and then name CSymbolTable List(FALSE, TRUE); for (i = 0; i < Universe.GetItemTypeCount(); i++) { CItemType *pWeapon = Universe.GetItemType(i); if (pWeapon->GetCategory() != itemcatWeapon) continue; CString sLevel = (pWeapon->GetLevel() < 10 ? strPatternSubst(CONSTLIT("0%d"), pWeapon->GetLevel()) : strFromInt(pWeapon->GetLevel(), FALSE)); CString sSortName = strPatternSubst(CONSTLIT("%s%s"), sLevel, pWeapon->GetNounPhrase()); List.AddEntry(sSortName, (CObject *)pWeapon); } // Loop over sorted list and output data for (i = 0; i < List.GetCount(); i++) { CItemType *pWeapon = (CItemType *)List.GetValue(i); // Get the data for the weapon int iFireDelay = pWeapon->GetDataFieldInteger(CONSTLIT("fireDelay")); Metric rAverageDamage = pWeapon->GetDataFieldInteger(CONSTLIT("averageDamage")) / 1000.0; int iDamageType = pWeapon->GetDataFieldInteger(CONSTLIT("damageType")); if (iDamageType < 0 || iDamageType >= damageCount) iDamageType = 0; // Adjust damage for type rAverageDamage = rAverageDamage * (iDamageAdj[iDamageType] / 100.0); if (rAverageDamage < 1.0) rAverageDamage = 0.0; // Calculate how many shots it would take to pierce through the shields char szBuffer[256]; Metric rShotsToDeplete; Metric rRegenPerShot = rHPRegenPerTick * (Metric)iFireDelay; if (rRegenPerShot >= rAverageDamage) { rShotsToDeplete = 1000000.0; lstrcpy(szBuffer, "ineffective"); } else { Metric rDrainPerShot = rAverageDamage - rRegenPerShot; rShotsToDeplete = rHP / rDrainPerShot; sprintf(szBuffer, "%.2f", rShotsToDeplete); } // See if this weapon is overpowered or underpowered char szEval[256]; if (bEval) { lstrcpy(szEval, "\t"); if (pWeapon->GetLevel() < pItem->GetLevel()) { if (rShotsToDeplete <= 10.0) lstrcpy(szEval, "\tOVERpowered"); } else { if (rShotsToDeplete > 20.0) lstrcpy(szEval, "\tUNDERpowered"); } } else lstrcpy(szEval, ""); // Print table if (bVerbose) { printf("%s\t%s\t%s\t(%d ticks; %.2f damage; %.2f regen/shot)%s\n", RomanNumeral(pWeapon->GetLevel()), pWeapon->GetNounPhrase().GetASCIIZPointer(), szBuffer, iFireDelay, rAverageDamage, rRegenPerShot, szEval); } else { printf("%s\t%s\t%s%s\n", RomanNumeral(pWeapon->GetLevel()), pWeapon->GetNounPhrase().GetASCIIZPointer(), szBuffer, szEval); } } }