void CTranscendenceWnd::OnCharIntro (char chChar, DWORD dwKeyData) // OnCharIntro // // Handle WM_CHAR { if (m_bOverwriteGameDlg) { return; } if (m_PlayerDisplay.OnChar(chChar)) return; if (m_ButtonBarDisplay.OnChar(chChar)) return; switch (chChar) { case 'N': case 'n': { CShip *pShip = m_Universe.GetPOV()->AsShip(); if (pShip) { m_dwIntroShipClass = pShip->GetClass()->GetUNID(); pShip->Destroy(removedFromSystem, NULL); } break; } } }
void CTranscendenceWnd::DestroyIntroShips (void) // DestroyIntroShips // // Destroys all ships of the same class as the POV { int i; CShip *pShip = g_pUniverse->GetPOV()->AsShip(); if (pShip == NULL) return; // Destroy all ships of the current class CSystem *pSystem = pShip->GetSystem(); CShipClass *pClassToDestroy = pShip->GetClass(); TArray<CSpaceObject *> ShipsToDestroy; CSpaceObject *pOtherShip = NULL; for (i = 0; i < pSystem->GetObjectCount(); i++) { CSpaceObject *pObj = pSystem->GetObject(i); CShip *pShip; if (pObj && !pObj->IsInactive() && !pObj->IsVirtual() && (pShip = pObj->AsShip())) { if (pShip->GetClass() == pClassToDestroy) ShipsToDestroy.Insert(pObj); else if (pOtherShip == NULL) pOtherShip = pObj; } } // Destroy ships for (i = 0; i < ShipsToDestroy.GetCount(); i++) ShipsToDestroy[i]->Destroy(removedFromSystem, CDamageSource()); }
void CPlayerGameStats::OnObjDestroyedByPlayer (const SDestroyCtx &Ctx, CSpaceObject *pPlayer) // OnDestroyedByPlayer // // Object destroyed by player { bool bIsEnemy = Ctx.pObj->IsEnemy(pPlayer); // Is this a ship? CShip *pShip; if (Ctx.pObj->GetCategory() == CSpaceObject::catShip && (pShip = Ctx.pObj->AsShip())) { CShipClass *pClass = pShip->GetClass(); SShipClassStats *pStats = GetShipStats(pClass->GetUNID()); if (bIsEnemy) { pStats->iEnemyDestroyed++; m_iScore += pClass->GetScore(); } else pStats->iFriendDestroyed++; } // Is this a station? else if (Ctx.pObj->GetCategory() == CSpaceObject::catStation) { if (Ctx.pObj->HasAttribute(CONSTLIT("populated"))) { SStationTypeStats *pStats = GetStationStats(Ctx.pObj->GetType()->GetUNID()); pStats->iDestroyed++; } } }
ALERROR CTargetDisplay::Init (CPlayerShipController *pPlayer, const RECT &rcRect, DWORD dwLocation) // Init // // Initializes display { CleanUp(); m_pPlayer = pPlayer; // Create the painter CShip *pShip = m_pPlayer->GetShip(); SDesignLoadCtx Ctx; m_pHUDPainter = IHUDPainter::Create(Ctx, pShip->GetClass(), hudTargeting); if (m_pHUDPainter) m_pHUDPainter->SetLocation(rcRect, dwLocation); return NOERROR; }
void CGSelectorArea::SetRegionsFromWeapons (CSpaceObject *pSource) // SetRegionsFromWeapons // // Creates regions based on installed weapons. { int i; ASSERT(pSource); if (pSource == NULL) return; CShip *pShip = pSource->AsShip(); if (pShip == NULL) return; CShipClass *pClass = pShip->GetClass(); // Keep track of layouts that have already been used. TArray<bool> SlotStatus; SlotStatus.InsertEmpty(MISC_DEVICES_LAYOUT_COUNT); for (i = 0; i < MISC_DEVICES_LAYOUT_COUNT; i++) SlotStatus[i] = true; // If we don't have a launcher, we place the launcher slot first because we // want it to take precedence (position-wise). int iIndex; bool bHasLauncher = (pShip->GetNamedDevice(devMissileWeapon) != NULL); if (!bHasLauncher) { // See if we can figure out the proper position for the launcher based // on the class slots CVector vLauncherPos; SDeviceDesc DeviceDesc; if (pClass->FindDeviceSlotDesc(devMissileWeapon, &DeviceDesc)) vLauncherPos = pClass->GetPosOffset(DeviceDesc.iPosAngle, DeviceDesc.iPosRadius, DeviceDesc.iPosZ, DeviceDesc.b3DPosition); // Find a layout if (FindLayoutForPos(vLauncherPos, SlotStatus, &iIndex)) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devMissileWeapon; pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; SlotStatus[iIndex] = false; } } // Create a region for each weapon. for (i = 0; i < pShip->GetDeviceCount(); i++) { CInstalledDevice *pDevice = pShip->GetDevice(i); if (pDevice->IsEmpty() || (pDevice->GetCategory() != itemcatWeapon && pDevice->GetCategory() != itemcatLauncher)) continue; if (pDevice->GetCategory() == itemcatLauncher) bHasLauncher = true; // If the device already has a position index, then use that (assuming // it's free). iIndex = pDevice->GetSlotPosIndex(); if (iIndex < 0 || iIndex >= SlotStatus.GetCount() || !SlotStatus[iIndex]) iIndex = -1; // If we don't have an assigned slot, figure it out. if (iIndex == -1) { if (!FindLayoutForPos(pDevice->GetPosOffset(pShip), SlotStatus, &iIndex)) continue; // Remember so we stay in this location. pDevice->SetSlotPosIndex(iIndex); } // Create the region const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeInstalledItem; pEntry->pItemCtx = new CItemCtx(pShip, pDevice); pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; // Mark the layout as used SlotStatus[iIndex] = false; } // Figure out how many empty weapon slots we should create. We add one // empty slot for each weapon slot, but we subtract one if we don't have // a launcher and we always have at least 1 empty slot, in case the player // finds a slot-less weapon. #ifdef SINGLE_FREE_SLOT int iEmptySlots = 1; #else int iWeaponSlotsInUse; int iTotalSlotsInUse = pShip->CalcDeviceSlotsInUse(&iWeaponSlotsInUse); int iEmptySlots = Max(1, Min((pClass->GetMaxDevices() - iTotalSlotsInUse), (pClass->GetMaxWeapons() - iWeaponSlotsInUse)) - (bHasLauncher ? 0 : 1)); #endif // Try to position the empty slots CVector vWeaponPos; SDeviceDesc DeviceDesc; if (pClass->FindDeviceSlotDesc(devPrimaryWeapon, &DeviceDesc)) vWeaponPos = pClass->GetPosOffset(DeviceDesc.iPosAngle, DeviceDesc.iPosRadius, DeviceDesc.iPosZ, DeviceDesc.b3DPosition); for (i = 0; i < iEmptySlots; i++) { // Find a position if (FindLayoutForPos(vWeaponPos, SlotStatus, &iIndex)) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devPrimaryWeapon; pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; SlotStatus[iIndex] = false; } } }
void CGSelectorArea::SetRegionsFromMiscDevices (CSpaceObject *pSource) // SetRegionsFromMiscDevices // // Generates regions showing misc devices (including reactor, drive, // and cargo hold). { int i; ASSERT(pSource); if (pSource == NULL) return; CShip *pShip = pSource->AsShip(); if (pShip == NULL) return; CShipClass *pClass = pShip->GetClass(); // Keep track of layouts that have already been used. TArray<bool> SlotStatus; SlotStatus.InsertEmpty(MISC_DEVICES_LAYOUT_COUNT); for (i = 0; i < MISC_DEVICES_LAYOUT_COUNT; i++) SlotStatus[i] = true; // Reserve the slots for named device types SlotStatus[REACTOR_SLOT_INDEX] = false; SlotStatus[DRIVE_SLOT_INDEX] = false; SlotStatus[CARGO_SLOT_INDEX] = false; // Count the number of miscellaneous devices with 0 // slots (because we may need to bump them). int iSlottedDevices = 0; int iNonSlotDevices = 0; for (i = 0; i < pShip->GetDeviceCount(); i++) { CInstalledDevice *pDevice = pShip->GetDevice(i); if (pDevice->IsEmpty() || pDevice->GetCategory() != itemcatMiscDevice) continue; if (pDevice->GetClass()->GetSlotsRequired() > 0) iSlottedDevices++; else iNonSlotDevices++; } // We try to fit all other devices (and placeholders) before we add a // non-slotted device. int iNonSlotDeviceSlotsAvail = Max(0, MISC_DEVICES_LAYOUT_COUNT - 4 - iSlottedDevices); // Create a region for each device. int iIndex = -1; bool bHasReactor = false; bool bHasDrive = false; bool bHasCargo = false; int iNextUnamedSlot = FIRST_UNNAMED_SLOT_INDEX; for (i = 0; i < pShip->GetDeviceCount(); i++) { CInstalledDevice *pDevice = pShip->GetDevice(i); if (pDevice->IsEmpty()) continue; // Figure out the layout descriptor iIndex = -1; const SLayoutDesc *pLayout = NULL; switch (pDevice->GetCategory()) { case itemcatCargoHold: pLayout = &g_MiscDevicesLayout[CARGO_SLOT_INDEX]; bHasCargo = true; break; case itemcatDrive: pLayout = &g_MiscDevicesLayout[DRIVE_SLOT_INDEX]; bHasDrive = true; break; case itemcatMiscDevice: { // If this is a 0-slot device and we have no more room for // 0-slot devices, then we skip it. if (pDevice->GetClass()->GetSlotsRequired() == 0 && iNonSlotDeviceSlotsAvail <= 0) continue; // If the device already has a position index, then use that (assuming // it's free). iIndex = pDevice->GetSlotPosIndex(); if (iIndex < 0 || iIndex >= SlotStatus.GetCount() || !SlotStatus[iIndex]) iIndex = -1; // If we don't have an assigned slot, figure it out. if (iIndex == -1) { // Look for a new position if (!FindLayoutForPos(pDevice->GetPosOffset(pShip), SlotStatus, &iIndex)) continue; // Remember so we stay in this location. pDevice->SetSlotPosIndex(iIndex); } // Remember the layout and mark it as used. pLayout = &g_MiscDevicesLayout[iIndex]; SlotStatus[iIndex] = false; break; } case itemcatReactor: pLayout = &g_MiscDevicesLayout[REACTOR_SLOT_INDEX]; bHasReactor = true; break; } // Create the region (but only if we have a layout position // for it). if (pLayout) { SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeInstalledItem; pEntry->pItemCtx = new CItemCtx(pShip, pDevice); pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } } // Add empty slots, if necessary if (!bHasReactor) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[REACTOR_SLOT_INDEX]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devReactor; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } if (!bHasDrive) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[DRIVE_SLOT_INDEX]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devDrive; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } if (!bHasCargo) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[CARGO_SLOT_INDEX]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devCargo; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } // Figure out how many empty weapon slots we should create. We add one // empty slot for each weapon slot, but we subtract one if we don't have // a launcher and we always have at least 1 empty slot, in case the player // finds a slot-less weapon. #ifdef SINGLE_FREE_SLOT int iEmptySlots = 1; #else int iNonWeaponSlotsInUse; int iTotalSlotsInUse = pShip->CalcDeviceSlotsInUse(NULL, &iNonWeaponSlotsInUse); int iEmptySlots = Max(1, Min((pClass->GetMaxDevices() - iTotalSlotsInUse), (pClass->GetMaxNonWeapons() - iNonWeaponSlotsInUse)) - (bHasReactor ? 0 : 1) - (bHasDrive ? 0 : 1) - (bHasCargo ? 0 : 1)); #endif for (i = 0; i < iEmptySlots; i++) { if (FindLayoutForPos(CVector(), SlotStatus, &iIndex)) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devNone; pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; SlotStatus[iIndex] = false; } } }
void CGSelectorArea::SetRegionsFromArmor (CSpaceObject *pSource) // SetRegionsFromArmor // // Generates regions showing armor and shields for the given ship. { int i; ASSERT(pSource); if (pSource == NULL) return; CShip *pShip = pSource->AsShip(); if (pShip == NULL) return; CShipClass *pClass = pShip->GetClass(); // Compute some metrics. // // We place the shield generator in the center and the armor segments in a // circle around it. const RECT &rcRect = GetRect(); int cxArea = RectWidth(rcRect); int cyArea = RectHeight(rcRect); const int iRadius = WIDE_COLUMN_SPACING; // Now add all the armor segments for (i = 0; i < pShip->GetArmorSectionCount(); i++) { SEntry *pEntry = m_Regions.Insert(); CInstalledArmor *pArmor = pShip->GetArmorSection(i); pEntry->iType = typeInstalledItem; pEntry->pItemCtx = new CItemCtx(pShip, pArmor); // Position the armor segment in a circle (add 90 degrees because the // ship image points up). const CShipArmorSegmentDesc &Section = pClass->GetHullSection(i); int iCenterAngle = 90 + Section.GetCenterAngle(); int xCenter; int yCenter; IntPolarToVector(iCenterAngle, iRadius, &xCenter, &yCenter); pEntry->rcRect.left = xCenter - (ITEM_ENTRY_WIDTH / 2); pEntry->rcRect.top = -yCenter - (ITEM_ENTRY_HEIGHT / 2); pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } // Add the shield generator last SEntry *pEntry = m_Regions.Insert(); CInstalledDevice *pShields = pShip->GetNamedDevice(devShields); if (pShields) { pEntry->iType = typeInstalledItem; pEntry->pItemCtx = new CItemCtx(pShip, pShields); } else { pEntry->iType = typeEmptySlot; pEntry->iSlotType = devShields; } pEntry->rcRect.left = -ITEM_ENTRY_WIDTH / 2; pEntry->rcRect.top = -ITEM_ENTRY_HEIGHT / 2; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; }
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 CReactorDisplay::Update (void) // Update // // Updates the buffer from data { if (m_pPlayer == NULL) return; CShip *pShip = m_pPlayer->GetShip(); const CPlayerSettings *pSettings = pShip->GetClass()->GetPlayerSettings(); const SReactorImageDesc &ReactorDesc = pSettings->GetReactorDesc(); int yOffset = (RectHeight(m_rcRect) - RectHeight(ReactorDesc.ReactorImage.GetImageRect())) / 2; // Paint the background ReactorDesc.ReactorImage.PaintImageUL(m_Buffer, 0, yOffset, 0, 0); // Calculate fuel values int iFuelLeft = pShip->GetFuelLeft(); int iMaxFuel = pShip->GetMaxFuel(); int iFuelLevel = (iMaxFuel > 0 ? (Min((iFuelLeft * 100 / iMaxFuel) + 1, 100)) : 0); // Paint the fuel level CG16bitImage *pFuelImage = NULL; RECT rcSrcRect; bool bBlink; if (iFuelLevel < 15) { pFuelImage = &ReactorDesc.FuelLowLevelImage.GetImage(NULL_STR); rcSrcRect = ReactorDesc.FuelLowLevelImage.GetImageRect(); bBlink = true; } else { pFuelImage = &ReactorDesc.FuelLevelImage.GetImage(NULL_STR); rcSrcRect = ReactorDesc.FuelLevelImage.GetImageRect(); bBlink = false; } if (!bBlink || ((m_iTickCount % 2) == 0)) { int cxFuelLevel = RectWidth(rcSrcRect) * iFuelLevel / 100; m_Buffer.ColorTransBlt(rcSrcRect.left, rcSrcRect.top, cxFuelLevel, RectHeight(rcSrcRect), 255, *pFuelImage, ReactorDesc.xFuelLevelImage, yOffset + ReactorDesc.yFuelLevelImage); } // Paint fuel level text m_Buffer.Fill(ReactorDesc.rcFuelLevelText.left, yOffset + ReactorDesc.rcFuelLevelText.top, RectWidth(ReactorDesc.rcFuelLevelText), RectHeight(ReactorDesc.rcFuelLevelText), DEFAULT_TRANSPARENT_COLOR); CString sFuelLevel = strPatternSubst(CONSTLIT("fuel")); int cxWidth = m_pFonts->Small.MeasureText(sFuelLevel); m_pFonts->Small.DrawText(m_Buffer, ReactorDesc.rcFuelLevelText.left, yOffset + ReactorDesc.rcFuelLevelText.top, m_pFonts->wHelpColor, sFuelLevel, 0); // Calculate the power level int iPowerUsage = pShip->GetPowerConsumption(); int iMaxPower = pShip->GetMaxPower(); int iPowerLevel; if (iMaxPower) iPowerLevel = Min((iPowerUsage * 100 / iMaxPower) + 1, 120); else iPowerLevel = 0; if (iPowerLevel >= 100) m_iOverloading++; else m_iOverloading = 0; bBlink = (m_iOverloading > 0); // Paint the power level if (!bBlink || ((m_iOverloading % 2) == 1)) { CG16bitImage *pPowerImage = &ReactorDesc.PowerLevelImage.GetImage(NULL_STR); rcSrcRect = ReactorDesc.PowerLevelImage.GetImageRect(); int cxPowerLevel = RectWidth(rcSrcRect) * iPowerLevel / 120; m_Buffer.ColorTransBlt(rcSrcRect.left, rcSrcRect.top, cxPowerLevel, RectHeight(rcSrcRect), 255, *pPowerImage, ReactorDesc.xPowerLevelImage, yOffset + ReactorDesc.yPowerLevelImage); } // Paint power level text m_Buffer.Fill(ReactorDesc.rcPowerLevelText.left, yOffset + ReactorDesc.rcPowerLevelText.top, RectWidth(ReactorDesc.rcPowerLevelText), RectHeight(ReactorDesc.rcPowerLevelText), DEFAULT_TRANSPARENT_COLOR); CString sPowerLevel = strPatternSubst(CONSTLIT("power usage")); int cyHeight; cxWidth = m_pFonts->Small.MeasureText(sPowerLevel, &cyHeight); m_pFonts->Small.DrawText(m_Buffer, ReactorDesc.rcPowerLevelText.left, yOffset + ReactorDesc.rcPowerLevelText.bottom - cyHeight, m_pFonts->wHelpColor, sPowerLevel, 0); // Paint the reactor name (we paint on top of the levels) WORD wColor; if (pShip->GetReactorDesc()->fDamaged) wColor = DAMAGED_TEXT_COLOR; else wColor = m_pFonts->wTitleColor; CString sReactorName = strPatternSubst(CONSTLIT("%s (%s)"), pShip->GetReactorName(), ReactorPower2String(iMaxPower)); m_pFonts->Medium.DrawText(m_Buffer, ReactorDesc.rcReactorText.left, yOffset + ReactorDesc.rcReactorText.top, wColor, sReactorName, 0); m_iTickCount++; }