ALERROR CEffectCreator::CreateTypeFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, CEffectCreator **retpCreator) // CreateTypeFromXML // // Creates the class only. This is used by the main Design load code when we use // the full <EffectType> definition. { ALERROR error; CEffectCreator *pCreator; // Create the effect based on the child tag CXMLElement *pEffect = pDesc->GetContentElementByTag(EFFECT_TAG); if (pEffect == NULL) { Ctx.sError = CONSTLIT("<EffectType> must have an <Effect> sub-element."); return ERR_FAIL; } // If we've got no sub elements, then its a null creator if (pEffect->GetContentElementCount() == 0) pCreator = new CNullEffectCreator; // If we've got a single element, then we create a simple creator else if (pEffect->GetContentElementCount() == 1) { const CString &sTag = pEffect->GetContentElement(0)->GetTag(); if (error = CreateFromTag(sTag, &pCreator)) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid effect tag: %s"), sTag); return error; } } // Otherwise we have a group else pCreator = new CEffectGroupCreator; // Done *retpCreator = pCreator; return NOERROR; }
ALERROR WriteSubModules (CTDBCompiler &Ctx, CXMLElement *pModule, const CString &sFolder, CDataFile &Out) { int i, j; for (i = 0; i < pModule->GetContentElementCount(); i++) { CXMLElement *pItem = pModule->GetContentElement(i); if (strEquals(pItem->GetTag(), TAG_MODULES)) { for (j = 0; j < pItem->GetContentElementCount(); j++) { CXMLElement *pDesc = pItem->GetContentElement(j); CString sFilename = pDesc->GetAttribute(ATTRIB_FILENAME); if (WriteModule(Ctx, sFilename, sFolder, Out) != NOERROR) continue; } } else if (strEquals(pItem->GetTag(), TAG_MODULE)) { CString sFilename = pItem->GetAttribute(ATTRIB_FILENAME); if (WriteModule(Ctx, sFilename, sFolder, Out) != NOERROR) continue; } } return NOERROR; }
ALERROR CSovereign::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Create from XML { int i; // Initialize m_sName = pDesc->GetAttribute(CONSTLIT(g_NameAttrib)); // Alignment CString sAlignment = pDesc->GetAttribute(ALIGNMENT_ATTRIB); if (strEquals(sAlignment, CONSTRUCTIVE_CHAOS_ALIGN)) m_iAlignment = alignConstructiveChaos; else if (strEquals(sAlignment, CONSTRUCTIVE_ORDER_ALIGN)) m_iAlignment = alignConstructiveOrder; else if (strEquals(sAlignment, NEUTRAL_ALIGN)) m_iAlignment = alignNeutral; else if (strEquals(sAlignment, DESTRUCTIVE_ORDER_ALIGN)) m_iAlignment = alignDestructiveOrder; else if (strEquals(sAlignment, DESTRUCTIVE_CHAOS_ALIGN)) m_iAlignment = alignDestructiveChaos; else return ERR_FAIL; // Load language CXMLElement *pLanguage = pDesc->GetContentElementByTag(LANGUAGE_TAG); if (pLanguage) { int iCount = pLanguage->GetContentElementCount(); for (i = 0; i < iCount; i++) { CXMLElement *pItem = pLanguage->GetContentElement(i); CString *pText = new CString(pItem->GetAttribute(TEXT_ATTRIB)); DWORD dwID = pItem->GetAttributeInteger(ID_ATTRIB); if (dwID != 0) m_Language.AddEntry(dwID, pText); } } // Load relationships m_pInitialRelationships = pDesc->GetContentElementByTag(RELATIONSHIPS_TAG); if (m_pInitialRelationships) m_pInitialRelationships = m_pInitialRelationships->OrphanCopy(); // Done return NOERROR; }
ALERROR CEffectCreator::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Load from XML. This is only called if we go through the EffectType path // (as opposed to plain Effect). { ALERROR error; // Basic info m_sUNID = strFromInt(GetUNID(), FALSE); m_dwSoundUNID = pDesc->GetAttributeInteger(SOUND_ATTRIB); m_iSound = -1; // Allow our subclass to initialize based on the effect // (We know we have one because we couldn't have gotten this far // without one. See CreateTypeFromXML.) CXMLElement *pEffect = pDesc->GetContentElementByTag(EFFECT_TAG); ASSERT(pEffect); if (pEffect->GetContentElementCount() == 1) error = OnEffectCreateFromXML(Ctx, pEffect->GetContentElement(0), m_sUNID); else error = OnEffectCreateFromXML(Ctx, pEffect, m_sUNID); if (error) return error; // Load damage descriptors CXMLElement *pDamageDesc = pDesc->GetContentElementByTag(DAMAGE_TAG); if (pDamageDesc) { m_pDamage = new CWeaponFireDesc; CString sUNID = strPatternSubst(CONSTLIT("%d/d"), GetUNID()); if (error = m_pDamage->InitFromXML(Ctx, pDamageDesc, sUNID, true)) return error; } return NOERROR; }
ALERROR CHighScoreList::Load (const CString &sFilename) // Load // // Load the high score list { ALERROR error; m_iCount = 0; // Load XML CFileReadBlock DataFile(sFilename); CXMLElement *pData; CString sError; if (error = CXMLElement::ParseXML(&DataFile, &pData, &sError)) // Means we can't find it or is corrupt... return NOERROR; // Get the most recent player name m_sMostRecentPlayerName = pData->GetAttribute(LAST_PLAYER_NAME_ATTRIB); m_iMostRecentPlayerGenome = CGameRecord::LoadGenome(pData->GetAttribute(LAST_PLAYER_GENOME_ATTRIB)); // Fill the structures for (int i = 0; i < pData->GetContentElementCount(); i++) { if (error = m_List[m_iCount].InitFromXML(pData->GetContentElement(i))) return error; m_iCount++; } m_bModified = false; // Done delete pData; return NOERROR; }
void CDockingPorts::InitPortsFromXML (CSpaceObject *pOwner, CXMLElement *pElement) // InitPortsFromXML // // InitPortsFromXML { // See if we've got a special element with docking port geometry CXMLElement *pDockingPorts = pElement->GetContentElementByTag(DOCKING_PORTS_TAG); if (pDockingPorts) { m_iPortCount = pDockingPorts->GetContentElementCount(); if (m_iPortCount > 0) { m_pPort = new DockingPort[m_iPortCount]; for (int 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; m_pPort[i].iRotation = (VectorToPolar(vDockPos) + 180) % 360; } } } // Otherwise, initialize ports based on a count else InitPorts(pOwner, pElement->GetAttributeInteger(DOCKING_PORTS_ATTRIB), 64 * g_KlicksPerPixel); }
ALERROR CGameSettings::ParseCommandLine (char *pszCmdLine) // ParseCommandLine // // Allow command line to override settings { ALERROR error; int i; char *argv[2]; argv[0] = "Transcendence"; argv[1] = pszCmdLine; CXMLElement *pCmdLine; if (error = CreateXMLElementFromCommandLine(2, argv, &pCmdLine)) return error; // Loop over all command line arguments for (i = 0; i < COMMAND_LINE_DATA_COUNT; i++) { bool bValue; if (pCmdLine->FindAttributeBool(CString(g_CommandLineData[i].pszParam, -1, true), &bValue)) SetValueBoolean(g_CommandLineData[i].iOption, bValue); } // If we have an arg then use it as the save file name if (pCmdLine->GetContentElementCount() > 0) m_sSaveFile = pCmdLine->GetContentText(0); // Done delete pCmdLine; 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; }
ALERROR CAdventureDesc::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Load from XML { ALERROR error; int i; // If we are part of the default resource, then get the adventure UNID if (Ctx.pExtension == NULL) { m_dwExtensionUNID = pDesc->GetAttributeInteger(ADVENTURE_UNID_ATTRIB); m_fInDefaultResource = true; } // Otherwise, we remember the extension that we were loaded from else { m_dwExtensionUNID = Ctx.pExtension->GetUNID(); m_fInDefaultResource = false; } // Load the name, etc m_sName = pDesc->GetAttribute(NAME_ATTRIB); if (error = ::LoadUNID(Ctx, pDesc->GetAttribute(BACKGROUND_ID_ATTRIB), &m_dwBackgroundUNID)) return error; // Starting ship criteria CString sCriteria; if (!pDesc->FindAttribute(STARTING_SHIP_CRITERIA_ATTRIB, &sCriteria)) sCriteria = CONSTLIT("*"); if (error = CDesignTypeCriteria::ParseCriteria(sCriteria, &m_StartingShips)) return ComposeLoadError(Ctx, ERR_STARTING_SHIP_CRITERIA); m_fIncludeOldShipClasses = pDesc->GetAttributeBool(INCLUDE_10_STARTING_CLASSES_ATTRIB); // Starting position m_sStartingNodeID = pDesc->GetAttribute(STARTING_SYSTEM_ATTRIB); m_sStartingPos = pDesc->GetAttribute(STARTING_POS_ATTRIB); // Welcome message if (!pDesc->FindAttribute(WELCOME_MESSAGE_ATTRIB, &m_sWelcomeMessage)) m_sWelcomeMessage = CONSTLIT("Welcome to Transcendence!"); // Init some flags m_fIsCurrentAdventure = false; // If we don't have a name, then get it from the extension if (m_sName.IsBlank()) { if (Ctx.pExtension) m_sName = Ctx.pExtension->GetName(); } // Otherwise, if the extension doesn't have a name, then we can set it else if (Ctx.pExtension && strFind(Ctx.pExtension->GetName(), CONSTLIT("Extension")) == 0) Ctx.pExtension->SetName(m_sName); // Initialize armor and shield damage adjustment tables InitDefaultDamageAdj(); for (i = 1; i <= MAX_ITEM_LEVEL; i++) { m_ArmorDamageAdj[i - 1] = g_ArmorDamageAdj[i - 1]; m_ShieldDamageAdj[i - 1] = g_ShieldDamageAdj[i - 1]; } // Load constants CXMLElement *pConstants = pDesc->GetContentElementByTag(CONSTANTS_TAG); if (pConstants) { for (i = 0; i < pConstants->GetContentElementCount(); i++) { CXMLElement *pItem = pConstants->GetContentElement(i); if (strEquals(pItem->GetTag(), ARMOR_DAMAGE_ADJ_TAG)) { int iLevel = pItem->GetAttributeInteger(LEVEL_ATTRIB); if (iLevel < 1 || iLevel > MAX_ITEM_LEVEL) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid level: %d."), iLevel); return ERR_FAIL; } if (error = m_ArmorDamageAdj[iLevel - 1].InitFromXML(Ctx, pItem, true)) return error; } else if (strEquals(pItem->GetTag(), SHIELD_DAMAGE_ADJ_TAG)) { int iLevel = pItem->GetAttributeInteger(LEVEL_ATTRIB); if (iLevel < 1 || iLevel > MAX_ITEM_LEVEL) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid level: %d."), iLevel); return ERR_FAIL; } if (error = m_ShieldDamageAdj[iLevel - 1].InitFromXML(Ctx, pItem, true)) return error; } else { Ctx.sError = strPatternSubst(CONSTLIT("Invalid constant definition element: %s."), pItem->GetTag()); return ERR_FAIL; } } } return NOERROR; }
ALERROR CNPUniverse::CreateRandomWorld (CreateCtx &Ctx, CNPNullPoint *pNP, CNPSovereign *pSovereign) // CreateRandomWorld // // Creates a random world at the given null point { ALERROR error; CNPWorld *pWorld; int i, iRoll; // Create the world if (error = CNPWorld::Create(m_Worlds.RegisterEntry(), pNP->GetUNID(), pSovereign, &pWorld)) { Ctx.sError = LITERAL("Out of memory"); return error; } m_Worlds.SetEntry(pWorld->GetUNID(), pWorld); // Add to the null point if (error = pNP->AddWorld(pWorld)) { delete pWorld; Ctx.sError = LITERAL("Out of memory"); return error; } // Add some traits to the world CXMLElement *pTraitTable = Ctx.pTemplate->GetContentElementByTag(CONSTLIT("DefineWorldTraitTable")); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMajorDisadvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 35) AddRandomTrait(Ctx, pWorld, ttMinorDisadvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMinorDisadvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMajorAdvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 35) AddRandomTrait(Ctx, pWorld, ttMinorAdvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMinorAdvantage, 1, pTraitTable); // Pick a tech level for the world CXMLElement *pTechTable = Ctx.pTemplate->GetContentElementByTag(CONSTLIT("DefineWorldTechLevelTable")); iRoll = mathRandom(1, 100); NPTechLevels iMinTech = pWorld->GetMinTech(); for (i = 0; i < pTechTable->GetContentElementCount(); i++) { CXMLElement *pEntry = pTechTable->GetContentElement(i); int iProb = pEntry->GetAttributeInteger(CONSTLIT("Prob")); if (iRoll <= iProb) { NPTechLevels iTechLevel = (NPTechLevels)GetSymbolicAttribute(*Ctx.pSymbols, pEntry, CONSTLIT("Tech")); // Make sure this tech level is appropriate for the world while (iTechLevel < iMinTech) iTechLevel = (NPTechLevels)(iTechLevel + 1); pWorld->SetTechLevel(iTechLevel); break; } iRoll -= iProb; } // Set the initial population int iPopulation = 0; switch (pWorld->GetTechLevel()) { case techAgricultural: iPopulation = mathRandom(250, 750); break; case techSteam: case techCyber: { for (i = 0; i < 12; i++) iPopulation += mathRandom(0, 500); break; } case techBio: { for (i = 0; i < 10; i++) iPopulation += mathRandom(0, 1000); break; } case techFusion: case techAI: { for (i = 0; i < 8; i++) iPopulation += mathRandom(0, 1600); break; } default: { for (i = 0; i < 10; i++) iPopulation += mathRandom(0, 2000); break; } } pWorld->SetPopulation((1000 * iPopulation) + mathRandom(-500, 500)); // Set the efficiency pWorld->SetEfficiency(25 + mathRandom(0, 25) + mathRandom(0, 25) + mathRandom(0, 25)); // Figure out if this world is a suitable candidate for a capital if (IsWorldSuitableAsCapital(this, pWorld)) pWorld->SetTrait(traitReservedCapital); return NOERROR; }
ALERROR CPlayerSettings::InitFromXML (SDesignLoadCtx &Ctx, CShipClass *pClass, CXMLElement *pDesc) // InitFromXML // // Initialize from an XML element { ALERROR error; int i; m_sDesc = pDesc->GetAttribute(DESC_ATTRIB); m_dwLargeImage = LoadUNID(Ctx, pDesc->GetAttribute(LARGE_IMAGE_ATTRIB)); m_fDebug = pDesc->GetAttributeBool(DEBUG_ONLY_ATTRIB); m_fInitialClass = pDesc->GetAttributeBool(INITIAL_CLASS_ATTRIB); m_fHasArmorDesc = false; m_fHasReactorDesc = false; m_fHasShieldDesc = false; // Some ship capabilities bool bValue; if (pDesc->FindAttributeBool(AUTOPILOT_ATTRIB, &bValue)) m_fAutopilot = bValue; else m_fAutopilot = true; // Load some miscellaneous data CString sAttrib; if (!pDesc->FindAttribute(STARTING_CREDITS_ATTRIB, &sAttrib)) sAttrib = CONSTLIT("5d20+200"); if (error = m_StartingCredits.InitFromXML(Ctx, sAttrib)) return error; m_sStartNode = pDesc->GetAttribute(STARTING_SYSTEM_ATTRIB); m_sStartPos = pDesc->GetAttribute(STARTING_POS_ATTRIB); if (m_sStartPos.IsBlank()) m_sStartPos = CONSTLIT("Start"); // Load the ship screen CString sShipScreenUNID = pDesc->GetAttribute(SHIP_SCREEN_ATTRIB); if (sShipScreenUNID.IsBlank()) sShipScreenUNID = strFromInt(DEFAULT_SHIP_SCREEN_UNID, FALSE); m_pShipScreen.LoadUNID(Ctx, sShipScreenUNID); // Load the armor display data CXMLElement *pArmorDisplay = pDesc->GetContentElementByTag(ARMOR_DISPLAY_TAG); if (pArmorDisplay && pArmorDisplay->GetContentElementCount() > 0) { m_iArmorDescCount = pArmorDisplay->GetContentElementCount(); m_pArmorDesc = new SArmorImageDesc [m_iArmorDescCount]; for (i = 0; i < m_iArmorDescCount; i++) { SArmorImageDesc &ArmorDesc = m_pArmorDesc[i]; CXMLElement *pSegment = pArmorDisplay->GetContentElement(i); if (error = ArmorDesc.Image.InitFromXML(Ctx, pSegment)) return ComposeLoadError(Ctx, ERR_ARMOR_DISPLAY_NEEDED); ArmorDesc.sName = pSegment->GetAttribute(NAME_ATTRIB); ArmorDesc.xDest = pSegment->GetAttributeInteger(DEST_X_ATTRIB); ArmorDesc.yDest = pSegment->GetAttributeInteger(DEST_Y_ATTRIB); ArmorDesc.xHP = pSegment->GetAttributeInteger(HP_X_ATTRIB); ArmorDesc.yHP = pSegment->GetAttributeInteger(HP_Y_ATTRIB); ArmorDesc.yName = pSegment->GetAttributeInteger(NAME_Y_ATTRIB); ArmorDesc.cxNameBreak = pSegment->GetAttributeInteger(NAME_BREAK_WIDTH); ArmorDesc.xNameDestOffset = pSegment->GetAttributeInteger(NAME_DEST_X_ATTRIB); ArmorDesc.yNameDestOffset = pSegment->GetAttributeInteger(NAME_DEST_Y_ATTRIB); } m_fHasArmorDesc = true; } else { m_fHasArmorDesc = false; m_iArmorDescCount = 0; m_pArmorDesc = NULL; } // Load shield display data CXMLElement *pShieldDisplay = pDesc->GetContentElementByTag(SHIELD_DISPLAY_TAG); if (pShieldDisplay) { if (error = m_ShieldDesc.Image.InitFromXML(Ctx, pShieldDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_SHIELD_DISPLAY_NEEDED); m_fHasShieldDesc = true; } // Load reactor display data CXMLElement *pReactorDisplay = pDesc->GetContentElementByTag(REACTOR_DISPLAY_TAG); if (pReactorDisplay) { if (error = m_ReactorDesc.ReactorImage.InitFromXML(Ctx, pReactorDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); CXMLElement *pImage = pReactorDisplay->GetContentElementByTag(POWER_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.PowerLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xPowerLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yPowerLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xFuelLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yFuelLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LOW_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLowLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(REACTOR_TEXT_TAG), &m_ReactorDesc.rcReactorText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(POWER_LEVEL_TEXT_TAG), &m_ReactorDesc.rcPowerLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_TEXT_TAG), &m_ReactorDesc.rcFuelLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_fHasReactorDesc = true; } // Done return NOERROR; }
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); // Load XML CFileReadBlock DataFile(sFilespec); 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).GetASCIIZPointer()); 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 (m_pExtra) { bool bModified; if (error = m_pExtra->OnLoadSettings(pItem, &bModified)) return error; if (bModified) m_bModified = true; } } // Done delete pData; return NOERROR; }
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; }
ALERROR CPlayerSettings::InitFromXML (SDesignLoadCtx &Ctx, CShipClass *pClass, CXMLElement *pDesc) // InitFromXML // // Initialize from an XML element { ALERROR error; int i; m_sDesc = pDesc->GetAttribute(DESC_ATTRIB); if (error = LoadUNID(Ctx, pDesc->GetAttribute(LARGE_IMAGE_ATTRIB), &m_dwLargeImage)) return error; m_fDebug = pDesc->GetAttributeBool(DEBUG_ONLY_ATTRIB); CString sInitialClass = pDesc->GetAttribute(INITIAL_CLASS_ATTRIB); if (strEquals(sInitialClass, CONSTLIT("always"))) { m_fInitialClass = true; m_fIncludeInAllAdventures = true; } else { m_fInitialClass = CXMLElement::IsBoolTrueValue(sInitialClass); m_fIncludeInAllAdventures = false; } m_fHasArmorDesc = false; m_fHasReactorDesc = false; m_fHasShieldDesc = false; // Some ship capabilities bool bValue; if (pDesc->FindAttributeBool(AUTOPILOT_ATTRIB, &bValue)) m_fAutopilot = bValue; else m_fAutopilot = true; // Load some miscellaneous data CString sAttrib; if (!pDesc->FindAttribute(STARTING_CREDITS_ATTRIB, &sAttrib)) sAttrib = CONSTLIT("5d20+200"); if (error = m_StartingCredits.InitFromXML(Ctx, sAttrib)) return error; m_sStartNode = pDesc->GetAttribute(STARTING_SYSTEM_ATTRIB); m_sStartPos = pDesc->GetAttribute(STARTING_POS_ATTRIB); if (m_sStartPos.IsBlank()) m_sStartPos = CONSTLIT("Start"); // Load the ship screen CString sShipScreenUNID = pDesc->GetAttribute(SHIP_SCREEN_ATTRIB); if (sShipScreenUNID.IsBlank()) sShipScreenUNID = strFromInt(DEFAULT_SHIP_SCREEN_UNID, false); m_pShipScreen.LoadUNID(Ctx, sShipScreenUNID); // Load the armor display data CXMLElement *pArmorDisplay = pDesc->GetContentElementByTag(ARMOR_DISPLAY_TAG); if (pArmorDisplay && pArmorDisplay->GetContentElementCount() > 0) { // Loop over all sub elements for (i = 0; i < pArmorDisplay->GetContentElementCount(); i++) { CXMLElement *pSub = pArmorDisplay->GetContentElement(i); if (strEquals(pSub->GetTag(), ARMOR_SECTION_TAG)) { SArmorSegmentImageDesc &ArmorDesc = *m_ArmorDesc.Segments.Insert(); if (error = ArmorDesc.Image.InitFromXML(Ctx, pSub)) return ComposeLoadError(Ctx, ERR_ARMOR_DISPLAY_NEEDED); ArmorDesc.sName = pSub->GetAttribute(NAME_ATTRIB); ArmorDesc.xDest = pSub->GetAttributeInteger(DEST_X_ATTRIB); ArmorDesc.yDest = pSub->GetAttributeInteger(DEST_Y_ATTRIB); ArmorDesc.xHP = pSub->GetAttributeInteger(HP_X_ATTRIB); ArmorDesc.yHP = pSub->GetAttributeInteger(HP_Y_ATTRIB); ArmorDesc.yName = pSub->GetAttributeInteger(NAME_Y_ATTRIB); ArmorDesc.cxNameBreak = pSub->GetAttributeInteger(NAME_BREAK_WIDTH); ArmorDesc.xNameDestOffset = pSub->GetAttributeInteger(NAME_DEST_X_ATTRIB); ArmorDesc.yNameDestOffset = pSub->GetAttributeInteger(NAME_DEST_Y_ATTRIB); } else if (strEquals(pSub->GetTag(), SHIP_IMAGE_TAG)) { if (error = m_ArmorDesc.ShipImage.InitFromXML(Ctx, pSub)) return ComposeLoadError(Ctx, ERR_SHIP_IMAGE_NEEDED); } else return ComposeLoadError(Ctx, strPatternSubst(CONSTLIT("Unknown ArmorDisplay element: "), pSub->GetTag())); } m_fHasArmorDesc = true; } else m_fHasArmorDesc = false; // Load shield display data CXMLElement *pShieldDisplay = pDesc->GetContentElementByTag(SHIELD_DISPLAY_TAG); if (pShieldDisplay) { // Load the new shield effect if (error = m_ShieldDesc.pShieldEffect.LoadEffect(Ctx, strPatternSubst(CONSTLIT("%d:p:s"), pClass->GetUNID()), pShieldDisplay->GetContentElementByTag(SHIELD_EFFECT_TAG), pShieldDisplay->GetAttribute(SHIELD_EFFECT_ATTRIB))) return error; // If we don't have the new effect, load the backwards compatibility // image. if (m_ShieldDesc.pShieldEffect.IsEmpty()) { if (error = m_ShieldDesc.Image.InitFromXML(Ctx, pShieldDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_SHIELD_DISPLAY_NEEDED); } m_fHasShieldDesc = true; } // If we have a shield effect then we must have an armor image if (!m_ShieldDesc.pShieldEffect.IsEmpty() && m_ArmorDesc.ShipImage.GetBitmapUNID() == 0) return ComposeLoadError(Ctx, ERR_MUST_HAVE_SHIP_IMAGE); // Load reactor display data CXMLElement *pReactorDisplay = pDesc->GetContentElementByTag(REACTOR_DISPLAY_TAG); if (pReactorDisplay) { if (error = m_ReactorDesc.ReactorImage.InitFromXML(Ctx, pReactorDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); CXMLElement *pImage = pReactorDisplay->GetContentElementByTag(POWER_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.PowerLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xPowerLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yPowerLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xFuelLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yFuelLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LOW_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLowLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(REACTOR_TEXT_TAG), &m_ReactorDesc.rcReactorText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(POWER_LEVEL_TEXT_TAG), &m_ReactorDesc.rcPowerLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_TEXT_TAG), &m_ReactorDesc.rcFuelLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_fHasReactorDesc = true; } // Done return NOERROR; }
ALERROR CDesignCollection::LoadExtensionDesc (SDesignLoadCtx &Ctx, CXMLElement *pDesc, bool bDefaultResource, SExtensionDesc **retpExtension) // LoadExtensionDesc // // Loads a new extension descriptor { ALERROR error; int i; // Load version DWORD dwVersion = ::LoadExtensionVersion(pDesc->GetAttribute(VERSION_ATTRIB)); if (dwVersion == 0) { Ctx.sError = strPatternSubst(CONSTLIT("Unable to load extension: incompatible version: %s"), pDesc->GetAttribute(VERSION_ATTRIB)); return ERR_FAIL; } // Load UNID DWORD dwUNID = pDesc->GetAttributeInteger(UNID_ATTRIB); // See if this is registered // LATER: For now, this is hard-coded bool bIsRegistered = (dwUNID == 0x00300000) || (dwUNID == 0x00200000) || ((dwUNID & 0xF0000000) == 0xA0000000); // Make sure that unregistered extensions are in the correct ranage if (!bIsRegistered) { DWORD dwDomain = (dwUNID & 0xF0000000); if (dwDomain < 0xA0000000 || dwDomain > 0xEFFFFFFF) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid extension UNID: %x"), dwUNID); return ERR_FAIL; } } // Create structure SExtensionDesc *pEntry; if (error = AddExtension(Ctx, extExtension, dwUNID, bDefaultResource, &pEntry)) return error; pEntry->dwVersion = dwVersion; pEntry->bRegistered = bIsRegistered; pEntry->bEnabled = true; pEntry->bDebugOnly = pDesc->GetAttributeBool(DEBUG_ONLY_ATTRIB); // Load name pEntry->sName = pDesc->GetAttribute(NAME_ATTRIB); if (pEntry->sName.IsBlank()) pEntry->sName = strPatternSubst(CONSTLIT("Extension %x"), dwUNID); // Load credits (we parse them into a string array) CString sCredits = pDesc->GetAttribute(CREDITS_ATTRIB); if (!sCredits.IsBlank()) strDelimitEx(sCredits, ';', DELIMIT_TRIM_WHITESPACE, 0, &pEntry->Credits); // Load extends attrib CString sExtends = pDesc->GetAttribute(EXTENDS_ATTRIB); if (!sExtends.IsBlank()) { TArray<CString> Extends; strDelimitEx(sExtends, ';', DELIMIT_TRIM_WHITESPACE, 0, &Extends); for (i = 0; i < Extends.GetCount(); i++) { DWORD dwUNID = strToInt(Extends[i], INVALID_UNID); if (dwUNID != INVALID_UNID) pEntry->Extends.Insert(dwUNID); } } // If we're an extension in the default resource, load modules if (bDefaultResource) { CXMLElement *pModules = pDesc->GetContentElementByTag(MODULES_TAG); if (pModules) { for (i = 0; i < pModules->GetContentElementCount(); i++) { CXMLElement *pModule = pModules->GetContentElement(i); CString sModule = pModule->GetAttribute(FILENAME_ATTRIB); if (!sModule.IsBlank()) pEntry->Modules.Insert(sModule); } } } // Done *retpExtension = pEntry; 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 CEffectCreator::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Load from XML. This is only called if we go through the EffectType path // (as opposed to plain Effect types). { ALERROR error; // Basic info m_sUNID = strFromInt(GetUNID(), false); if (error = InitBasicsFromXML(Ctx, pDesc)) return error; // Allow our subclass to initialize based on the effect // (We know we have one because we couldn't have gotten this far // without one. See CreateTypeFromXML.) CXMLElement *pEffect = pDesc->GetContentElementByTag(EFFECT_TAG); ASSERT(pEffect); // Continue if (pEffect->GetContentElementCount() == 1) { CXMLElement *pEffectDesc = pEffect->GetContentElement(0); // Load events for this effect, in case they're here. CXMLElement *pEventsDesc = pEffectDesc->GetContentElementByTag(EVENTS_TAG); if (pEventsDesc) { if (error = m_Events.InitFromXML(Ctx, pEventsDesc)) return error; } // Load the single effect error = OnEffectCreateFromXML(Ctx, pEffectDesc, m_sUNID); } else error = OnEffectCreateFromXML(Ctx, pEffect, m_sUNID); if (error) return error; // Load damage descriptors CXMLElement *pDamageDesc = pDesc->GetContentElementByTag(DAMAGE_TAG); if (pDamageDesc) { m_pDamage = new CWeaponFireDesc; CString sUNID = strPatternSubst(CONSTLIT("%d/d"), GetUNID()); if (error = m_pDamage->InitFromXML(Ctx, pDamageDesc, sUNID, true)) return error; } return NOERROR; }
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 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 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; }
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); }
ALERROR CNPUniverse::LoadClassesFromXML (CXMLElement *pTemplate, CSymbolTable &Symbols, CString *retsError) // LoadClassesFromXML // // Loads the unit classes, etc. { ALERROR error; CXMLElement *pSection; CXMLElement *pTable; int i; // Load universal constants section if ((pSection = FindElement(pTemplate, CONSTLIT("DefineUniversalConstants"), retsError)) == NULL) return ERR_FAIL; // Load tech table if ((pTable = FindElement(pSection, CONSTLIT("TechTable"), retsError)) == NULL) return ERR_FAIL; if (pTable->GetContentElementCount() != techCount - 1) { *retsError = CONSTLIT("<TechTable> does not have the right number of entries."); return ERR_FAIL; } for (i = 0; i < pTable->GetContentElementCount(); i++) { CXMLElement *pEntry = pTable->GetContentElement(i); m_TechTable[i + 1].sName = pEntry->GetAttribute(CONSTLIT("Name")); m_TechTable[i + 1].iProductionFactor = pEntry->GetAttributeInteger(CONSTLIT("Prod")); m_TechTable[i + 1].iStdLivingFactor = pEntry->GetAttributeInteger(CONSTLIT("StdLiving")); m_TechTable[i + 1].iPollutionFactor = pEntry->GetAttributeInteger(CONSTLIT("Pollution")); } // Load unit classes if ((pSection = FindElement(pTemplate, CONSTLIT("DefineUnitClasses"), retsError)) == NULL) return ERR_FAIL; for (i = 0; i < pSection->GetContentElementCount(); i++) { CNPUnitClass *pClass = new CNPUnitClass; if (pClass == NULL) { *retsError = CONSTLIT("Out of memory"); return ERR_FAIL; } if (error = pClass->LoadFromXML(pSection->GetContentElement(i), Symbols)) { *retsError = CONSTLIT("Unable to load unit class"); return ERR_FAIL; } m_UnitClasses.SetEntry(pClass->GetUNID(), pClass); } // Get the default sovereign if ((pSection = FindElement(pTemplate, CONSTLIT("DefineSovereigns"), retsError)) == NULL) return ERR_FAIL; if ((m_pPlayerTemplate = FindElement(pSection, CONSTLIT("DefineDefaultPlayer"), retsError)) == NULL) return ERR_FAIL; m_pPlayerTemplate = m_pPlayerTemplate->OrphanCopy(); 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; }
void GenerateWordList (const CString &sDataFile, CXMLElement *pCmdLine) // GenerateWordList // // Generate a list of unique words used in the game { ALERROR error; int i; CString sError; // Open the XML file CResourceDb Resources(sDataFile); if (error = Resources.Open()) { printf("Unable to initialize data file.\n"); return; } CXMLElement *pGameFile; if (error = Resources.LoadGameFile(&pGameFile, NULL, &sError)) { printf("%s\n", sError.GetASCIIZPointer()); return; } // Create the context CSymbolTable WordList(FALSE, TRUE); TraverseCtx Ctx; Ctx.pWordList = &WordList; // Recursive descent ParseWordList(Ctx, pGameFile); // Parse all modules too CXMLElement *pModules = pGameFile->GetContentElementByTag(MODULES_TAG); if (pModules) { for (i = 0; i < pModules->GetContentElementCount(); i++) { CXMLElement *pModule = pModules->GetContentElement(i); CXMLElement *pModuleXML; if (error = Resources.LoadModule(NULL_STR, pModule->GetAttribute(FILENAME_ATTRIB), &pModuleXML, &sError)) { printf("%s\n", sError.GetASCIIZPointer()); return; } ParseWordList(Ctx, pModuleXML); } } // Print out the word list for (i = 0; i < WordList.GetCount(); i++) printf("%s\n", WordList.GetKey(i).GetASCIIZPointer()); }
ALERROR WriteModule (const CString &sFilename, const CString &sFolder, CExternalEntityTable *pEntityTable, CSymbolTable &Resources, CDataFile &Out, int *retiModuleEntry) { ALERROR error; int i; // Parse the file CXMLElement *pModule; CExternalEntityTable EntityTable; if (pEntityTable) { CFileReadBlock DataFile(sFilename); CString sError; printf("Parsing %s...", sFilename.GetASCIIZPointer()); if (error = CXMLElement::ParseXML(&DataFile, pEntityTable, &pModule, &sError)) { printf("\n%s\n", sError.GetASCIIZPointer()); return error; } printf("done.\n"); } else { CFileReadBlock DataFile(sFilename); CString sError; printf("Parsing %s...", sFilename.GetASCIIZPointer()); if (error = CXMLElement::ParseXML(&DataFile, &pModule, &sError, &EntityTable)) { printf("\n%s\n", sError.GetASCIIZPointer()); return error; } pEntityTable = &EntityTable; printf("done.\n"); } // Write the module itself int iEntry; if (error = WriteGameFile(sFilename, 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) Resources.AddEntry(sFilename, (CObject *)iEntry); // Store all the image resources if (error = WriteModuleImages(pModule, sFolder, Resources, Out)) return error; // Store all the sound resources if (error = WriteModuleSounds(pModule, sFolder, Resources, Out)) return error; // Store all modules CXMLElement *pModules = pModule->GetContentElementByTag(TAG_MODULES); if (pModules) { for (i = 0; i < pModules->GetContentElementCount(); i++) { CXMLElement *pItem = pModules->GetContentElement(i); CString sFilename = pItem->GetAttribute(ATTRIB_FILENAME); if (error = WriteModule(sFilename, sFolder, pEntityTable, Resources, Out, NULL)) continue; } } // Done if (retiModuleEntry) *retiModuleEntry = iEntry; return NOERROR; }