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; } } }