ALERROR CConquerNodesProc::LoadNodeWeightTable (SDesignLoadCtx &Ctx, CXMLElement *pDesc, TArray<SNodeWeight> *retTable) // LoadNodeWeightTable // // Loads a node criteria/weight table { ALERROR error; int i; // OK if NULL; it means the element is missing if (pDesc == NULL) return NOERROR; // Load for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pChanceXML = pDesc->GetContentElement(i); SNodeWeight *pChance = retTable->Insert(); if (error = CTopologyNode::ParseCriteria(pChanceXML->GetAttribute(CRITERIA_ATTRIB), &pChance->Criteria, &Ctx.sError)) return error; pChance->iWeight = pChanceXML->GetAttributeIntegerBounded(WEIGHT_ATTRIB, 0, -1, 1); pChance->iSuccessChance = pChanceXML->GetAttributeIntegerBounded(SUCCESS_CHANCE_ATTRIB, 0, 100, 100); } return NOERROR; }
ALERROR CGroupOfDeviceGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // LoadFromXML // // Load from XML { int i; ALERROR error; m_Count.LoadFromXML(pDesc->GetAttribute(COUNT_ATTRIB)); if (m_Count.IsEmpty()) m_Count.SetConstant(1); // Load either a <DeviceSlot> element or another device generator. for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pEntry = pDesc->GetContentElement(i); if (strEquals(pEntry->GetTag(), DEVICE_SLOT_TAG)) { SSlotDesc *pSlotDesc = m_SlotDesc.Insert(); CItem::ParseCriteria(pEntry->GetAttribute(CRITERIA_ATTRIB), &pSlotDesc->Criteria); if (error = IDeviceGenerator::InitDeviceDescFromXML(Ctx, pEntry, &pSlotDesc->DefaultDesc)) return error; pSlotDesc->iMaxCount = pEntry->GetAttributeIntegerBounded(MAX_COUNT_ATTRIB, 0, -1, -1); } else { SEntry *pTableEntry = m_Table.Insert(); pTableEntry->iChance = pEntry->GetAttributeIntegerBounded(CHANCE_ATTRIB, 0, -1, 100); if (error = IDeviceGenerator::CreateFromXML(Ctx, pEntry, &pTableEntry->pDevice)) { pTableEntry->pDevice = NULL; return error; } } } return NOERROR; }
ALERROR CIntegralRotationDesc::InitFromXML (SDesignLoadCtx &Ctx, const CString &sUNID, CXMLElement *pDesc) // InitFromXML // // Initialize from an XML descriptor { // If we have a Maneuver element, then use that (and ignore other attributes) CXMLElement *pManeuver = pDesc->GetContentElementByTag(MANEUVER_TAG); if (pManeuver) { m_iManeuverability = 0; m_iCount = pManeuver->GetAttributeIntegerBounded(ROTATION_COUNT_ATTRIB, 1, -1, STD_ROTATION_COUNT); // Max rotation rate is in degrees per tick. Later we convert that to rotation frames per tick // (but not until we figure out the number of rotation frames). m_rDegreesPerTick = pManeuver->GetAttributeDoubleBounded(MAX_ROTATION_RATE_ATTRIB, 0.01, -1.0, 360.0 / STD_ROTATION_COUNT); // Also convert rotation acceleration m_rAccelPerTick = pManeuver->GetAttributeDoubleBounded(ROTATION_ACCEL_ATTRIB, 0.01, -1.0, m_rDegreesPerTick); m_rAccelPerTickStop = pManeuver->GetAttributeDoubleBounded(ROTATION_STOP_ACCEL_ATTRIB, 0.01, -1.0, m_rAccelPerTick); } // Otherwise we look for attributes on the root (this is backwards compatible // with version prior to API 20 else { m_iCount = pDesc->GetAttributeIntegerBounded(ROTATION_COUNT_ATTRIB, 1, -1, STD_ROTATION_COUNT); // The original maneuverability value is the number of half-ticks that // we take per rotation frame. // // NOTE: For compatibility we don't allow maneuverability less than 2, which was the // limit using the old method (1 tick delay). m_iManeuverability = pDesc->GetAttributeIntegerBounded(MANEUVER_ATTRIB, 2, -1, 2); // Convert that to degrees per tick m_rDegreesPerTick = (m_iCount > 0 ? (STD_SECONDS_PER_UPDATE * 360.0) / (m_iCount * m_iManeuverability) : 0.0); // Default acceleration is equal to rotation rate m_rAccelPerTick = m_rDegreesPerTick; m_rAccelPerTickStop = m_rDegreesPerTick; } return NOERROR; }
ALERROR CTableEntry::InitFromXML (SDesignLoadCtx &Ctx, CIDCounter &IDGen, CXMLElement *pDesc) // InitFromXML // // Initialize from XML { ALERROR error; int i; m_dwID = IDGen.GetID(); // Load each sub-entry in turn int iCount = pDesc->GetContentElementCount(); if (iCount == 0) return NOERROR; m_iTotalChance = 0; m_Table.InsertEmpty(iCount); for (i = 0; i < iCount; i++) { CXMLElement *pItem = pDesc->GetContentElement(i); if (error = CCompositeImageDesc::InitEntryFromXML(Ctx, pItem, IDGen, &m_Table[i].pImage)) return error; // Load the chance m_Table[i].iChance = pItem->GetAttributeIntegerBounded(CHANCE_ATTRIB, 0, -1, 1); m_iTotalChance += m_Table[i].iChance; } // Done return NOERROR; }
ALERROR CTopologyNode::ParseCriteria (CXMLElement *pCrit, SCriteria *retCrit, CString *retsError) // ParseCriteria // // Parses an XML element into a criteria desc { int i; retCrit->iChance = 100; retCrit->iMaxInterNodeDist = -1; retCrit->iMinInterNodeDist = 0; retCrit->iMaxStargates = -1; retCrit->iMinStargates = 0; if (pCrit) { for (i = 0; i < pCrit->GetContentElementCount(); i++) { CXMLElement *pItem = pCrit->GetContentElement(i); if (strEquals(pItem->GetTag(), ATTRIBUTES_TAG)) { CString sCriteria = pItem->GetAttribute(CRITERIA_ATTRIB); ParseCriteriaInt(sCriteria, retCrit); } else if (strEquals(pItem->GetTag(), CHANCE_TAG)) { retCrit->iChance = pItem->GetAttributeIntegerBounded(CHANCE_ATTRIB, 0, 100, 100); } else if (strEquals(pItem->GetTag(), DISTANCE_BETWEEN_NODES_TAG)) { retCrit->iMinInterNodeDist = pItem->GetAttributeIntegerBounded(MIN_ATTRIB, 0, -1, 0); retCrit->iMaxInterNodeDist = pItem->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, -1); } else if (strEquals(pItem->GetTag(), DISTANCE_TO_TAG)) { SDistanceTo *pDistTo = retCrit->DistanceTo.Insert(); pDistTo->iMinDist = pItem->GetAttributeIntegerBounded(MIN_ATTRIB, 0, -1, 0); pDistTo->iMaxDist = pItem->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, -1); CString sCriteria; if (pItem->FindAttribute(CRITERIA_ATTRIB, &sCriteria)) { SCriteria Criteria; if (ParseCriteriaInt(sCriteria, &Criteria) != NOERROR) { *retsError = strPatternSubst(CONSTLIT("Unable to parse criteria: %s"), sCriteria); return ERR_FAIL; } pDistTo->AttribsRequired = Criteria.AttribsRequired; pDistTo->AttribsNotAllowed = Criteria.AttribsNotAllowed; } else pDistTo->sNodeID = pItem->GetAttribute(NODE_ID_ATTRIB); } else if (strEquals(pItem->GetTag(), STARGATE_COUNT_TAG)) { retCrit->iMinStargates = pItem->GetAttributeIntegerBounded(MIN_ATTRIB, 0, -1, 0); retCrit->iMaxStargates = pItem->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, -1); } else { *retsError = strPatternSubst(CONSTLIT("Unknown criteria element: %s"), pItem->GetTag()); return ERR_FAIL; } } } return NOERROR; }
bool IDockScreenDisplay::GetDisplayOptions (SInitCtx &Ctx, SDisplayOptions *retOptions, CString *retsError) // GetDisplayOptions // // Initializes the display options structure, which is used by list and // selector displays. { // Initialize background image options CString sBackgroundID; if (Ctx.pDesc->FindAttribute(BACKGROUND_ID_ATTRIB, &sBackgroundID)) { // If the attribute exists, but is empty (or equals "none") then // we don't have a background if (sBackgroundID.IsBlank() || strEquals(sBackgroundID, CONSTLIT("none"))) retOptions->BackgroundDesc.iType = backgroundNone; else if (strEquals(sBackgroundID, TYPE_HERO)) { retOptions->BackgroundDesc.iType = backgroundObjHeroImage; retOptions->BackgroundDesc.pObj = Ctx.pLocation; } // If the ID is "object" then we should ask the object else if (strEquals(sBackgroundID, TYPE_OBJECT)) { retOptions->BackgroundDesc.pObj = Ctx.pLocation; if (Ctx.pLocation->IsPlayer()) retOptions->BackgroundDesc.iType = backgroundObjSchematicImage; else retOptions->BackgroundDesc.iType = backgroundObjHeroImage; } else if (strEquals(sBackgroundID, TYPE_SCHEMATIC)) { retOptions->BackgroundDesc.iType = backgroundObjSchematicImage; retOptions->BackgroundDesc.pObj = Ctx.pLocation; } // If the ID is "player" then we should ask the player ship else if (strEquals(sBackgroundID, DATA_FROM_PLAYER)) { CSpaceObject *pPlayer = g_pUniverse->GetPlayerShip(); if (pPlayer) { retOptions->BackgroundDesc.iType = backgroundObjSchematicImage; retOptions->BackgroundDesc.pObj = pPlayer; } } // Otherwise, we expect an integer else { retOptions->BackgroundDesc.iType = backgroundImage; retOptions->BackgroundDesc.dwImageID = strToInt(sBackgroundID, 0); } } // Initialize control rect. If we have a background, then initialize to // backwards compatible position. Otherwise, we take up the full range. if (retOptions->BackgroundDesc.iType != backgroundDefault) { retOptions->rcControl.left = 4; retOptions->rcControl.top = 12; retOptions->rcControl.right = 548; retOptions->rcControl.bottom = 396; } else { retOptions->rcControl.left = 0; retOptions->rcControl.top = 23; retOptions->rcControl.right = 600; retOptions->rcControl.bottom = 482; } // There are a couple of different ways to get options (for backwards // compatibility). CXMLElement *pOptions; if ((pOptions = Ctx.pDesc->GetContentElementByTag(LIST_OPTIONS_TAG)) == NULL && (pOptions = Ctx.pDesc->GetContentElementByTag(LIST_TAG)) == NULL) return true; // Read from the element retOptions->sDataFrom = pOptions->GetAttribute(DATA_FROM_ATTRIB); retOptions->sItemCriteria = pOptions->GetAttribute(LIST_ATTRIB); retOptions->sCode = pOptions->GetContentText(0); retOptions->sInitialItemCode = pOptions->GetAttribute(INITIAL_ITEM_ATTRIB); retOptions->sRowHeightCode = pOptions->GetAttribute(ROW_HEIGHT_ATTRIB); // See if we have control position if (pOptions->FindAttributeInteger(POS_X_ATTRIB, (int *)&retOptions->rcControl.left)) { retOptions->rcControl.top = pOptions->GetAttributeIntegerBounded(POS_Y_ATTRIB, 0, -1); retOptions->rcControl.right = retOptions->rcControl.left + pOptions->GetAttributeIntegerBounded(WIDTH_ATTRIB, 0, -1); retOptions->rcControl.bottom = retOptions->rcControl.top + pOptions->GetAttributeIntegerBounded(HEIGHT_ATTRIB, 0, -1); } return true; }
void GenerateEffectImage (CUniverse &Universe, CXMLElement *pCmdLine) { CString sError; int i, j; // Input file CString sInput = pCmdLine->GetAttribute(CONSTLIT("input")); if (sInput.IsBlank()) { printf("Input file required.\n"); return; } // Output file (optional) CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("output")); if (!sFilespec.IsBlank()) sFilespec = pathAddExtensionIfNecessary(sFilespec, CONSTLIT(".bmp")); // Load a resource file so that we can create a design load context CResourceDb Resources(CONSTLIT("Transcendence")); if (Resources.Open(DFOPEN_FLAG_READ_ONLY, &sError) != NOERROR) { printf("%s\n", (LPSTR)sError); return; } CExternalEntityTable *pEntities; if (Resources.LoadEntities(&sError, &pEntities) != NOERROR) { printf("%s\n", sError.GetASCIIZPointer()); return; } // Generate a list of effect render structures TArray<SEffectRender> Effects; // Load the input file CFileReadBlock InputFile(sInput); if (InputFile.Open() != NOERROR) { printf("Unable to open input file: %s\n", sInput.GetASCIIZPointer()); return; } // Parse the file CXMLElement *pRenderFile; if (CXMLElement::ParseXML(&InputFile, pEntities, &pRenderFile, &sError) != NOERROR) { printf("%s\n", sError.GetASCIIZPointer()); return; } // Keep track of the max cell size and frame count int cxCellWidth = 0; int cyCellHeight = 0; int iCellsPerEffect = 1; // Generate structures SDesignLoadCtx LoadCtx; LoadCtx.sResDb = Resources.GetFilespec(); LoadCtx.pResDb = &Resources; LoadCtx.bNoVersionCheck = true; for (i = 0; i < pRenderFile->GetContentElementCount(); i++) { CXMLElement *pRender = pRenderFile->GetContentElement(i); CXMLElement *pEffectDesc = pRender->GetContentElementByTag(CONSTLIT("Effect")); if (pEffectDesc == NULL) { printf("<Effect> tag required.\n"); return; } SEffectRender *pEffect = Effects.Insert(); // Parse the effect if (pEffect->pEffectCreator.LoadEffect(LoadCtx, CONSTLIT("none"), pEffectDesc, NULL_STR) != NOERROR) { printf("%s\n", LoadCtx.sError.GetASCIIZPointer()); return; } // Bind if (pEffect->pEffectCreator.Bind(LoadCtx) != NOERROR) { printf("%s\n", LoadCtx.sError.GetASCIIZPointer()); return; } // Create a painter pEffect->pPainter = pEffect->pEffectCreator->CreatePainter(); if (pEffect->pPainter == NULL) { printf("Unable to create painter.\n"); return; } // Render specs int cyHeight = pRender->GetAttributeIntegerBounded(CONSTLIT("height"), 0, -1, 128); int cxWidth = pRender->GetAttributeIntegerBounded(CONSTLIT("width"), 0, -1, 128); cxCellWidth = Max(cxCellWidth, cxWidth); cyCellHeight = Max(cyCellHeight, cyHeight); // Figure out how many animation cells pEffect->iLifetime = Max(1, pEffect->pEffectCreator->GetLifetime()); iCellsPerEffect = Max(iCellsPerEffect, pEffect->iLifetime); } // Create the resulting image CImageGrid Output; Output.Create(iCellsPerEffect * Effects.GetCount(), cxCellWidth, cyCellHeight); // Paint for (i = 0; i < Effects.GetCount(); i++) { SEffectRender *pEffect = &Effects[i]; SViewportPaintCtx Ctx; for (j = 0; j < pEffect->iLifetime; j++) { int x, y; Output.GetCellCenter(i * iCellsPerEffect + j, &x, &y); // Create a context Ctx.iTick = j; // Paint the effect pEffect->pPainter->Paint(Output.GetImage(), x, y, Ctx); // Update pEffect->pPainter->OnUpdate(); } } // Output OutputImage(Output.GetImage(), sFilespec); }
void CDockingPorts::InitPortsFromXML (CSpaceObject *pOwner, CXMLElement *pElement) // InitPortsFromXML // // InitPortsFromXML { int i; // See if we've got a special element with docking port geometry CXMLElement *pDockingPorts = pElement->GetContentElementByTag(DOCKING_PORTS_TAG); if (pDockingPorts) { // Initialize max dist // NOTE: pOwner can be NULL because sometimes we init ports from a ship class // (without an object). int iDefaultDist = Max(DEFAULT_DOCK_DISTANCE_LS, (pOwner ? 8 + (int)((pOwner->GetBoundsRadius() / LIGHT_SECOND) + 0.5) : 0)); m_iMaxDist = pDockingPorts->GetAttributeIntegerBounded(MAX_DIST_ATTRIB, 1, -1, iDefaultDist); // If we have sub-elements then these are port definitions. m_iPortCount = pDockingPorts->GetContentElementCount(); if (m_iPortCount > 0) { m_pPort = new SDockingPort[m_iPortCount]; for (i = 0; i < m_iPortCount; i++) { CXMLElement *pPort = pDockingPorts->GetContentElement(i); CVector vDockPos((pPort->GetAttributeInteger(X_ATTRIB) * g_KlicksPerPixel), (pPort->GetAttributeInteger(Y_ATTRIB) * g_KlicksPerPixel)); m_pPort[i].vPos = vDockPos; if (pPort->FindAttributeInteger(ROTATION_ATTRIB, &m_pPort[i].iRotation)) m_pPort[i].iRotation = (m_pPort[i].iRotation % 360); else m_pPort[i].iRotation = (VectorToPolar(vDockPos) + 180) % 360; if (pPort->GetAttributeBool(BRING_TO_FRONT_ATTRIB)) m_pPort[i].iLayer = plBringToFront; else if (pPort->GetAttributeBool(SEND_TO_BACK_ATTRIB)) m_pPort[i].iLayer = plSendToBack; } } // Otherwise, we expect a port count and radius else if ((m_iPortCount = pDockingPorts->GetAttributeIntegerBounded(PORT_COUNT_ATTRIB, 0, -1, 0)) > 0) { int iRadius = pDockingPorts->GetAttributeIntegerBounded(PORT_RADIUS_ATTRIB, 0, -1, DEFAULT_PORT_POS_RADIUS); int iAngle = 360 / m_iPortCount; // We need the image scale to adjust coordinates int iScale = (pOwner ? pOwner->GetImage().GetImageViewportSize() : 512); // Initialize ports m_pPort = new SDockingPort[m_iPortCount]; for (i = 0; i < m_iPortCount; i++) { C3DConversion::CalcCoord(iScale, i * iAngle, iRadius, 0, &m_pPort[i].vPos); m_pPort[i].iRotation = ((i * iAngle) + 180) % 360; } } // Otherwise, no ports else { m_iPortCount = 0; m_pPort = NULL; } } // Otherwise, initialize ports based on a count else InitPorts(pOwner, pElement->GetAttributeInteger(DOCKING_PORTS_ATTRIB), 64 * g_KlicksPerPixel); }
void CDockingPorts::InitPortsFromXML (CSpaceObject *pOwner, CXMLElement *pElement) // InitPortsFromXML // // InitPortsFromXML { int i; // See if we've got a special element with docking port geometry CXMLElement *pDockingPorts = pElement->GetContentElementByTag(DOCKING_PORTS_TAG); if (pDockingPorts) { // Initialize max dist m_iMaxDist = pDockingPorts->GetAttributeIntegerBounded(MAX_DIST_ATTRIB, 1, -1, DEFAULT_DOCK_DISTANCE_LS); // If we have sub-elements then these are port definitions. m_iPortCount = pDockingPorts->GetContentElementCount(); if (m_iPortCount > 0) { m_pPort = new DockingPort[m_iPortCount]; for (i = 0; i < m_iPortCount; i++) { CXMLElement *pPort = pDockingPorts->GetContentElement(i); CVector vDockPos((pPort->GetAttributeInteger(X_ATTRIB) * g_KlicksPerPixel), (pPort->GetAttributeInteger(Y_ATTRIB) * g_KlicksPerPixel)); m_pPort[i].iStatus = psEmpty; m_pPort[i].pObj = NULL; m_pPort[i].vPos = vDockPos; if (pPort->FindAttributeInteger(ROTATION_ATTRIB, &m_pPort[i].iRotation)) m_pPort[i].iRotation = (m_pPort[i].iRotation % 360); else m_pPort[i].iRotation = (VectorToPolar(vDockPos) + 180) % 360; } } // Otherwise, we expect a port count and radius else if ((m_iPortCount = pDockingPorts->GetAttributeIntegerBounded(PORT_COUNT_ATTRIB, 0, -1, 0)) > 0) { m_pPort = new DockingPort[m_iPortCount]; int iRadius = pDockingPorts->GetAttributeIntegerBounded(PORT_RADIUS_ATTRIB, 0, -1, DEFAULT_PORT_POS_RADIUS); Metric rRadius = g_KlicksPerPixel * iRadius; int iAngle = 360 / m_iPortCount; for (i = 0; i < m_iPortCount; i++) { m_pPort[i].iStatus = psEmpty; m_pPort[i].pObj = NULL; m_pPort[i].vPos = PolarToVector(i * iAngle, rRadius); m_pPort[i].iRotation = ((i * iAngle) + 180) % 360; } } // Otherwise, no ports else { m_iPortCount = 0; m_pPort = NULL; } } // Otherwise, initialize ports based on a count else InitPorts(pOwner, pElement->GetAttributeInteger(DOCKING_PORTS_ATTRIB), 64 * g_KlicksPerPixel); }
ALERROR CConquerNodesProc::OnInitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, const CString &sUNID) // OnInitFromXML // // Initialize from XML element { ALERROR error; int i; // Initialize criteria CTopologyNode::ParseCriteria(NULL, &m_Criteria); // Loop over all elements for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); // If we have a criteria, parse it and remember it // (Note: If multiple criteria are found, we take the latest one). if (strEquals(pItem->GetTag(), CRITERIA_TAG)) { // Parse the filter if (error = CTopologyNode::ParseCriteria(pItem, &m_Criteria, &Ctx.sError)) return error; } // Otherwise, treat it as a conqueror definition and insert it in the list else { CString sNewUNID = strPatternSubst(CONSTLIT("%s/%d"), sUNID, m_Conquerors.GetCount()); SConqueror *pConqueror = m_Conquerors.Insert(); // Get some properties pConqueror->iSeedChance = pItem->GetAttributeIntegerBounded(SEED_CHANCE_ATTRIB, 1, 100, 1); pConqueror->iMaxSeeds = pItem->GetAttributeIntegerBounded(MAX_SEEDS_ATTRIB, 1, -1, 1); pConqueror->iExpandChance = pItem->GetAttributeIntegerBounded(EXPAND_CHANCE_ATTRIB, 1, 100, 1); pConqueror->iMaxNodes = pItem->GetAttributeIntegerBounded(MAX_NODES_ATTRIB, 1, -1, 1); // Get the seed and expand probabilities if (error = LoadNodeWeightTable(Ctx, pItem->GetContentElementByTag(SEED_CHANCE_TAG), &pConqueror->Seed)) return error; if (error = LoadNodeWeightTable(Ctx, pItem->GetContentElementByTag(EXPAND_CHANCE_TAG), &pConqueror->Expand)) return error; // Get the processor itself CXMLElement *pProcXML = pItem->GetContentElementByTag(PROCESSOR_TAG); if (pProcXML) { if (error = ITopologyProcessor::CreateFromXMLAsGroup(Ctx, pProcXML, sNewUNID, &pConqueror->pProc)) return error; } else { Ctx.sError = CONSTLIT("<Processor> element not found in <ConquerNodes>"); return ERR_FAIL; } } } return NOERROR; }
ALERROR COverlayType::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Create from XML { ALERROR error; // Effect CXMLElement *pEffect = pDesc->GetContentElementByTag(EFFECT_TAG); if (pEffect) { if (error = CEffectCreator::CreateFromXML(Ctx, pEffect, strPatternSubst(CONSTLIT("%d:e"), GetUNID()), &m_pEffect)) { Ctx.sError = strPatternSubst(CONSTLIT("energy field %x: Unable to load effect"), GetUNID()); return error; } } pEffect = pDesc->GetContentElementByTag(HIT_EFFECT_TAG); if (pEffect == NULL) pEffect = pDesc->GetContentElementByTag(EFFECT_WHEN_HIT_TAG); if (pEffect) { if (error = CEffectCreator::CreateFromXML(Ctx, pEffect, strPatternSubst(CONSTLIT("%d:h"), GetUNID()), &m_pHitEffect)) { Ctx.sError = strPatternSubst(CONSTLIT("energy field %x: Unable to load hit effect"), GetUNID()); return error; } // For compatibility with previous versions, if we're using the old // <ShipEnergyFieldType> then altEffect defaults to TRUE. Otherwise, for new // <OverlayType> altEffect defaults to false. bool bAltEffect; if (pEffect->FindAttributeBool(ALT_EFFECT_ATTRIB, &bAltEffect)) m_fAltHitEffect = bAltEffect; else m_fAltHitEffect = strEquals(pDesc->GetTag(), SHIP_ENERGY_FIELD_TYPE_TAG); } else m_fAltHitEffect = false; // Rotation m_fRotateWithShip = !pDesc->GetAttributeBool(IGNORE_SHIP_ROTATION_ATTRIB); // Damage adjustment int iAbsorbCount; LoadDamageAdj(pDesc, ABSORB_ADJ_ATTRIB, m_iAbsorbAdj, &iAbsorbCount); // Bonus adjustment LoadDamageAdj(pDesc, BONUS_ADJ_ATTRIB, m_iBonusAdj); // Load the weapon suppress if (error = m_WeaponSuppress.InitFromXML(pDesc->GetAttribute(WEAPON_SUPPRESS_ATTRIB))) { Ctx.sError = CONSTLIT("Unable to load weapon suppress attribute"); return error; } // Keep track of the events that we have m_fHasOnUpdateEvent = FindEventHandler(ON_UPDATE_EVENT); // Are we a field/shield overlay (or part of hull)? // By default, we are a shield overlay if we absorb damage. bool bValue; if (pDesc->FindAttributeBool(SHIELD_OVERLAY_ATTRIB, &bValue)) m_fShieldOverlay = bValue; else m_fShieldOverlay = (iAbsorbCount > 0); // Counter CXMLElement *pCounter = pDesc->GetContentElementByTag(COUNTER_TAG); if (pCounter) { CString sStyle = pCounter->GetAttribute(STYLE_ATTRIB); if (strEquals(sStyle, COUNTER_PROGRESS)) m_iCounterType = counterProgress; else if (strEquals(sStyle, COUNTER_RADIUS)) m_iCounterType = counterRadius; else { Ctx.sError = strPatternSubst(CONSTLIT("Unknown counter style: %s"), sStyle); return ERR_FAIL; } m_sCounterLabel = pCounter->GetAttribute(LABEL_ATTRIB); m_iCounterMax = pCounter->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, 100); m_wCounterColor = ::LoadRGBColor(pCounter->GetAttribute(COLOR_ATTRIB)); } else { m_iCounterType = counterNone; m_iCounterMax = 0; m_wCounterColor = 0; } // Options m_fDisarmShip = pDesc->GetAttributeBool(DISARM_ATTRIB); m_fParalyzeShip = pDesc->GetAttributeBool(PARALYZE_ATTRIB); m_fDisableShipScreen = pDesc->GetAttributeBool(DISABLE_SHIP_SCREEN_ATTRIB); m_fSpinShip = pDesc->GetAttributeBool(SPIN_ATTRIB); int iDrag; if (pDesc->FindAttributeInteger(DRAG_ATTRIB, &iDrag)) m_rDrag = Min(Max(0, iDrag), 100) / 100.0; else m_rDrag = 1.0; // Done return NOERROR; }