ALERROR CTopologyNode::InitFromSystemXML (CXMLElement *pSystem, CString *retsError) // InitFromSystemXML // // Initializes the system information based on an XML element. // NOTE: We assume the universe is fully bound at this point. { ALERROR error; CString sSystemUNID = pSystem->GetAttribute(UNID_ATTRIB); DWORD dwUNID = strToInt(sSystemUNID, 0, NULL); // If the system node contains a table of different system types, then // remember the root node because some of the system information (such as the // name) may be there. CXMLElement *pSystemParent = NULL; // If there is no UNID attribute then it means that the system // is randomly determined based on a table if (dwUNID == 0 && pSystem->GetContentElementCount() == 1) { CXMLElement *pTableElement = pSystem->GetContentElement(0); if (pTableElement == NULL) { ASSERT(false); return ERR_FAIL; } CRandomEntryResults System; if (error = CRandomEntryGenerator::Generate(pTableElement, System)) { *retsError = strPatternSubst(CONSTLIT("Topology %s: Unable to generate random system UNID"), m_sID); return ERR_FAIL; } if (System.GetCount() != 1) { *retsError = strPatternSubst(CONSTLIT("Topology %s: Table generated no systems"), m_sID); return ERR_FAIL; } pSystemParent = pSystem; pSystem = System.GetResult(0); dwUNID = pSystem->GetAttributeInteger(UNID_ATTRIB); } // Set the system UNID if (dwUNID != 0) m_SystemUNID = dwUNID; // Get the system type CSystemType *pSystemType = g_pUniverse->FindSystemType(m_SystemUNID); // Set the name of the system CString sName; if (!pSystem->FindAttribute(NAME_ATTRIB, &sName)) if (pSystemParent) sName = pSystemParent->GetAttribute(NAME_ATTRIB); if (!sName.IsBlank()) SetName(sName); // Set the level int iLevel = 0; if (!pSystem->FindAttributeInteger(LEVEL_ATTRIB, &iLevel)) if (pSystemParent) iLevel = pSystemParent->GetAttributeInteger(LEVEL_ATTRIB); if (iLevel > 0) SetLevel(iLevel); if (GetLevel() == 0) SetLevel(1); // Add variants for the system CString sVariant; if (pSystem->FindAttribute(VARIANT_ATTRIB, &sVariant)) AddVariantLabel(sVariant); if (pSystemParent && pSystemParent->FindAttribute(VARIANT_ATTRIB, &sVariant)) AddVariantLabel(sVariant); // Add attributes for the node/system CString sAttribs; if (pSystem->FindAttribute(ATTRIBUTES_ATTRIB, &sAttribs)) AddAttributes(sAttribs); if (pSystemParent && pSystemParent->FindAttribute(ATTRIBUTES_ATTRIB, &sAttribs)) AddAttributes(sAttribs); if (pSystemType && !pSystemType->GetAttributes().IsBlank()) AddAttributes(pSystemType->GetAttributes()); 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; }
ALERROR WriteModule (CTDBCompiler &Ctx, const CString &sFilename, const CString &sFolder, CDataFile &Out, int *retiModuleEntry, bool bCore) { ALERROR error; int i; // Parse the file CXMLElement *pModule; CExternalEntityTable *pEntityTable = new CExternalEntityTable; CFileReadBlock DataFile(pathAddComponent(Ctx.GetRootPath(), sFilename)); CString sError; printf("Parsing %s...", sFilename.GetASCIIZPointer()); if (error = CXMLElement::ParseXML(&DataFile, Ctx.GetCoreEntities(), &pModule, &sError, pEntityTable)) { printf("\n"); Ctx.ReportError(sError); return error; } // If this is a core module (embedded in the root XML) then we add these // entities to the core. [Ctx takes ownership.] if (bCore) Ctx.AddEntityTable(pEntityTable); // Chain entity tables (so that any modules that we load get the benefit). // This will chain Ctx.pCoreEntities (and restore it in the destructor). // // NOTE: If this is a core module, then we don't do this, since we've // already added the entities to the context block. CSaveEntitiesTable SavedEntities(Ctx, (!bCore ? pEntityTable : NULL)); printf("done.\n"); // Compress if this is NOT the main file. We can't compress the // main file because we sometimes need to read it partially. bool bCompress = (retiModuleEntry == NULL); // Write the module itself int iEntry; if (error = WriteGameFile(Ctx, sFilename, bCompress, Out, &iEntry)) return error; // If the caller doesn't want the module entry, then it means that this is // a module (instead of the main file). If so, add it to the resources table if (retiModuleEntry == NULL) Ctx.AddResource(sFilename, iEntry, bCompress); // Store all the image resources if (error = WriteModuleImages(Ctx, pModule, sFolder, Out)) return error; // Store all the sound resources if (error = WriteModuleSounds(Ctx, pModule, sFolder, Out)) return error; // Store all modules if (error = WriteSubModules(Ctx, pModule, sFolder, Out)) return error; // The root module may have a TranscendenceAdventure tag with modules in it for (i = 0; i < pModule->GetContentElementCount(); i++) { CXMLElement *pItem = pModule->GetContentElement(i); if (strEquals(pItem->GetTag(), TAG_CORE_LIBRARY) || strEquals(pItem->GetTag(), TAG_TRANSCENDENCE_ADVENTURE) || strEquals(pItem->GetTag(), TAG_TRANSCENDENCE_LIBRARY)) { // If we have a filename, then we need to save the target as a // module. CString sFilename; if (pItem->FindAttribute(ATTRIB_FILENAME, &sFilename)) { // Write out the module, making sure to set the core flag. if (error = WriteModule(Ctx, sFilename, sFolder, Out, NULL, true)) return error; // We ignore any other elements. continue; } // Store all the image resources if (error = WriteModuleImages(Ctx, pItem, sFolder, Out)) return error; // Store all the sound resources if (error = WriteModuleSounds(Ctx, pItem, sFolder, Out)) return error; // Modules if (error = WriteSubModules(Ctx, pItem, sFolder, Out)) return error; } } // Done if (retiModuleEntry) *retiModuleEntry = iEntry; return NOERROR; }
ALERROR CDeviceClass::InitDeviceFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, CItemType *pType) // InitDeviceFromXML // // Initializes the device class base { int i; ALERROR error; m_pItemType = pType; // Number of slots that the device takes up (if the attribute is missing // then we assume 1) CString sAttrib; if (pDesc->FindAttribute(DEVICE_SLOTS_ATTRIB, &sAttrib)) m_iSlots = strToInt(sAttrib, 1, NULL); else m_iSlots = 1; // Slot type CString sSlotType; if (pDesc->FindAttribute(CATEGORY_ATTRIB, &sSlotType) || pDesc->FindAttribute(DEVICE_SLOT_CATEGORY_ATTRIB, &sSlotType)) { if (!CItemType::ParseItemCategory(sSlotType, &m_iSlotCategory)) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid deviceSlotCategory: %s."), sSlotType); return ERR_FAIL; } // Make sure it is a valid device switch (m_iSlotCategory) { // OK case itemcatCargoHold: case itemcatDrive: case itemcatLauncher: case itemcatMiscDevice: case itemcatReactor: case itemcatShields: case itemcatWeapon: break; default: { Ctx.sError = strPatternSubst(CONSTLIT("Not a valid device category: %s."), sSlotType); return ERR_FAIL; } } } else // itemcatNone means use the actual item category m_iSlotCategory = itemcatNone; // Overlay if (error = m_pOverlayType.LoadUNID(Ctx, pDesc->GetAttribute(OVERLAY_TYPE_ATTRIB))) return error; // Other settings m_iMaxHPBonus = pDesc->GetAttributeIntegerBounded(MAX_HP_BONUS_ATTRIB, 0, -1, 150); m_fExternal = pDesc->GetAttributeBool(EXTERNAL_ATTRIB); // Does this device enhance other items? CXMLElement *pEnhanceList = pDesc->GetContentElementByTag(ENHANCE_ABILITIES_TAG); if (pEnhanceList) { m_Enhancements.InsertEmpty(pEnhanceList->GetContentElementCount()); for (i = 0; i < pEnhanceList->GetContentElementCount(); i++) { CXMLElement *pEnhancement = pEnhanceList->GetContentElement(i); m_Enhancements[i].sType = pEnhancement->GetAttribute(TYPE_ATTRIB); // Load the item criteria CString sCriteria; if (!pEnhancement->FindAttribute(CRITERIA_ATTRIB, &sCriteria)) sCriteria = CONSTLIT("*"); CItem::ParseCriteria(sCriteria, &m_Enhancements[i].Criteria); // Parse the enhancement itself if (error = m_Enhancements[i].Enhancement.InitFromDesc(Ctx, pEnhancement->GetAttribute(ENHANCEMENT_ATTRIB))) return error; } } return NOERROR; }
ALERROR CDockPane::CreateControls (CString *retsError) // CreateControls // // Creates controls based on the pane descriptor. We assume that m_pContainer has // already been created and is empty. { int i; // If there is a <Controls> element then use that to figure out what to // create. CXMLElement *pControls = m_pPaneDesc->GetContentElementByTag(CONTROLS_TAG); if (pControls) { for (i = 0; i < pControls->GetContentElementCount(); i++) { CXMLElement *pControlDef = pControls->GetContentElement(i); // Figure out the type EControlTypes iType; if (strEquals(pControlDef->GetTag(), COUNTER_TAG)) iType = controlCounter; else if (strEquals(pControlDef->GetTag(), ITEM_DISPLAY_TAG)) iType = controlItemDisplay; else if (strEquals(pControlDef->GetTag(), TEXT_TAG)) iType = controlDesc; else if (strEquals(pControlDef->GetTag(), TEXT_INPUT_TAG)) iType = controlTextInput; else { *retsError = strPatternSubst(CONSTLIT("Unknown control element: <%s>."), pControlDef->GetTag()); return ERR_FAIL; } // Get the ID CString sID; if (!pControlDef->FindAttribute(ID_ATTRIB, &sID)) { *retsError = strPatternSubst(CONSTLIT("Missing ID attrib for control element: <%s>."), pControlDef->GetTag()); return ERR_FAIL; } // Create the control CreateControl(iType, sID); } } // Otherwise we create default controls else { // Create the text description control CreateControl(controlDesc, DEFAULT_DESC_ID); // Create counter or input fields if (m_pPaneDesc->GetAttributeBool(SHOW_COUNTER_ATTRIB)) CreateControl(controlCounter, DEFAULT_COUNTER_ID); else if (m_pPaneDesc->GetAttributeBool(SHOW_TEXT_INPUT_ATTRIB)) CreateControl(controlTextInput, DEFAULT_TEXT_INPUT_ID); } return NOERROR; }
void InitStationTypeImage (SEntryDesc &Entry, CStationType *pStationType) { struct SSatImageDesc { const CObjectImageArray *pImage; CCompositeImageSelector Selector; int xOffset; int yOffset; }; int i; SSelectorInitCtx InitCtx; pStationType->SetImageSelector(InitCtx, &Entry.Selector); const CObjectImageArray *pMainImage = &pStationType->GetImage(Entry.Selector, CCompositeImageModifiers()); // If we have no satellites, then we can just return the single station // image. CXMLElement *pSatellites = pStationType->GetSatellitesDesc(); if (pSatellites == NULL) { Entry.pImage = pMainImage; return; } // Figure out the extents of the image RECT rcMainImage = pMainImage->GetImageRect(); RECT rcBounds; rcBounds.left = -(RectWidth(rcMainImage) / 2); rcBounds.top = -(RectHeight(rcMainImage) / 2); rcBounds.right = rcBounds.left + RectWidth(rcMainImage); rcBounds.bottom = rcBounds.top + RectHeight(rcMainImage); // Loop over all satellites and get metrics TArray<SSatImageDesc> SatImages; for (i = 0; i < pSatellites->GetContentElementCount(); i++) { CXMLElement *pSatDesc = pSatellites->GetContentElement(i); if (!pSatDesc->FindAttribute(SEGMENT_ATTRIB) || !strEquals(STATION_TAG, pSatDesc->GetTag())) continue; // Get the type of the satellite CStationType *pSatType = g_pUniverse->FindStationType(pSatDesc->GetAttributeInteger(TYPE_ATTRIB)); if (pSatType == NULL) continue; // Prepare the image for the satellite SSatImageDesc *pSatImage = SatImages.Insert(); pSatType->SetImageSelector(InitCtx, &pSatImage->Selector); // If we have an image variant, then set it int iVariant; if (pSatDesc->FindAttributeInteger(IMAGE_VARIANT_ATTRIB, &iVariant)) { IImageEntry *pRoot = pSatType->GetImage().GetRoot(); DWORD dwID = (pRoot ? pRoot->GetID() : DEFAULT_SELECTOR_ID); pSatImage->Selector.DeleteAll(); pSatImage->Selector.AddVariant(dwID, iVariant); } pSatImage->pImage = &pSatType->GetImage(pSatImage->Selector, CCompositeImageModifiers()); // Now get the offset pSatImage->xOffset = pSatDesc->GetAttributeInteger(X_OFFSET_ATTRIB); pSatImage->yOffset = pSatDesc->GetAttributeInteger(Y_OFFSET_ATTRIB); // Compute the satellite rect RECT rcSatImage = pSatImage->pImage->GetImageRect(); RECT rcSatBounds; rcSatBounds.left = pSatImage->xOffset - (RectWidth(rcSatImage) / 2); rcSatBounds.top = -pSatImage->yOffset - (RectHeight(rcSatImage) / 2); rcSatBounds.right = rcSatBounds.left + RectWidth(rcSatImage); rcSatBounds.bottom = rcSatBounds.top + RectHeight(rcSatImage); // Increase the size of the bounds rcBounds.left = Min(rcBounds.left, rcSatBounds.left); rcBounds.right = Max(rcBounds.right, rcSatBounds.right); rcBounds.top = Min(rcBounds.top, rcSatBounds.top); rcBounds.bottom = Max(rcBounds.bottom, rcSatBounds.bottom); } // If no segments, then we just return the basic image if (SatImages.GetCount() == 0) { Entry.pImage = pMainImage; return; } // Create an image that will hold the composite CG32bitImage *pCompositeImage = new CG32bitImage; pCompositeImage->Create(RectWidth(rcBounds), RectHeight(rcBounds), CG32bitImage::alpha8, CG32bitPixel::Null()); int xCenter = -rcBounds.left; int yCenter = -rcBounds.top; // Paint the main image pMainImage->PaintImage(*pCompositeImage, xCenter, yCenter, 0, Entry.iRotation, true); // Paint all the satellites for (i = 0; i < SatImages.GetCount(); i++) SatImages[i].pImage->PaintImage(*pCompositeImage, xCenter + SatImages[i].xOffset, yCenter - SatImages[i].yOffset, 0, 0, true); // Now create the proper image array RECT rcResult; rcResult.left = 0; rcResult.top = 0; rcResult.right = RectWidth(rcBounds); rcResult.bottom = RectHeight(rcBounds); int xOffset = (RectWidth(rcBounds) / 2) - xCenter; int yOffset = (RectHeight(rcBounds) / 2) - yCenter; Entry.pCompositeImageArray = new CObjectImageArray; Entry.pCompositeImageArray->Init(pCompositeImage, rcResult, 0, 0, true, xOffset, yOffset); // Done Entry.pImage = Entry.pCompositeImageArray; }
ALERROR CDockScreenCustomList::OnInitList (SInitCtx &Ctx, CString *retsError) // OnInitList // // Initialize list { // Get the list element CXMLElement *pListData = Ctx.pDesc->GetContentElementByTag(LIST_TAG); if (pListData == NULL) return ERR_FAIL; // See if we define a custom row height CString sRowHeight; if (pListData->FindAttribute(ROW_HEIGHT_ATTRIB, &sRowHeight)) { CString sResult; if (!EvalString(sRowHeight, false, eventNone, &sResult)) { *retsError = sResult; return ERR_FAIL; } int cyRow = strToInt(sResult, -1); if (cyRow > 0) m_pItemListControl->SetRowHeight(cyRow); } // Get the list to show CCodeChain &CC = g_pUniverse->GetCC(); ICCItem *pExp = CC.Link(pListData->GetContentText(0), 0, NULL); // Evaluate the function CCodeChainCtx CCCtx; CCCtx.SetScreen(m_pDockScreen); CCCtx.SaveAndDefineSourceVar(m_pLocation); CCCtx.SaveAndDefineDataVar(m_pData); ICCItem *pResult = CCCtx.Run(pExp); // LATER:Event CCCtx.Discard(pExp); if (pResult->IsError()) { *retsError = pResult->GetStringValue(); return ERR_FAIL; } // Set this expression as the list m_pItemListControl->SetList(CC, pResult); CCCtx.Discard(pResult); // Position the cursor on the next relevant item SelectNextItem(); // Give the screen a chance to start at a different item (other // than the first) CString sInitialItemFunc = pListData->GetAttribute(INITIAL_ITEM_ATTRIB); if (!sInitialItemFunc.IsBlank()) { bool bMore = IsCurrentItemValid(); while (bMore) { bool bResult; if (!EvalBool(sInitialItemFunc, &bResult, retsError)) return ERR_FAIL; if (bResult) break; bMore = SelectNextItem(); } } 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. { DEBUG_TRY // 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 = 502; } // Get the type if (Ctx.pDisplayDesc && Ctx.pDisplayDesc->FindAttribute(TYPE_ATTRIB, &retOptions->sType)) NULL; else retOptions->sType = Ctx.pDesc->GetAttribute(TYPE_ATTRIB); // 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 && (pOptions = Ctx.pDisplayDesc) == NULL) return true; retOptions->pOptions = pOptions; // Read from the element retOptions->sDataFrom = pOptions->GetAttribute(DATA_FROM_ATTRIB); if (!pOptions->FindAttribute(CRITERIA_ATTRIB, &retOptions->sItemCriteria)) retOptions->sItemCriteria = pOptions->GetAttribute(LIST_ATTRIB); retOptions->sInitialItemCode = pOptions->GetAttribute(INITIAL_ITEM_ATTRIB); retOptions->sRowHeightCode = pOptions->GetAttribute(ROW_HEIGHT_ATTRIB); // Init code CXMLElement *pInitCode = pOptions->GetContentElementByTag(ON_DISPLAY_INIT_TAG); if (pInitCode == NULL) pInitCode = pOptions; retOptions->sCode = pInitCode->GetContentText(0); // List options retOptions->bNoArmorSpeedDisplay = pOptions->GetAttributeBool(NO_ARMOR_SPEED_DISPLAY_ATTRIB); retOptions->bActualItems = pOptions->GetAttributeBool(DISPLAY_ACTUAL_ATTRIB); retOptions->cxIcon = pOptions->GetAttributeIntegerBounded(ICON_WIDTH_ATTRIB, 0, -1, ICON_WIDTH); retOptions->cyIcon = pOptions->GetAttributeIntegerBounded(ICON_HEIGHT_ATTRIB, 0, -1, ICON_HEIGHT); retOptions->rIconScale = pOptions->GetAttributeDoubleBounded(ICON_SCALE_ATTRIB, 0.0, -1.0, 1.0); // Selector options retOptions->bNoEmptySlots = pOptions->GetAttributeBool(NO_EMPTY_SLOTS_ATTRIB); retOptions->sSlotNameCode = pOptions->GetAttribute(SLOT_NAME_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; DEBUG_CATCH }
ALERROR CGameSettings::Load (const CString &sFilespec, CString *retsError) // Load // // Load game settings from a file. If the file does not exist, then we // set settings to default values { ALERROR error; int i; // Initialize from defaults for (i = 0; i < OPTIONS_COUNT; i++) SetValue(i, CString(g_OptionData[i].pszDefaultValue, -1, true), true); // Look for a file in the current directory and see if it is writable. If // not, then look in AppData. We remember the place where we found a valid // file as our AppData root (and we base other directories off that). if (pathIsWritable(sFilespec)) { // AppData is current directory m_sAppData = NULL_STR; } else { m_sAppData = pathAddComponent(pathGetSpecialFolder(folderAppData), TRANSCENDENCE_APP_DATA); if (!pathCreate(m_sAppData) || !pathIsWritable(m_sAppData)) { *retsError = strPatternSubst(CONSTLIT("Unable to write to AppData folder: %s"), m_sAppData); return ERR_FAIL; } } // Settings file CString sSettingsFilespec = pathAddComponent(m_sAppData, sFilespec); // Load XML CFileReadBlock DataFile(sSettingsFilespec); CXMLElement *pData; CString sError; if (error = CXMLElement::ParseXML(&DataFile, &pData, retsError)) { // ERR_NOTFOUND means that we couldn't find the Settings.xml // file. In that case, initialize from defaults if (error == ERR_NOTFOUND) { LoadFromRegistry(); m_bModified = true; return NOERROR; } // Otherwise, it means that we got an error parsing the file. // Return the error, but leave the settings initialized to defaults // (We should be OK to continue, even with an error). else { m_bModified = false; return error; } } // Initialize to unmodified (as we load settings we might change this) m_bModified = false; // Loop over all elements for (i = 0; i < pData->GetContentElementCount(); i++) { CXMLElement *pItem = pData->GetContentElement(i); if (strEquals(pItem->GetTag(), OPTION_TAG)) { int iOption = FindOptionData(pItem->GetAttribute(NAME_ATTRIB)); if (iOption == -1) { kernelDebugLogMessage("Unknown option: %s", pItem->GetAttribute(NAME_ATTRIB)); continue; } SetValue(iOption, pItem->GetAttribute(VALUE_ATTRIB), true); } else if (strEquals(pItem->GetTag(), KEY_MAP_TAG)) { if (error = m_KeyMap.ReadFromXML(pItem)) return error; } else if (strEquals(pItem->GetTag(), EXTENSION_FOLDER_TAG)) { CString sFolder; if (pItem->FindAttribute(PATH_ATTRIB, &sFolder)) m_ExtensionFolders.Insert(sFolder); } else if (strEquals(pItem->GetTag(), EXTENSIONS_TAG)) { if (error = m_Extensions.ReadFromXML(pItem)) return error; } else if (m_pExtra) { bool bModified; if (error = m_pExtra->OnLoadSettings(pItem, &bModified)) return error; if (bModified) m_bModified = true; } } // Done delete pData; return NOERROR; }