void CShieldClass::CalcMinMaxHP (CItemCtx &Ctx, int iCharges, int iArmorSegs, int iTotalHP, int *retiMin, int *retiMax) const // CalcMinMaxHP // // Returns the min and max HP of this shield // // iCharges = m_iMaxCharges or the current charges on item // iArmorSegs = count of armor segments on ship (or 0) // iTotalHP = current total HP of all armor segments (or 0) { int iMax = m_iHitPoints; int iMin = iMax; if (m_iExtraHPPerCharge) iMax = Max(0, iMax + (m_iExtraHPPerCharge * iCharges)); if (m_iArmorShield) { iMin = m_iArmorShield; if (iArmorSegs > 0) iMax = Min(iMax, ((m_iArmorShield * iTotalHP / iArmorSegs) + 5) / 10); } // If we're installed, fire the custom event to get max HPs if (Ctx.GetSource() && Ctx.GetDevice()) { CItemEnhancementStack *pEnhancements = Ctx.GetDevice()->GetEnhancements(); iMax = FireGetMaxHP(Ctx.GetDevice(), Ctx.GetSource(), iMax); // Apply bonus from device (which includes mods) if (pEnhancements) iMax += (iMax * pEnhancements->GetBonus() / 100); } // Otherwise, we just apply mods else { const CItemEnhancement &Mods = Ctx.GetMods(); if (Mods.IsNotEmpty()) iMax = iMax * Mods.GetHPAdj() / 100; } // Done if (iMin > iMax) iMin = iMax; if (retiMin) *retiMin = iMin; if (retiMax) *retiMax = iMax; }
void CDeviceClass::AccumulateAttributes (CItemCtx &ItemCtx, int iVariant, TArray<SDisplayAttribute> *retList) // AccumulateAttributes // // Add display attributes to the list. { // Add general device attributes. If we have a variant, then it means // we're interested in the attributes for a missile/ammo of the device // (not the device itself). if (iVariant == -1) { CInstalledDevice *pDevice = ItemCtx.GetDevice(); // Linked-fire DWORD dwOptions = GetLinkedFireOptions(ItemCtx); if (dwOptions != 0) retList->Insert(SDisplayAttribute(attribPositive, CONSTLIT("linked-fire"))); } // Let our subclasses add their own attributes OnAccumulateAttributes(ItemCtx, iVariant, retList); }
bool CDeviceClass::AccumulateEnhancements (CItemCtx &Device, CInstalledDevice *pTarget, TArray<CString> &EnhancementIDs, CItemEnhancementStack *pEnhancements) // AccumulateEnhancements // // If this device can enhance pTarget, then we add to the list of enhancements. { int i; bool bEnhanced = false; CInstalledDevice *pDevice = Device.GetDevice(); CSpaceObject *pSource = Device.GetSource(); // See if we can enhance the target device if (pDevice == NULL || (pDevice->IsEnabled() && !pDevice->IsDamaged())) { for (i = 0; i < m_Enhancements.GetCount(); i++) { // If this type of enhancement has already been applied, skip it if (!m_Enhancements[i].sType.IsBlank() && EnhancementIDs.Find(m_Enhancements[i].sType)) continue; // If we don't match the criteria, skip it. if (pSource && pTarget && !pSource->GetItemForDevice(pTarget).MatchesCriteria(m_Enhancements[i].Criteria)) continue; // Add the enhancement pEnhancements->Insert(m_Enhancements[i].Enhancement); bEnhanced = true; // Remember that we added this enhancement class if (!m_Enhancements[i].sType.IsBlank()) EnhancementIDs.Insert(m_Enhancements[i].sType); } } // Let sub-classes add their own if (OnAccumulateEnhancements(Device, pTarget, EnhancementIDs, pEnhancements)) bEnhanced = true; // Done return bEnhanced; }
CString CDeviceClass::GetReference (CItemCtx &Ctx, int iVariant, DWORD dwFlags) // GetReference // // Returns reference string { CString sReference; // For a device we always add power and other properties. // (If iVariant != -1 then it means that we're looking for reference on a // missile or someting). if (iVariant == -1) { CInstalledDevice *pDevice = Ctx.GetDevice(); // Start with power requirements AppendReferenceString(&sReference, GetReferencePower(Ctx)); // Non-standard slots if (GetSlotsRequired() != 1) AppendReferenceString(&sReference, strPatternSubst(CONSTLIT("%d Slots"), GetSlotsRequired())); // External devices if (IsExternal() || (pDevice && pDevice->IsExternal())) AppendReferenceString(&sReference, CONSTLIT("External")); } // Combine with our subclass AppendReferenceString(&sReference, OnGetReference(Ctx, iVariant, dwFlags)); return sReference; }
int CItemEnhancementStack::CalcActivateDelay (CItemCtx &DeviceCtx) const // CalcActivateDelay // // Calculates the activation delay (in ticks) for the given device if we apply // this enhancement stack. { int i; CInstalledDevice *pDevice = DeviceCtx.GetDevice(); if (pDevice == NULL) return 0; Metric rDelay = -1.0; for (i = 0; i < m_Stack.GetCount(); i++) { int iMin, iMax; int iAdj = m_Stack[i].GetActivateRateAdj(&iMin, &iMax); if (iAdj != 100) { if (rDelay < 0.0) { pDevice->SetActivateDelayAdj(100); rDelay = pDevice->GetActivateDelay(DeviceCtx.GetSource()); } rDelay = iAdj * rDelay / 100.0; if (rDelay < (Metric)iMin) rDelay = (Metric)iMin; else if (iMax > 0 && rDelay > (Metric)iMax) rDelay = (Metric)iMax; } } return (rDelay < 0.0 ? 100 : (int)(rDelay + 0.5)); }
int CItemEnhancementStack::CalcActivateDelay (CItemCtx &DeviceCtx) const // CalcActivateDelay // // Calculates the activation delay (in ticks) for the given device if we apply // this enhancement stack. { int i; CInstalledDevice *pDevice = DeviceCtx.GetDevice(); if (pDevice == NULL) return 0; // Get the raw activation delay. NOTE: This DOES NOT include // any enhancements on the item. Metric rDelay = pDevice->GetClass()->GetActivateDelay(pDevice, DeviceCtx.GetSource()); // Apply enhancements (including on the item itself) for (i = 0; i < m_Stack.GetCount(); i++) { int iMin, iMax; int iAdj = m_Stack[i].GetActivateRateAdj(&iMin, &iMax); if (iAdj != 100) { rDelay = iAdj * rDelay / 100.0; if (rDelay < (Metric)iMin) rDelay = (Metric)iMin; else if (iMax > 0 && rDelay > (Metric)iMax) rDelay = (Metric)iMax; } } return (int)(rDelay + 0.5); }
bool CDeviceClass::SetItemProperty (CItemCtx &Ctx, const CString &sName, ICCItem *pValue, CString *retsError) // SetItemProperty // // Sets a device property. Subclasses should call this if they do not // understand the property. { CCodeChain &CC = g_pUniverse->GetCC(); // Get the installed device. We need this to set anything. CInstalledDevice *pDevice = Ctx.GetDevice(); if (pDevice == NULL) { *retsError = CONSTLIT("Item is not an installed device on object."); return false; } // Figure out what to set if (strEquals(sName, PROPERTY_FIRE_ARC)) { // A value of nil means no fire arc (and no omni) if (pValue == NULL || pValue->IsNil()) { pDevice->SetOmniDirectional(false); pDevice->SetFireArc(0, 0); } // A value of "omnidirectional" counts else if (strEquals(pValue->GetStringValue(), PROPERTY_OMNIDIRECTIONAL)) { pDevice->SetOmniDirectional(true); pDevice->SetFireArc(0, 0); } // A single value means that we just point in a direction else if (pValue->GetCount() == 1) { int iMinFireArc = AngleMod(pValue->GetElement(0)->GetIntegerValue()); pDevice->SetOmniDirectional(false); pDevice->SetFireArc(iMinFireArc, iMinFireArc); } // Otherwise we expect a list with two elements else if (pValue->GetCount() >= 2) { int iMinFireArc = AngleMod(pValue->GetElement(0)->GetIntegerValue()); int iMaxFireArc = AngleMod(pValue->GetElement(1)->GetIntegerValue()); pDevice->SetOmniDirectional(false); pDevice->SetFireArc(iMinFireArc, iMaxFireArc); } // Invalid else { *retsError = CONSTLIT("Invalid fireArc parameter."); return false; } } else if (strEquals(sName, PROPERTY_LINKED_FIRE_OPTIONS)) { // Parse the options DWORD dwOptions; if (!::GetLinkedFireOptions(pValue, &dwOptions, retsError)) return false; // Set pDevice->SetLinkedFireOptions(dwOptions); } else if (strEquals(sName, PROPERTY_POS)) { // Get the parameters. We accept a single list parameter with angle/radius/z. // (The latter is compatible with the return of objGetDevicePos.) int iPosAngle; int iPosRadius; int iZ; if (pValue == NULL || pValue->IsNil()) { iPosAngle = 0; iPosRadius = 0; iZ = 0; } else if (pValue->GetCount() >= 2) { iPosAngle = pValue->GetElement(0)->GetIntegerValue(); iPosRadius = pValue->GetElement(1)->GetIntegerValue(); if (pValue->GetCount() >= 3) iZ = pValue->GetElement(2)->GetIntegerValue(); else iZ = 0; } else { *retsError = CONSTLIT("Invalid angle and radius"); return false; } // Set it pDevice->SetPosAngle(iPosAngle); pDevice->SetPosRadius(iPosRadius); pDevice->SetPosZ(iZ); } else if (strEquals(sName, PROPERTY_SECONDARY)) { if (pValue == NULL || !pValue->IsNil()) pDevice->SetSecondary(true); else pDevice->SetSecondary(false); } else { *retsError = strPatternSubst(CONSTLIT("Unknown item property: %s."), sName); return false; } return true; }