void CArmorDisplay::Update (void) // Update // // Updates buffer from data { int i; if (m_pPlayer == NULL) return; CShip *pShip = m_pPlayer->GetShip(); const CPlayerSettings *pSettings = pShip->GetClass()->GetPlayerSettings(); CItemListManipulator ItemList(pShip->GetItemList()); const CG16bitFont &SmallFont = m_pPlayer->GetTrans()->GetFonts().Small; m_Text.DeleteAll(); // If we've changed ships then we need to delete the painters if (m_dwCachedShipID != pShip->GetID()) { if (m_pShieldPainter) { m_pShieldPainter->Delete(); m_pShieldPainter = NULL; } m_dwCachedShipID = pShip->GetID(); } // Erase everything m_Buffer.Fill(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, DEFAULT_TRANSPARENT_COLOR); // Figure out the status of the shields int iHP = 0; int iMaxHP = 10; CInstalledDevice *pShield = pShip->GetNamedDevice(devShields); if (pShield) pShield->GetStatus(pShip, &iHP, &iMaxHP); // Draw the base ship image, if we have it const SArmorImageDesc &ArmorDesc = pSettings->GetArmorDesc(); if (!ArmorDesc.ShipImage.IsEmpty()) { const RECT &rcShip = ArmorDesc.ShipImage.GetImageRect(); m_Buffer.ColorTransBlt(rcShip.left, rcShip.top, RectWidth(rcShip), RectHeight(rcShip), 255, ArmorDesc.ShipImage.GetImage(NULL_STR), DESCRIPTION_WIDTH + ((SHIELD_IMAGE_WIDTH - RectWidth(rcShip)) / 2), (SHIELD_IMAGE_HEIGHT - RectHeight(rcShip)) / 2); } // Draw the old-style shields const SShieldImageDesc &ShieldDesc = pSettings->GetShieldDesc(); if (!ShieldDesc.pShieldEffect) { int iWhole = (iMaxHP > 0 ? (iHP * 100) / iMaxHP : 100); int iIndex = (100 - iWhole) / 20; const RECT &rcShield = ShieldDesc.Image.GetImageRect(); m_Buffer.ColorTransBlt(rcShield.left, rcShield.top + (RectHeight(rcShield) * iIndex), RectWidth(rcShield), RectHeight(rcShield), 255, ShieldDesc.Image.GetImage(NULL_STR), DESCRIPTION_WIDTH + ((SHIELD_IMAGE_WIDTH - RectWidth(rcShield)) / 2), (SHIELD_IMAGE_HEIGHT - RectHeight(rcShield)) / 2); } if (pShield) { m_Buffer.Fill(SHIELD_HP_DISPLAY_X, SHIELD_HP_DISPLAY_Y, SHIELD_HP_DISPLAY_WIDTH, SHIELD_HP_DISPLAY_HEIGHT, SHIELD_HP_DISPLAY_BACK_COLOR); CString sHP = strFromInt(iHP); int cxWidth = m_pFonts->Medium.MeasureText(sHP, NULL); m_pFonts->Medium.DrawText(m_Buffer, SHIELD_HP_DISPLAY_X + (SHIELD_HP_DISPLAY_WIDTH - cxWidth) / 2, SHIELD_HP_DISPLAY_Y - 1, CG16bitImage::LightenPixel(m_pFonts->wAltGreenColor, 60), sHP); DrawBrokenLine(m_Buffer, 0, SHIELD_HP_DISPLAY_Y, SHIELD_HP_DISPLAY_X, SHIELD_HP_DISPLAY_Y, 0, SHIELD_HP_DISPLAY_LINE_COLOR); WORD wColor; if (pShield->IsEnabled() && !pShield->IsDamaged() && !pShield->IsDisrupted()) wColor = m_pFonts->wAltGreenColor; else wColor = DISABLED_TEXT_COLOR; CString sShieldName = pShield->GetClass()->GetName(); int cyHeight; cxWidth = m_pFonts->Medium.MeasureText(sShieldName, &cyHeight); // Add the shield name to list of text to paint STextPaint *pPaint = m_Text.Insert(); pPaint->sText = sShieldName; pPaint->x = 0; pPaint->y = SHIELD_HP_DISPLAY_Y; pPaint->pFont = &m_pFonts->Medium; pPaint->wColor = wColor; // Paint the modifiers if (pShield->GetMods().IsNotEmpty() || pShield->GetBonus() != 0) { pShip->SetCursorAtNamedDevice(ItemList, devShields); CString sMods = pShield->GetEnhancedDesc(pShip, &ItemList.GetItemAtCursor()); if (!sMods.IsBlank()) { bool bDisadvantage = (*(sMods.GetASCIIZPointer()) == '-'); int cx = SmallFont.MeasureText(sMods); m_Buffer.Fill(SHIELD_HP_DISPLAY_X - cx - 8, SHIELD_HP_DISPLAY_Y, cx + 8, SHIELD_HP_DISPLAY_HEIGHT, (bDisadvantage ? ARMOR_DAMAGED_BACK_COLOR : ARMOR_ENHANCE_BACK_COLOR)); SmallFont.DrawText(m_Buffer, SHIELD_HP_DISPLAY_X - cx - 4, SHIELD_HP_DISPLAY_Y + (SHIELD_HP_DISPLAY_HEIGHT - SmallFont.GetHeight()) / 2, (bDisadvantage ? ARMOR_DAMAGED_TEXT_COLOR : ARMOR_ENHANCE_TEXT_COLOR), sMods); } } } // Draw armor int iArmorCount = Min(pShip->GetArmorSectionCount(), pSettings->GetArmorDescCount()); for (i = 0; i < iArmorCount; i++) { const SArmorSegmentImageDesc *pImage = &pSettings->GetArmorDesc(i); CInstalledArmor *pArmor = pShip->GetArmorSection(i); int iMaxHP = pArmor->GetMaxHP(pShip); int iWhole = (iMaxHP == 0 ? 100 : (pArmor->GetHitPoints() * 100) / iMaxHP); int iIndex = (100 - iWhole) / 20; if (iIndex < 5) { const RECT &rcImage = pImage->Image.GetImageRect(); m_Buffer.ColorTransBlt(rcImage.left, rcImage.top + iIndex * RectHeight(rcImage), RectWidth(rcImage), RectHeight(rcImage), 255, pImage->Image.GetImage(NULL_STR), DESCRIPTION_WIDTH + pImage->xDest, pImage->yDest); } } // Draw the new style shields on top if (ShieldDesc.pShieldEffect) { int x = DESCRIPTION_WIDTH + SHIELD_IMAGE_WIDTH / 2; int y = SHIELD_IMAGE_HEIGHT / 2; SViewportPaintCtx Ctx; Ctx.iTick = g_pUniverse->GetTicks(); Ctx.iVariant = (iMaxHP > 0 ? (iHP * 100) / iMaxHP : 0); Ctx.iDestiny = pShip->GetDestiny(); Ctx.iRotation = 90; if (m_pShieldPainter == NULL) m_pShieldPainter = ShieldDesc.pShieldEffect->CreatePainter(); m_pShieldPainter->Paint(m_Buffer, x, y, Ctx); } // Draw armor names for (i = 0; i < iArmorCount; i++) { const SArmorSegmentImageDesc *pImage = &pSettings->GetArmorDesc(i); CInstalledArmor *pArmor = pShip->GetArmorSection(i); // Paint the HPs if (i == m_iSelection) { m_Buffer.Fill(DESCRIPTION_WIDTH + pImage->xHP - 1, pImage->yHP - 1, HP_DISPLAY_WIDTH + 2, HP_DISPLAY_HEIGHT + 2, CG16bitImage::DarkenPixel(m_pFonts->wSelectBackground, 128)); } else { m_Buffer.Fill(DESCRIPTION_WIDTH + pImage->xHP, pImage->yHP, HP_DISPLAY_WIDTH, HP_DISPLAY_HEIGHT, HP_DISPLAY_BACK_COLOR); } CString sHP = strFromInt(pArmor->GetHitPoints()); int cxWidth = m_pFonts->Medium.MeasureText(sHP, NULL); m_pFonts->Medium.DrawText(m_Buffer, DESCRIPTION_WIDTH + pImage->xHP + (HP_DISPLAY_WIDTH - cxWidth) / 2, pImage->yHP - 1, m_pFonts->wTitleColor, sHP); // Paint the armor name line DrawBrokenLine(m_Buffer, 0, pImage->yName + m_pFonts->Medium.GetHeight(), DESCRIPTION_WIDTH + pImage->xHP + pImage->xNameDestOffset, pImage->yHP + pImage->yNameDestOffset, pImage->cxNameBreak, (i == m_iSelection ? CG16bitImage::DarkenPixel(m_pFonts->wSelectBackground, 128) : ARMOR_LINE_COLOR)); // Paint the armor names CString sName = pArmor->GetClass()->GetShortName(); int cy; int cx = m_pFonts->Medium.MeasureText(sName, &cy) + 4; if (i == m_iSelection) { m_Buffer.Fill(0, pImage->yName, cx, cy, CG16bitImage::DarkenPixel(m_pFonts->wSelectBackground, 128)); } STextPaint *pPaint = m_Text.Insert(); pPaint->sText = sName; pPaint->x = 2; pPaint->y = pImage->yName; pPaint->pFont = &m_pFonts->Medium; pPaint->wColor = m_pFonts->wTitleColor; // Paint the modifiers if (pArmor->GetMods().IsNotEmpty()) { pShip->SetCursorAtArmor(ItemList, i); CString sMods = ItemList.GetItemAtCursor().GetEnhancedDesc(pShip); if (!sMods.IsBlank()) { int cx = SmallFont.MeasureText(sMods); m_Buffer.Fill(ARMOR_ENHANCE_X - cx - 4, pImage->yName + m_pFonts->Medium.GetHeight() - HP_DISPLAY_HEIGHT, cx + 8, HP_DISPLAY_HEIGHT, ARMOR_ENHANCE_BACK_COLOR); SmallFont.DrawText(m_Buffer, ARMOR_ENHANCE_X - cx, pImage->yName + 3, ARMOR_ENHANCE_TEXT_COLOR, sMods); } } } }
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 CPlayerGameStats::GenerateGameStats (CGameStats &Stats, CSpaceObject *pPlayerShip, bool bGameOver) const // GenerateGameStats // // Generates a stats for everything we track { int j; CShip *pShip = (pPlayerShip ? pPlayerShip->AsShip() : NULL); if (pShip == NULL) return; CPlayerShipController *pPlayer = (CPlayerShipController *)pShip->GetController(); if (pPlayer == NULL) return; CSovereign *pPlayerSovereign = g_pUniverse->FindSovereign(g_PlayerSovereignUNID); if (pPlayerSovereign == NULL) return; // Base stats Stats.Insert(CONSTLIT("Genome"), strCapitalize(GetGenomeName(pPlayer->GetPlayerGenome()))); Stats.Insert(CONSTLIT("Score"), strFormatInteger(CalcEndGameScore(), -1, FORMAT_THOUSAND_SEPARATOR | FORMAT_UNSIGNED)); Stats.Insert(CONSTLIT("Ship class"), pShip->GetNounPhrase(0)); CTimeSpan Time = GetPlayTime(); if (!Time.IsBlank()) Stats.Insert(CONSTLIT("Time played"), Time.Format(NULL_STR)); #ifdef REAL_TIME Time = GetGameTime(); if (!Time.IsBlank()) Stats.Insert(CONSTLIT("Time elapsed in game"), Time.Format(NULL_STR)); #endif // Some combat stats CString sDestroyed = GetStat(ENEMY_SHIPS_DESTROYED_STAT); if (!sDestroyed.IsBlank()) Stats.Insert(CONSTLIT("Enemy ships destroyed"), sDestroyed, CONSTLIT("combat")); sDestroyed = GetStat(FRIENDLY_SHIPS_DESTROYED_STAT); if (!sDestroyed.IsBlank()) Stats.Insert(CONSTLIT("Friendly ships destroyed"), sDestroyed, CONSTLIT("combat")); sDestroyed = GetStat(ENEMY_STATIONS_DESTROYED_STAT); if (!sDestroyed.IsBlank()) Stats.Insert(CONSTLIT("Enemy stations destroyed"), sDestroyed, CONSTLIT("combat")); sDestroyed = GetStat(FRIENDLY_STATIONS_DESTROYED_STAT); if (!sDestroyed.IsBlank()) Stats.Insert(CONSTLIT("Friendly stations destroyed"), sDestroyed, CONSTLIT("combat")); // Add stat for every station destroyed CStatCounterArray CounterArray; CMapIterator i; m_StationStats.Reset(i); while (m_StationStats.HasMore(i)) { SStationTypeStats *pStats; DWORD dwUNID = m_StationStats.GetNext(i, &pStats); CStationType *pType = g_pUniverse->FindStationType(dwUNID); if (pType == NULL) continue; CString sName = pType->GetNounPhrase(0); CString sSort = strPatternSubst(CONSTLIT("%03d%s"), 100 - pType->GetLevel(), sName); if (pType->GetSovereign()->IsEnemy(pPlayerSovereign)) CounterArray.Insert(sName, pStats->iDestroyed, CONSTLIT("Enemy stations destroyed"), sSort); else CounterArray.Insert(sName, pStats->iDestroyed, CONSTLIT("Friendly stations destroyed"), sSort); } CounterArray.GenerateGameStats(Stats); // Add stat for every ship class destroyed CounterArray.DeleteAll(); m_ShipStats.Reset(i); while (m_ShipStats.HasMore(i)) { SShipClassStats *pStats; DWORD dwUNID = m_ShipStats.GetNext(i, &pStats); CShipClass *pClass = g_pUniverse->FindShipClass(dwUNID); if (pClass == NULL) continue; CString sName = pClass->GetNounPhrase(0); CString sSort = strPatternSubst(CONSTLIT("%09d%s"), 100000000 - pClass->GetScore(), sName); if (pStats->iEnemyDestroyed > 0) CounterArray.Insert(sName, pStats->iEnemyDestroyed, CONSTLIT("Enemy ships destroyed"), sSort); if (pStats->iFriendDestroyed > 0) CounterArray.Insert(sName, pStats->iFriendDestroyed, CONSTLIT("Friendly ships destroyed"), sSort); } CounterArray.GenerateGameStats(Stats); // Add stat for every weapon fired m_ItemStats.Reset(i); while (m_ItemStats.HasMore(i)) { SItemTypeStats *pStats; DWORD dwUNID = m_ItemStats.GetNext(i, &pStats); CItemType *pItemType = g_pUniverse->FindItemType(dwUNID); if (pItemType == NULL) continue; CString sName = pItemType->GetNounPhrase(nounShort); CString sSort = strPatternSubst(CONSTLIT("%03d%s"), 100 - pItemType->GetLevel(), sName); // Installed items if (pStats->dwFirstInstalled != INVALID_TIME) Stats.Insert(sName, NULL_STR, CONSTLIT("Items installed"), sSort); if (pStats->iCountFired > 0) Stats.Insert(sName, strFormatInteger(pStats->iCountFired, -1, FORMAT_THOUSAND_SEPARATOR | FORMAT_UNSIGNED), CONSTLIT("Weapons fired"), sSort); } // Stats for player equipment (but only if the game is done) if (bGameOver) { TSortMap<CString, CItem> InstalledItems; // First we generate a sorted list of installed items // (We do this in case there are multiple of the same device/armor so that // we can coalesce them together into a single line). CItemListManipulator ItemList(pShip->GetItemList()); ItemList.ResetCursor(); while (ItemList.MoveCursorForward()) { const CItem &Item(ItemList.GetItemAtCursor()); if (Item.IsInstalled()) { CString sEnhancement = Item.GetEnhancedDesc(pShip); CString sItemName = Item.GetNounPhrase(nounActual | nounCountOnly | nounShort); CString sLine = (sEnhancement.IsBlank() ? sItemName : strPatternSubst(CONSTLIT("%s [%s]"), sItemName, sEnhancement)); bool bInserted; CItem *pEntry = InstalledItems.SetAt(sLine, &bInserted); if (bInserted) { *pEntry = Item; pEntry->SetCount(1); } else pEntry->SetCount(pEntry->GetCount() + 1); } } // Now add all the installed items to the stats for (j = 0; j < InstalledItems.GetCount(); j++) { // Redo the line now that we know the proper count CString sEnhancement = InstalledItems[j].GetEnhancedDesc(pShip); CString sItemName = InstalledItems[j].GetNounPhrase(nounActual | nounCountOnly); CString sLine = (sEnhancement.IsBlank() ? sItemName : strPatternSubst(CONSTLIT("%s [%s]"), sItemName, sEnhancement)); // Compute the sort order int iOrder; switch (InstalledItems[j].GetType()->GetCategory()) { case itemcatWeapon: iOrder = 0; break; case itemcatLauncher: iOrder = 1; break; case itemcatShields: iOrder = 2; break; case itemcatArmor: iOrder = 3; break; case itemcatReactor: iOrder = 4; break; case itemcatDrive: iOrder = 5; break; default: iOrder = 6; break; } CString sSort = strPatternSubst(CONSTLIT("%d%03d%s"), iOrder, 100 - InstalledItems[j].GetType()->GetLevel(), sLine); Stats.Insert(sLine, NULL_STR, CONSTLIT("Final equipment"), sSort); } // Add the remaining items ItemList.ResetCursor(); while (ItemList.MoveCursorForward()) { const CItem &Item(ItemList.GetItemAtCursor()); if (!Item.IsInstalled()) { CString sEnhancement = Item.GetEnhancedDesc(pShip); CString sItemName = Item.GetNounPhrase(nounActual | nounCountOnly); CString sLine = (sEnhancement.IsBlank() ? sItemName : strPatternSubst(CONSTLIT("%s [%s]"), sItemName, sEnhancement)); CString sSort = strPatternSubst(CONSTLIT("%03d%s"), 100 - Item.GetType()->GetLevel(), sLine); Stats.Insert(sLine, NULL_STR, CONSTLIT("Final items"), sSort); } } } }