Exemple #1
0
void CListSaveFilesTask::CreateFileEntry (CGameFile &GameFile, const CTimeDate &ModifiedTime, int yStart, IAnimatron **retpEntry, int *retcyHeight)

//	CreateFileEntry
//
//	Creates a display entry for the save file

	{
	const CVisualPalette &VI = m_HI.GetVisuals();
	const CG16bitFont &MediumFont = VI.GetFont(fontMedium);
	const CG16bitFont &SubTitleFont = VI.GetFont(fontSubTitle);

	int x = 0;
	int y = 0;
	int xText = x + ADVENTURE_ICON_WIDTH + ICON_SPACING_HORZ;
	int cxText = m_cxWidth - (ADVENTURE_ICON_WIDTH + 2 * ICON_SPACING_HORZ + SHIP_IMAGE_WIDTH);

	//	Start with a sequencer

	CAniSequencer *pRoot = new CAniSequencer;
	pRoot->SetPropertyVector(PROP_POSITION, CVector(0, yStart));

	//	Add the character name and current star system

	CString sHeading = strPatternSubst(CONSTLIT("%s — %s"), GameFile.GetPlayerName(), GameFile.GetSystemName());

	IAnimatron *pName = new CAniText;
	pName->SetPropertyVector(PROP_POSITION, CVector(xText, y));
	pName->SetPropertyVector(PROP_SCALE, CVector(10000, 1000));
	pName->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogInput));
	pName->SetPropertyFont(PROP_FONT, &SubTitleFont);
	pName->SetPropertyString(PROP_TEXT, sHeading);

	pRoot->AddTrack(pName, 0);
	y += SubTitleFont.GetHeight();

	//	Now add some additional information

	CShipClass *pClass = g_pUniverse->FindShipClass(GameFile.GetPlayerShip());
	CString sShipClass = (pClass ? pClass->GetName() : NULL_STR);
	CString sGenome = strCapitalize(GetGenomeName(GameFile.GetPlayerGenome()));

	CString sState;
	if (GameFile.IsGameResurrect())
		sState = strPatternSubst(CONSTLIT("Resurrect in the %s System"), GameFile.GetSystemName());
	else
		sState = strPatternSubst(CONSTLIT("Continue in the %s System"), GameFile.GetSystemName());

	CString sDesc;
	if (!sGenome.IsBlank() && !sShipClass.IsBlank())
		sDesc = strPatternSubst(CONSTLIT("%s — %s — %s"), sGenome, sShipClass, sState);
	else
		sDesc = sState;

	IAnimatron *pDesc = new CAniText;
	pDesc->SetPropertyVector(PROP_POSITION, CVector(xText, y));
	pDesc->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000));
	pDesc->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogInput));
	pDesc->SetPropertyFont(PROP_FONT, &MediumFont);
	pDesc->SetPropertyString(PROP_TEXT, sDesc);

	RECT rcLine;
	pDesc->GetSpacingRect(&rcLine);

	pRoot->AddTrack(pDesc, 0);
	y += RectHeight(rcLine);

	//	Adventure info

	CExtension *pAdventure = NULL;
	bool bHasAdventureIcon = false;

	if (g_pUniverse->FindExtension(GameFile.GetAdventure(), 0, &pAdventure))
		{
		//	Adventure icon

		CG16bitImage *pIcon;
		pAdventure->CreateIcon(ADVENTURE_ICON_WIDTH, ADVENTURE_ICON_HEIGHT, &pIcon);

		if (pIcon)
			{
			int xOffset = (ADVENTURE_ICON_WIDTH - pIcon->GetWidth()) / 2;
			IAnimatron *pIconAni = new CAniRect;
			pIconAni->SetPropertyVector(PROP_POSITION, CVector(x + xOffset, 0));
			pIconAni->SetPropertyVector(PROP_SCALE, CVector(pIcon->GetWidth(), pIcon->GetHeight()));
			pIconAni->SetFillMethod(new CAniImageFill(pIcon, true));

			pRoot->AddTrack(pIconAni, 0);

			bHasAdventureIcon = true;
			}

		//	Adventure name

		pName = new CAniText;
		pName->SetPropertyVector(PROP_POSITION, CVector(xText, y));
		pName->SetPropertyVector(PROP_SCALE, CVector(10000, 1000));
		pName->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogLabel));
		pName->SetPropertyFont(PROP_FONT, &MediumFont);
		pName->SetPropertyString(PROP_TEXT, pAdventure->GetName());

		pRoot->AddTrack(pName, 0);
		y += MediumFont.GetHeight();
		}

	//	Create an image of the ship class

	if (pClass)
		{
		const CObjectImageArray &ObjImage = pClass->GetImage();
		if (ObjImage.IsLoaded())
			{
			RECT rcRect = ObjImage.GetImageRect();
			CG16bitImage &Image = ObjImage.GetImage(NULL_STR);
			int cxImage = RectWidth(rcRect);
			int cyImage = RectHeight(rcRect);

			int cxNewWidth = Min(SHIP_IMAGE_WIDTH, cxImage);
			int cyNewHeight = cxNewWidth;

			CG16bitImage *pNewImage = new CG16bitImage;
			pNewImage->CreateFromImageTransformed(Image, 
					rcRect.left, 
					rcRect.top, 
					cxImage,
					cyImage,
					(Metric)cxNewWidth / cxImage,
					(Metric)cyNewHeight / cyImage,
					0.0);

			//	Position

			int xImage = x + m_cxWidth - SHIP_IMAGE_WIDTH + (SHIP_IMAGE_WIDTH - cxNewWidth) / 2;
			int yImage = (SHIP_IMAGE_HEIGHT - cyNewHeight) / 2;

			//	New image frame

			IAnimatron *pImageFrame = new CAniRect;
			pImageFrame->SetPropertyVector(PROP_POSITION, CVector(xImage, yImage));
			pImageFrame->SetPropertyVector(PROP_SCALE, CVector(cxNewWidth, cyNewHeight));
			pImageFrame->SetFillMethod(new CAniImageFill(pNewImage, true));

			pRoot->AddTrack(pImageFrame, 0);
			}
		}

	//	Extra information

	CString sEpitaph = GameFile.GetEpitaph();
	int iScore = GameFile.GetScore();
	CTimeDate LocalTime = ModifiedTime.ToLocalTime();
	CString sModifiedTime = LocalTime.Format("%d %B %Y %I:%M %p");
	CString sFilename = pathGetFilename(GameFile.GetFilespec());

	CString sGameType;
	if (GameFile.IsRegistered())
		sGameType = CONSTLIT("Registered");
	else if (GameFile.IsDebug())
		sGameType = CONSTLIT("Debug");
	else
		sGameType = CONSTLIT("Unregistered");

	CString sExtra;
	if (!sEpitaph.IsBlank())
		sExtra = strPatternSubst(CONSTLIT("Score %d — %s\n%s — %s — %s"), iScore, sEpitaph, sGameType, sModifiedTime, sFilename);
	else if (iScore > 0)
		sExtra = strPatternSubst(CONSTLIT("Score %d\n%s — %s — %s"), iScore, sGameType, sModifiedTime, sFilename);
	else
		sExtra = strPatternSubst(CONSTLIT("%s — %s — %s"), sGameType, sModifiedTime, sFilename);

	pDesc = new CAniText;
	pDesc->SetPropertyVector(PROP_POSITION, CVector(xText, y));
	pDesc->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000));
	pDesc->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogLabel));
	pDesc->SetPropertyFont(PROP_FONT, &MediumFont);
	pDesc->SetPropertyString(PROP_TEXT, sExtra);

	pDesc->GetSpacingRect(&rcLine);

	pRoot->AddTrack(pDesc, 0);
	y += RectHeight(rcLine);

	//	Done

	*retpEntry = pRoot;

	if (retcyHeight)
		*retcyHeight = (bHasAdventureIcon ? Max(ADVENTURE_ICON_HEIGHT, y) : y);
	}
Exemple #2
0
ALERROR CDesignCollection::BindDesign (const TArray<CExtension *> &BindOrder, bool bNewGame, bool bNoResources, CString *retsError)

//	BindDesign
//
//	Binds the design collection to the set of design types in the given list of
//	extensions.

	{
	DEBUG_TRY

	ALERROR error;
	int i;

	//	Unbind everything

	DEBUG_TRY

	CShipClass::UnbindGlobal();

	for (i = 0; i < m_AllTypes.GetCount(); i++)
		m_AllTypes.GetEntry(i)->UnbindDesign();
	m_AllTypes.DeleteAll();

	DEBUG_CATCH_MSG("Crash unbinding types.");

	//	Reset the bind tables

	for (i = 0; i < designCount; i++)
		m_ByType[i].DeleteAll();

	m_CreatedTypes.DeleteAll(true);
	m_OverrideTypes.DeleteAll();

	//	Reset

	m_pTopology = NULL;
	m_pAdventureExtension = NULL;

	//	Create a design load context

	SDesignLoadCtx Ctx;
	Ctx.bBindAsNewGame = bNewGame;
	Ctx.bNoResources = bNoResources;

	//	Loop over the bind list in order and add appropriate types to m_AllTypes
	//	(The order guarantees that the proper types override)

	for (i = 0; i < BindOrder.GetCount(); i++)
		{
		CExtension *pExtension = BindOrder[i];

		try {

		const CDesignTable &Types = pExtension->GetDesignTypes();

#ifdef DEBUG_BIND
		::OutputDebugString(strPatternSubst(CONSTLIT("EXTENSION %s\n"), pExtension->GetName()));
		for (int j = 0; j < Types.GetCount(); j++)
			{
			::OutputDebugString(strPatternSubst(CONSTLIT("%08x: %s\n"), Types.GetEntry(j)->GetUNID(), Types.GetEntry(j)->GetTypeName()));
			}
#endif

		//	Run globals for the extension

		if (error = pExtension->ExecuteGlobals(Ctx))
			{
			*retsError = Ctx.sError;
			return error;
			}

		//	Add the types

		m_AllTypes.Merge(Types, &m_OverrideTypes);

		//	If this is the adventure, then remember it

		if (pExtension->GetType() == extAdventure)
			{
			m_pAdventureExtension = pExtension;
			m_pAdventureDesc = pExtension->GetAdventureDesc();
			}

		//	If this is an adventure or the base extension then take the 
		//	topology.

		if (pExtension->GetType() == extAdventure || pExtension->GetType() == extBase)
			m_pTopology = &pExtension->GetTopology();

		} catch (...)
			{
			::kernelDebugLogMessage("Crash processing extension:");
			CExtension::DebugDump(pExtension, true);
			throw;
			}
		}

	//	If this is a new game, then create all the Template types

	if (bNewGame)
		{
		DEBUG_TRY

		m_DynamicUNIDs.DeleteAll();
		m_DynamicTypes.DeleteAll();

		if (error = FireOnGlobalTypesInit(Ctx))
			{
			*retsError = Ctx.sError;
			return error;
			}

		if (error = CreateTemplateTypes(Ctx))
			{
			*retsError = Ctx.sError;
			return error;
			}

		DEBUG_CATCH_MSG("Crash defining dynamic types.");
		}

	//	Add all the dynamic types. These came either from the saved game file or
	//	from the Template types above.

	m_AllTypes.Merge(m_DynamicTypes, &m_OverrideTypes);

	//	Now resolve all overrides and inheritance

	if (error = ResolveOverrides(Ctx))
		{
		*retsError = Ctx.sError;
		return error;
		}

	//	Initialize the byType lists

	DEBUG_TRY
	for (i = 0; i < m_AllTypes.GetCount(); i++)
		{
		CDesignType *pEntry = m_AllTypes.GetEntry(i);
		m_ByType[pEntry->GetType()].AddEntry(pEntry);
		}
	DEBUG_CATCH_MSG("Crash initializing byType lists.");

	//	Set our adventure desc as current; since adventure descs are always 
	//	loaded this is the only thing that we can use to tell if we should
	//	call global events.
	//
	//	This must happen after Unbind (because that clears it) and before
	//	PrepareBindDesign.
	//
	//	NOTE: m_pAdventureDesc can be NULL (e.g., in the intro screen).

	DEBUG_TRY
	if (m_pAdventureDesc)
		m_pAdventureDesc->SetCurrentAdventure();
	DEBUG_CATCH_MSG("Crash setting current adventure.");

	//	Cache a map between currency name and economy type
	//	We need to do this before Bind because some types will lookup
	//	a currency name during Bind.

	DEBUG_TRY
	m_EconomyIndex.DeleteAll();
	for (i = 0; i < GetCount(designEconomyType); i++)
		{
		CEconomyType *pEcon = CEconomyType::AsType(GetEntry(designEconomyType, i));
		const CString &sName = pEcon->GetSID();

		bool bUnique;
		CEconomyType **ppDest = m_EconomyIndex.SetAt(sName, &bUnique);
		if (!bUnique)
			{
			pEcon->ComposeLoadError(Ctx, CONSTLIT("Currency ID must be unique"));
			*retsError = Ctx.sError;
			return ERR_FAIL;
			}

		*ppDest = pEcon;
		}
	DEBUG_CATCH_MSG("Crash initializing economies.");

	//	Prepare to bind. This is used by design elements that need two passes
	//	to bind. We also use it to set up the inheritence hierarchy, which means
	//	that we rely on the map from UNID to valid design type (m_AllTypes)

	m_DisplayAttribs.DeleteAll();

	DEBUG_TRY
	for (i = 0; i < m_AllTypes.GetCount(); i++)
		{
		CDesignType *pEntry = m_AllTypes.GetEntry(i);
		if (error = pEntry->PrepareBindDesign(Ctx))
			{
			*retsError = Ctx.sError;
			return error;
			}

		//	We take this opportunity to build a list of display attributes
		//	defined by each type.

		const CDisplayAttributeDefinitions &Attribs = pEntry->GetDisplayAttributes();
		if (!Attribs.IsEmpty())
			m_DisplayAttribs.Append(Attribs);
		}
	DEBUG_CATCH_MSG("Crash in PrepareBind.");

	//	Now call Bind on all active design entries

	for (i = 0; i < evtCount; i++)
		m_EventsCache[i]->DeleteAll();

	DEBUG_TRY
	for (i = 0; i < m_AllTypes.GetCount(); i++)
		{
		CDesignType *pEntry = m_AllTypes.GetEntry(i);
		if (error = pEntry->BindDesign(Ctx))
			{
			*retsError = Ctx.sError;
			return error;
			}

		//	Cache some global events. We keep track of the global events for
		//	all types so that we can access them faster.

		CacheGlobalEvents(pEntry);
		}
	DEBUG_CATCH_MSG("Crash in BindDesign.");

	//	Finish binding. This pass is used by design elements
	//	that need to do stuff after all designs are bound.

	DEBUG_TRY
	for (i = 0; i < m_AllTypes.GetCount(); i++)
		{
		CDesignType *pEntry = m_AllTypes.GetEntry(i);
		if (error = pEntry->FinishBindDesign(Ctx))
			{
			*retsError = Ctx.sError;
			return error;
			}
		}
	DEBUG_CATCH_MSG("Crash in FinishBind.");

	//	Remember what we bound

	m_BoundExtensions = BindOrder;

	return NOERROR;

	DEBUG_CATCH
	}