Esempio n. 1
0
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;
	}
Esempio n. 2
0
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;
	}
Esempio n. 3
0
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;
	}
Esempio n. 4
0
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;
	}
Esempio n. 5
0
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;
	}
Esempio n. 6
0
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);
	}
Esempio n. 7
0
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;
	}
Esempio n. 8
0
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;
}
Esempio n. 10
0
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;
	}
Esempio n. 11
0
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;
	}
Esempio n. 12
0
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;
	}
Esempio n. 13
0
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;
	}
Esempio n. 15
0
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;
	}
Esempio n. 16
0
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;
	}
Esempio n. 17
0
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;
	}
Esempio n. 18
0
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);
	}
Esempio n. 19
0
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);
	}
Esempio n. 20
0
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;
	}
Esempio n. 21
0
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);
	}
Esempio n. 22
0
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;
	}
Esempio n. 23
0
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;
	}
Esempio n. 24
0
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());
}
Esempio n. 25
0
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;
	}