CSpaceObject *IDockScreenDisplay::EvalListSource (const CString &sString, CString *retsError)

//	EvalListSource
//
//	Returns the object from which we should display items

	{
	char *pPos = sString.GetPointer();

	//	See if we need to evaluate

	if (*pPos == '=')
		{
		CCodeChainCtx Ctx;
		Ctx.SetScreen(this);
		Ctx.SaveAndDefineSourceVar(m_pLocation);
		Ctx.SaveAndDefineDataVar(m_pData);

		ICCItem *pExp = Ctx.Link(sString, 1, NULL);

		ICCItem *pResult = Ctx.Run(pExp);	//	LATER:Event
		Ctx.Discard(pExp);

		if (pResult->IsError())
			{
			*retsError = pResult->GetStringValue();
			Ctx.Discard(pResult);
			return NULL;
			}

		//	Convert to an object pointer

		CSpaceObject *pSource;
		if (strEquals(pResult->GetStringValue(), DATA_FROM_PLAYER))
			pSource = m_pPlayer->GetShip();
		else if (strEquals(pResult->GetStringValue(), DATA_FROM_STATION)
				|| strEquals(pResult->GetStringValue(), DATA_FROM_SOURCE))
			pSource = m_pLocation;
		else
			pSource = Ctx.AsSpaceObject(pResult);

		Ctx.Discard(pResult);
		return pSource;
		}

	//	Otherwise, compare to constants

	else if (strEquals(sString, DATA_FROM_PLAYER))
		return m_pPlayer->GetShip();
	else
		return m_pLocation;
	}
bool IDockScreenDisplay::EvalBool (const CString &sCode, bool *retbResult, CString *retsError)

//	EvalBool
//
//	Evaluates the given string

	{
	CCodeChainCtx Ctx;
	Ctx.SetScreen(m_pDockScreen);
	Ctx.SaveAndDefineSourceVar(m_pLocation);
	Ctx.SaveAndDefineDataVar(m_pData);

	char *pPos = sCode.GetPointer();
	ICCItem *pExp = Ctx.Link(sCode, 1, NULL);

	ICCItem *pResult = Ctx.Run(pExp);	//	LATER:Event
	Ctx.Discard(pExp);

	if (pResult->IsError())
		{
		*retsError = pResult->GetStringValue();
		Ctx.Discard(pResult);
		return false;
		}

	*retbResult = !pResult->IsNil();
	Ctx.Discard(pResult);

	return true;
	}
Exemple #3
0
bool GetLinkedFireOptions (ICCItem *pArg, DWORD *retdwOptions, CString *retsError)

//	GetLinkedFireOptions
//
//	Parses a list of linked fire options

	{
	int i;

	DWORD dwOptions = 0;

	if (pArg && !pArg->IsNil())
		{
		SDesignLoadCtx LoadCtx;

		DWORD dwOption;
		for (i = 0; i < pArg->GetCount(); i++)
			{
			ICCItem *pOption = pArg->GetElement(i);

			if (CDeviceClass::ParseLinkedFireOptions(LoadCtx, pOption->GetStringValue(), &dwOption) != NOERROR)
				{
				*retsError = LoadCtx.sError;
				return false;
				}

			dwOptions |= dwOption;
			}
		}

	//	Done

	*retdwOptions = dwOptions;
	return true;
	}
Exemple #4
0
ALERROR CExtension::LoadGlobalsElement (SDesignLoadCtx &Ctx, CXMLElement *pDesc)

//	LoadGlobalsElement
//
//	Loads <Globals>

	{
	CCodeChainCtx CCCtx;

	//	Parse the code and keep it

	ICCItem *pCode = CCCtx.Link(pDesc->GetContentText(0), 0, NULL);
	if (pCode->IsError())
		{
		Ctx.sError = strPatternSubst(CONSTLIT("%s globals: %s"), Ctx.sErrorFilespec, pCode->GetStringValue());
		return ERR_FAIL;
		}

	SGlobalsEntry *pEntry = m_Globals.Insert();
	pEntry->pCode = pCode;
	pEntry->sFilespec = Ctx.sErrorFilespec;

#ifdef DEBUG_GLOBALS
	::kernelDebugLogMessage("Loading globals in %s", Ctx.sErrorFilespec);
#endif

	return NOERROR;
	}
Exemple #5
0
ICCItem *fnFind (CEvalContext *pCtx, ICCItem *pArgs, DWORD dwData)

//	fnFind
//
//	Finds a target in a source

	{
	int i;
	CCodeChain *pCC = pCtx->pCC;

	//	Get the source and target

	ICCItem *pSource = pArgs->GetElement(0);
	ICCItem *pTarget = pArgs->GetElement(1);

	//	If this is a list, then look for the target in the list and
	//	return the item position in the list

	int iPos;
	if (pSource->IsList())
		{
		iPos = -1;
		for (i = 0; i < pSource->GetCount(); i++)
			{
			ICCItem *pItem = pSource->GetElement(i);
			if (HelperCompareItems(pItem, pTarget) == 0)
				{
				iPos = i;
				break;
				}
			}
		}

	//	Otherwise, look for the target string in the source string

	else
		{
		iPos = strFind(pSource->GetStringValue(), pTarget->GetStringValue());
		}

	//	Done

	if (iPos == -1)
		return pCC->CreateNil();
	else
		return pCC->CreateInteger(iPos);
	}
ICCItem *CCSymbolTable::UnstreamItem (CCodeChain *pCC, IReadStream *pStream)

//	UnstreamItem
//
//	Unstream the sub-class specific data

	{
	ALERROR error;
	int i, iCount;

	//	Read the count

	if (error = pStream->Read((char *)&iCount, sizeof(iCount), NULL))
		return pCC->CreateSystemError(error);

	//	Read all the items

	for (i = 0; i < iCount; i++)
		{
		ICCItem *pItem;
		CString sKey;
		CObject *pOldEntry;

		//	Load the key

		pItem = pCC->UnstreamItem(pStream);
		if (pItem->IsError())
			return pItem;

		sKey = pItem->GetStringValue();
		pItem->Discard(pCC);

		//	Now load the value

		pItem = pCC->UnstreamItem(pStream);

		//	Note that we don't abort in case of an error
		//	because the list might contain errors

		//	Append the item to the symbol table

		if (m_Symbols.ReplaceEntry(sKey, pItem, TRUE, &pOldEntry) != NOERROR)
			return pCC->CreateMemoryError();

		//	No need to discard pItem because we're adding it to the
		//	symbol table.

		//	If we have a previous entry, decrement its refcount since we're
		//	throwing it away

		ASSERT(pOldEntry == NULL);
		}

	//	We are never a local symbol table

	m_bLocalFrame = FALSE;

	return pCC->CreateTrue();
	}
Exemple #7
0
void CEffectCreator::InitPainterParameters (CCreatePainterCtx &Ctx, IEffectPainter *pPainter)

//	InitPainterParameters
//
//	Initialize painter parameters

	{
	SEventHandlerDesc Event;
	if (FindEventHandlerEffectType(evtGetParameters, &Event))
		{
		CCodeChainCtx CCCtx;

		CCCtx.SaveAndDefineDataVar(Ctx.GetData());

		ICCItem *pResult = CCCtx.Run(Event);
		if (pResult->IsError())
			::kernelDebugLogMessage(CONSTLIT("EffectType %x GetParameters: %s"), GetUNID(), (LPSTR)pResult->GetStringValue());
		else if (pResult->IsSymbolTable())
			{
			int i;
			CCSymbolTable *pTable = (CCSymbolTable *)pResult;

			for (i = 0; i < pTable->GetCount(); i++)
				{
				CString sParam = pTable->GetKey(i);
				ICCItem *pValue = pTable->GetElement(i);
				CEffectParamDesc Value;

				if (pValue->IsNil())
					Value.InitNull();
				else if (pValue->IsInteger())
					Value.InitInteger(pValue->GetIntegerValue());
				else if (pValue->IsIdentifier())
					{
					CString sValue = pValue->GetStringValue();
					char *pPos = sValue.GetASCIIZPointer();

					//	If this is a color, parse it

					if (*pPos == '#')
						Value.InitColor(::LoadRGBColor(sValue));

					//	Otherwise, a string

					else
						Value.InitString(sValue);
					}

				pPainter->SetParam(Ctx, sParam, Value);
				}
			}
		else
			::kernelDebugLogMessage(CONSTLIT("EffectType %x GetParameters: Expected struct result."), GetUNID());

		CCCtx.Discard(pResult);
		}
	}
ALERROR CDesignCollection::CreateTemplateTypes (SDesignLoadCtx &Ctx)

//	CreateTemplateTypes
//
//	This is called inside of BindDesign to create all template types

	{
	ALERROR error;
	int i;

	//	Create an appropriate context for running code

	CCodeChainCtx CCCtx;

	//	Loop over all active types looking for templates.
	//	NOTE: We cannot use the type-specific arrays because they have not been
	//	set up yet (remember that we are inside of BindDesign).

	for (i = 0; i < m_AllTypes.GetCount(); i++)
		{
		CDesignType *pTemplate = m_AllTypes.GetEntry(i);
		if (pTemplate->GetType() != designTemplateType)
			continue;

		//	Get the function to generate the type source

		CString sSource;
		SEventHandlerDesc Event;
		if (pTemplate->FindEventHandler(GET_TYPE_SOURCE_EVENT, &Event))
			{
			ICCItem *pResult = CCCtx.Run(Event);
			if (pResult->IsError())
				{
				Ctx.sError = strPatternSubst(CONSTLIT("GetTypeSource (%x): %s"), pTemplate->GetUNID(), pResult->GetStringValue());
				return ERR_FAIL;
				}
			else if (pResult->IsNil())
				sSource = NULL_STR;
			else
				sSource = pResult->GetStringValue();

			CCCtx.Discard(pResult);
			}

		//	Define the type

		if (!sSource.IsBlank())
			{
			if (error = AddDynamicType(pTemplate->GetExtension(), pTemplate->GetUNID(), sSource, true, &Ctx.sError))
				return error;
			}
		}

	return NOERROR;
	}
Exemple #9
0
bool CCodeChainCtx::RunEvalString (const CString &sString, bool bPlain, CString *retsResult)

//	RunString
//
//	If sString starts with '=' or if bPlain is TRUE, then we evaluate sString as an
//	expression. If success (no error) we return TRUE. Otherwise, we return FALSE and
//	the error is in retsResult.

	{
	char *pPos = sString.GetPointer();

	if (bPlain || *pPos == '=')
		{
		ICCItem *pExp = Link(sString, (bPlain ? 0 : 1), NULL);

		ICCItem *pResult = Run(pExp);	//	LATER:Event
		Discard(pExp);

		if (pResult->IsError())
			{
			*retsResult = pResult->GetStringValue();
			Discard(pResult);
			return false;
			}

		//	Note: We use GetStringValue instead of Unlink because we don't
		//	want to preserve CC semantics (e.g., we don't need strings to
		//	be quoted).

		*retsResult = pResult->GetStringValue();
		Discard(pResult);
		return true;
		}
	else
		{
		*retsResult = strCEscapeCodes(sString);
		return true;
		}
	}
ALERROR CEventHandler::AddEvent (const CString &sEvent, const CString &sCode, CString *retsError)

//	AddEvent
//
//	Adds an event

	{
	ICCItem *pCode = g_pUniverse->GetCC().Link(sCode, 0, NULL);
	if (pCode->IsError())
		{
		if (retsError)
			*retsError = pCode->GetStringValue();
		return ERR_FAIL;
		}

	m_Handlers.Insert(sEvent, pCode);

	return NOERROR;
	}
Exemple #11
0
ALERROR CUniverse::LoadGlobals (SDesignLoadCtx &Ctx, CXMLElement *pElement)

//	LoadGlobals
//
//	Load global code

	{
	ICCItem *pCode = m_CC.Link(pElement->GetContentText(0), 0, NULL);
	ICCItem *pResult = m_CC.TopLevel(pCode, &g_pUniverse);
	if (pResult->IsError())
		{
		Ctx.sError = pResult->GetStringValue();
		return ERR_FAIL;
		}

	pResult->Discard(&m_CC);

	return NOERROR;
	}
void CAdventureDesc::FireOnGameStart (void)

//	FireOnGameStart
//
//	Fire OnGameStart event

{
    SEventHandlerDesc Event;

    if (FindEventHandler(ON_GAME_START_EVENT, &Event))
    {
        CCodeChainCtx Ctx;

        //	Run code

        ICCItem *pResult = Ctx.Run(Event);
        if (pResult->IsError())
            kernelDebugLogMessage("OnGameStart error: %s", pResult->GetStringValue());
        Ctx.Discard(pResult);
    }
}
CString CListWrapper::GetDescAtCursor (void)

//	GetDescAtCursor
//
//	Returns the description of the list element

	{
	if (IsCursorValid())
		{
		ICCItem *pItem = m_pList->GetElement(m_iCursor);
		if (DESC_INDEX < pItem->GetCount())
			{
			ICCItem *pDesc = pItem->GetElement(DESC_INDEX);
			if (pDesc->IsNil())
				return NULL_STR;

			return pDesc->GetStringValue();
			}
		}

	return NULL_STR;
	}
CString CListWrapper::GetTitleAtCursor (void)

//	GetTitleAtCursor
//
//	Returns the title of the list element

	{
	if (IsCursorValid())
		{
		ICCItem *pItem = m_pList->GetElement(m_iCursor);
		if (TITLE_INDEX < pItem->GetCount())
			{
			ICCItem *pTitle = pItem->GetElement(TITLE_INDEX);
			if (pTitle->IsNil())
				return NULL_STR;

			return pTitle->GetStringValue();
			}
		}

	return NULL_STR;
	}
ALERROR CEventHandler::InitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc)

//	InitFromXML
//
//	Load all handlers

	{
	int i;

	for (i = 0; i < pDesc->GetContentElementCount(); i++)
		{
		CXMLElement *pHandler = pDesc->GetContentElement(i);
		ICCItem *pCode = g_pUniverse->GetCC().Link(pHandler->GetContentText(0), 0, NULL);
		if (pCode->IsError())
			{
			Ctx.sError = strPatternSubst("<%s> event: %s", pHandler->GetTag(), pCode->GetStringValue());
			return ERR_FAIL;
			}

		//	If this is an old extension, then make sure the code is not using the
		//	gStation variable, because we no longer support it

		if (Ctx.pExtension && Ctx.pExtension->dwVersion < 2)
			{
			if (g_pUniverse->GetCC().HasIdentifier(pCode, CONSTLIT("gStation")))
				{
				Ctx.sError = CONSTLIT("gStation variable has been deprecated--use gSource instead.");
				return ERR_FAIL;
				}
			}

		//	Done

		m_Handlers.Insert(pHandler->GetTag(), pCode);
		}

	return NOERROR;
	}
void CAdventureDesc::FireOnGameEnd (const CGameRecord &Game, const SBasicGameStats &BasicStats)

//	FireOnGameEnd
//
//	Fire OnGameEnd event

{
    SEventHandlerDesc Event;

    if (FindEventHandler(ON_GAME_END_EVENT, &Event))
    {
        CCodeChainCtx Ctx;

        //	Initialize variables

        Ctx.DefineInteger(CONSTLIT("aScore"), Game.GetScore());
        Ctx.DefineInteger(CONSTLIT("aResurrectCount"), Game.GetResurrectCount());
        Ctx.DefineInteger(CONSTLIT("aSystemsVisited"), BasicStats.iSystemsVisited);
        Ctx.DefineInteger(CONSTLIT("aEnemiesDestroyed"), BasicStats.iEnemiesDestroyed);
        Ctx.DefineInteger(CONSTLIT("aBestEnemiesDestroyed"), BasicStats.iBestEnemyDestroyedCount);
        if (BasicStats.dwBestEnemyDestroyed)
            Ctx.DefineInteger(CONSTLIT("aBestEnemyClass"), BasicStats.dwBestEnemyDestroyed);
        else
            Ctx.DefineNil(CONSTLIT("aBestEnemyClass"));

        Ctx.DefineString(CONSTLIT("aEndGameReason"), Game.GetEndGameReason());
        Ctx.DefineString(CONSTLIT("aEpitaph"), Game.GetEndGameEpitaph());
        Ctx.DefineString(CONSTLIT("aEpitaphOriginal"), Game.GetEndGameEpitaph());
        Ctx.DefineString(CONSTLIT("aTime"), Game.GetPlayTimeString());

        //	Invoke

        ICCItem *pResult = Ctx.Run(Event);
        if (pResult->IsError())
            kernelDebugLogMessage("OnGameEnd error: %s", pResult->GetStringValue());
        Ctx.Discard(pResult);
    }
}
Exemple #17
0
ALERROR CExtension::ExecuteGlobals (SDesignLoadCtx &Ctx)

//	ExecuteGlobals
//
//	Execute the globals

	{
	DEBUG_TRY

	int i;
	CCodeChainCtx CCCtx;

	//	Add a hook so that all lambda expressions defined in this global block
	//	are wrapped with something that sets the extension UNID to the context.

	if (m_iType != extBase)
		CCCtx.SetGlobalDefineWrapper(this);

	//	Run the code (which will likely define a bunch of functions)

	for (i = 0; i < m_Globals.GetCount(); i++)
		{
		ICCItem *pResult = CCCtx.Run(m_Globals[i].pCode);
		if (pResult->IsError())
			{
			Ctx.sError = strPatternSubst(CONSTLIT("%s globals: %s"), m_Globals[i].sFilespec, pResult->GetStringValue());
			return ERR_FAIL;
			}

		CCCtx.Discard(pResult);
		}

	//	Done

	return NOERROR;

	DEBUG_CATCH
	}
Exemple #18
0
bool CDockPane::SetControlValue (const CString &sID, ICCItem *pValue)

//	SetControlValue
//
//	Sets the value of the given control. Return FALSE if we could not find a 
//	control of the given ID.

	{
	CCodeChain &CC = g_pUniverse->GetCC();

	SControl *pControl;
	if (!FindControl(sID, &pControl))
		return false;

	switch (pControl->iType)
		{
		case controlCounter:
			{
			CGTextArea *pTextArea = pControl->AsTextArea();
			CString sText = strFromInt(pValue->GetIntegerValue());
			pTextArea->SetText(sText);
			pControl->bReplaceInput = true;
			return true;
			}

		case controlDesc:
			{
			CGTextArea *pTextArea = pControl->AsTextArea();
			CUIHelper UIHelper(*g_pHI);
			CString sRTF;
			UIHelper.GenerateDockScreenRTF(pValue->GetStringValue(), &sRTF);

			pTextArea->SetRichText(sRTF);
			return true;
			}

		case controlItemDisplay:
			{
			CGItemDisplayArea *pItemDisplayArea = pControl->AsItemDisplayArea();

			//	Nil means nil

			if (pValue->IsNil())
				{
				pItemDisplayArea->SetItem(NULL, CItem::NullItem());
				return true;
				}

			//	If a structure, we expect two fields:

			else if (pValue->IsSymbolTable())
				{
				ICCItem *pItemCC = pValue->GetElement(CONSTLIT("item"));
				if (pItemCC == NULL)
					{
					CString sTitle;
					CString sDesc;

					//	If no item, then we expect title and desc

					ICCItem *pTitleCC = pValue->GetElement(CONSTLIT("title"));
					if (pTitleCC)
						sTitle = pTitleCC->GetStringValue();

					ICCItem *pDescCC = pValue->GetElement(CONSTLIT("desc"));
					if (pDescCC)
						sDesc = pDescCC->GetStringValue();

					pItemDisplayArea->SetItem(NULL, CItem::NullItem());
					pItemDisplayArea->SetText(sTitle, sDesc);

					return true;
					}

				CItem Item = ::CreateItemFromList(CC, pItemCC);

				CSpaceObject *pSource = NULL;
				ICCItem *pSourceCC = pValue->GetElement(CONSTLIT("source"));
				if (pSourceCC)
					pSource = ::CreateObjFromItem(CC, pSourceCC);

				pItemDisplayArea->SetItem(pSource, Item);
				return true;
				}

			//	If this is a list then we expect an item value

			else if (pValue->IsList())
				{
				CItem Item = ::CreateItemFromList(CC, pValue);
				pItemDisplayArea->SetItem(NULL, Item);
				return true;
				}

			return false;
			}

		case controlTextInput:
			{
			CGTextArea *pTextArea = pControl->AsTextArea();
			CString sValue = pValue->GetStringValue();
			pTextArea->SetText(sValue);
			pTextArea->SetCursor(0, sValue.GetLength());
			return true;
			}
		}

	return false;
	}
ALERROR CLanguageDataBlock::InitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc)

//	InitFromXML
//
//	Initializes from an XML block

	{
	int i;

	for (i = 0; i < pDesc->GetContentElementCount(); i++)
		{
		CXMLElement *pItem = pDesc->GetContentElement(i);
		CString sID = pItem->GetAttribute(ID_ATTRIB);
		if (sID.IsBlank())
			{
			Ctx.sError = strPatternSubst(CONSTLIT("Invalid id in <Language> block"));
			return ERR_FAIL;
			}

		if (strEquals(pItem->GetTag(), TEXT_TAG))
			{
			//	Link the code

			CCodeChainCtx CCCtx;
			ICCItem *pCode = CCCtx.Link(pItem->GetContentText(0), 0, NULL);
			if (pCode->IsError())
				{
				Ctx.sError = strPatternSubst(CONSTLIT("Language id: %s : %s"), sID, pCode->GetStringValue());
				return ERR_FAIL;
				}

			//	Add an entry

			bool bIsNew;
			SEntry *pEntry = m_Data.SetAt(sID, &bIsNew);
			if (!bIsNew)
				{
				Ctx.sError = strPatternSubst(CONSTLIT("Duplicate <Language> element: %s"), sID);
				return ERR_FAIL;
				}

			//	If pCode is a string and not an identifier, then we can just
			//	store it directly.

			if (pCode->IsIdentifier() && pCode->IsQuoted())
				{
				pEntry->pCode = NULL;
				pEntry->sText = pCode->GetStringValue();
				}

			//	Otherwise we store the code

			else
				pEntry->pCode = pCode->Reference();

			//	Done

			CCCtx.Discard(pCode);
			}
		else if (strEquals(pItem->GetTag(), MESSAGE_TAG))
			{
			//	Add an entry

			bool bIsNew;
			SEntry *pEntry = m_Data.SetAt(sID, &bIsNew);
			if (!bIsNew)
				{
				Ctx.sError = strPatternSubst(CONSTLIT("Duplicate <Language> element: %s"), sID);
				return ERR_FAIL;
				}

			//	Set the text

			pEntry->pCode = NULL;
			pEntry->sText = pItem->GetAttribute(TEXT_ATTRIB);
			}
		else
			{
			Ctx.sError = strPatternSubst(CONSTLIT("Invalid element in <Language> block: <%s>"), pItem->GetTag());
			return ERR_FAIL;
			}
		}

	return NOERROR;
	}
CLanguageDataBlock::ETranslateResult CLanguageDataBlock::Translate (CSpaceObject *pObj, const CString &sID, TArray<CString> *retText, CString *retsText) const

//	Translate
//
//	Translates an entry to either a string or an array of strings.

	{
	int i;

	//	If we can't find this ID then we can't translate

	SEntry *pEntry = m_Data.GetAt(sID);
	if (pEntry == NULL)
		return resultNotFound;

	//	If we don't want the text back then all we need to do is return that we
	//	have the text.

	if (retText == NULL && retsText == NULL)
		return resultFound;

	//	If we don't need to run code then we just return the string.

	if (pEntry->pCode == NULL)
		{
		if (retsText)
			{
			*retsText = ::ComposePlayerNameString(pEntry->sText, g_pUniverse->GetPlayerName(), g_pUniverse->GetPlayerGenome());
			return resultString;
			}
		else
			return resultFound;
		}

	//	Otherwise we have to run some code

	CCodeChainCtx Ctx;
	Ctx.SaveAndDefineSourceVar(pObj);
	Ctx.DefineString(CONSTLIT("aTextID"), sID);
	
	ICCItem *pResult = Ctx.Run(pEntry->pCode);	//	LATER:Event
	ETranslateResult iResult;

	//	Nil

	if (pResult->IsNil())
		iResult = resultNotFound;

	//	List of strings

	else if (pResult->GetCount() > 1)
		{
		if (retText)
			{
			CString sPlayerName = g_pUniverse->GetPlayerName();
			GenomeTypes iPlayerGenome = g_pUniverse->GetPlayerGenome();

			retText->DeleteAll();

			retText->InsertEmpty(pResult->GetCount());
			for (i = 0; i < pResult->GetCount(); i++)
				retText->GetAt(i) = ::ComposePlayerNameString(pResult->GetElement(i)->GetStringValue(), sPlayerName, iPlayerGenome);

			iResult = resultArray;
			}
		else
			iResult = resultFound;
		}

	//	String

	else
		{
		if (retsText)
			{
			*retsText = ::ComposePlayerNameString(pResult->GetStringValue(), g_pUniverse->GetPlayerName(), g_pUniverse->GetPlayerGenome());
			iResult = resultString;
			}
		else
			iResult = resultFound;
		}

	//	Done

	Ctx.Discard(pResult);

	return iResult;
	}
Exemple #21
0
ICCItem *fnPageMap (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData)

//	fnPageMap
//
//	(pageMap address|pageID enumMethod ['excludeNil] var exp) -> filtered list

	{
	CCodeChain *pCC = pEvalCtx->pCC;

	//	Args

	ICCItem *pAddress = pArgs->GetElement(0);
	ICCItem *pMethod = pArgs->GetElement(1);

	bool bExcludeNil;
	int iOptionalArg = 2;
	if (pArgs->GetCount() > 4)
		bExcludeNil = strEquals(pArgs->GetElement(iOptionalArg++)->GetStringValue(), CONSTLIT("excludeNil"));
	else
		bExcludeNil = false;

	ICCItem *pVar = pArgs->GetElement(iOptionalArg++);
	ICCItem *pBody = pArgs->GetElement(iOptionalArg++);

	//	Open the page

	IPage *pPage;
	CString sError;
	if (g_PM.OpenPage(pAddress->GetStringValue(), &pPage, &sError) != NOERROR)
		return pCC->CreateError(sError, NULL);

	//	Prepare the method

	SPageEnumCtx EnumCtx;
	if (pPage->EnumReset(*pCC, pMethod, EnumCtx, &sError))
		{
		g_PM.ClosePage(pPage);
		return pCC->CreateError(sError, NULL);
		}

	//	Create a destination list

	ICCItem *pResult = pCC->CreateLinkedList();
	if (pResult->IsError())
		{
		g_PM.ClosePage(pPage);
		return pResult;
		}

	CCLinkedList *pList = (CCLinkedList *)pResult;

	//	Setup the locals. We start by creating a local symbol table

	ICCItem *pLocalSymbols = pCC->CreateSymbolTable();
	if (pLocalSymbols->IsError())
		{
		pResult->Discard(pCC);
		g_PM.ClosePage(pPage);
		return pLocalSymbols;
		}

	//	Associate the enumaration variable

	ICCItem *pError = pLocalSymbols->AddEntry(pCC, pVar, pCC->CreateNil());
	if (pError->IsError())
		{
		pLocalSymbols->Discard(pCC);
		pResult->Discard(pCC);
		g_PM.ClosePage(pPage);
		return pError;
		}

	pError->Discard(pCC);

	//	Setup the context

	if (pEvalCtx->pLocalSymbols)
		pLocalSymbols->SetParent(pEvalCtx->pLocalSymbols);
	else
		pLocalSymbols->SetParent(pEvalCtx->pLexicalSymbols);
	ICCItem *pOldSymbols = pEvalCtx->pLocalSymbols;
	pEvalCtx->pLocalSymbols = pLocalSymbols;

	//	Get the offset of the variable so we don't have to
	//	search for it all the time

	int iVarOffset = pLocalSymbols->FindOffset(pCC, pVar);

	//	Enumerate the page

	while (pPage->EnumHasMore(EnumCtx))
		{
		ICCItem *pItem = pPage->EnumGetNext(*pCC, EnumCtx);
		if (pItem->IsError())
			{
			pResult->Discard(pCC);
			pResult = pItem;
			break;
			}

		//	Set the element

		pLocalSymbols->AddByOffset(pCC, iVarOffset, pItem);

		//	Eval

		ICCItem *pMapped = pCC->Eval(pEvalCtx, pBody);
		if (pMapped->IsError())
			{
			pItem->Discard(pCC);
			pResult->Discard(pCC);
			pResult = pMapped;
			break;
			}

		//	If the evaluation is not Nil, then we include the
		//	item in the result

		if (!bExcludeNil || !pMapped->IsNil())
			pList->Append(*pCC, pMapped);

		pItem->Discard(pCC);
		pMapped->Discard(pCC);
		}

	//	Clean up

	pEvalCtx->pLocalSymbols = pOldSymbols;
	pLocalSymbols->Discard(pCC);
	g_PM.ClosePage(pPage);

	//	Done

	if (pResult->GetCount() > 0)
		return pResult;
	else
		{
		pResult->Discard(pCC);
		return pCC->CreateNil();
		}
	}
Exemple #22
0
ICCItem *fnPageGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData)

//	fnPageGet
//
//	(pageGet address|pageID enumMethod [startIndex] [count]) -> list

	{
	CCodeChain *pCC = pEvalCtx->pCC;

	//	Args

	ICCItem *pAddress = pArgs->GetElement(0);
	ICCItem *pMethod = pArgs->GetElement(1);
	int iStart = (pArgs->GetCount() > 2 ? pArgs->GetElement(2)->GetIntegerValue() : 0);
	int iCount = (pArgs->GetCount() > 3 ? pArgs->GetElement(3)->GetIntegerValue() : -1);

	//	Open the page

	IPage *pPage;
	CString sError;
	if (g_PM.OpenPage(pAddress->GetStringValue(), &pPage, &sError) != NOERROR)
		return pCC->CreateError(sError, NULL);

	//	Prepare the method

	SPageEnumCtx EnumCtx;
	if (pPage->EnumReset(*pCC, pMethod, EnumCtx, &sError))
		{
		g_PM.ClosePage(pPage);
		return pCC->CreateError(sError, NULL);
		}

	//	Create a destination list

	ICCItem *pResult = pCC->CreateLinkedList();
	if (pResult->IsError())
		{
		g_PM.ClosePage(pPage);
		return pResult;
		}

	CCLinkedList *pList = (CCLinkedList *)pResult;

	//	Enumerate the page

	while ((iCount == -1 || iCount > 0) && pPage->EnumHasMore(EnumCtx))
		{
		ICCItem *pItem = pPage->EnumGetNext(*pCC, EnumCtx);
		if (pItem->IsError())
			{
			pResult->Discard(pCC);
			pResult = pItem;
			break;
			}

		//	Add to list

		if (iStart == 0)
			{
			pList->Append(*pCC, pItem);
			iCount--;
			}
		else
			iStart--;

		pItem->Discard(pCC);
		}

	//	Clean up

	g_PM.ClosePage(pPage);

	//	Done

	if (pResult->GetCount() > 0)
		return pResult;
	else
		{
		pResult->Discard(pCC);
		return pCC->CreateNil();
		}
	}
bool CWeaponFireDesc::FireOnDamageShields (SDamageCtx &Ctx, int iDevice)

//	FireOnDamageShields
//
//	Fire OnDamageShields event. Returns TRUE if we should skip further shields damage

	{
	SEventHandlerDesc Event;
	if (FindEventHandler(evtOnDamageShields, &Event))
		{
		//	Setup arguments

		CCodeChainCtx CCCtx;

		CItemListManipulator ItemList(Ctx.pObj->GetItemList());
		CShip *pShip = Ctx.pObj->AsShip();
		if (pShip)
			pShip->SetCursorAtDevice(ItemList, iDevice);

		CCCtx.SaveAndDefineSourceVar(Ctx.pObj);
		CCCtx.DefineInteger(CONSTLIT("aArmorSeg"), Ctx.iSectHit);
		CCCtx.DefineInteger(CONSTLIT("aDevice"), iDevice);
		CCCtx.DefineItem(CONSTLIT("aDeviceItem"), ItemList.GetItemAtCursor());
		CCCtx.DefineSpaceObject(CONSTLIT("aCause"), Ctx.pCause);
		CCCtx.DefineSpaceObject(CONSTLIT("aAttacker"), Ctx.Attacker.GetObj());
		CCCtx.DefineSpaceObject(CONSTLIT("aOrderGiver"), (Ctx.Attacker.GetObj() ? Ctx.Attacker.GetObj()->GetOrderGiver(Ctx.Attacker.GetCause()) : NULL));
		CCCtx.DefineVector(CONSTLIT("aHitPos"), Ctx.vHitPos);
		CCCtx.DefineInteger(CONSTLIT("aHitDir"), Ctx.iDirection);
		CCCtx.DefineInteger(CONSTLIT("aDamageHP"), Ctx.iDamage);
		CCCtx.DefineString(CONSTLIT("aDamageType"), GetDamageShortName(Ctx.Damage.GetDamageType()));
		CCCtx.DefineItemType(CONSTLIT("aWeaponType"), Ctx.pDesc->GetWeaponType());

		CCCtx.DefineInteger(CONSTLIT("aShieldHP"), Ctx.iHPLeft);
		CCCtx.DefineInteger(CONSTLIT("aShieldDamageHP"), Ctx.iShieldDamage);
		CCCtx.DefineInteger(CONSTLIT("aArmorDamageHP"), Ctx.iDamage - Ctx.iAbsorb);
		if (Ctx.bReflect)
			{
			CCCtx.DefineString(CONSTLIT("aShieldReflect"), STR_SHIELD_REFLECT);
			CCCtx.DefineInteger(CONSTLIT("aOriginalShieldDamageHP"), Ctx.iOriginalShieldDamage);
			CCCtx.DefineInteger(CONSTLIT("aOriginalArmorDamageHP"), Ctx.iDamage - Ctx.iOriginalAbsorb);
			}
		else
			{
			CCCtx.DefineNil(CONSTLIT("aShieldReflect"));
			CCCtx.DefineInteger(CONSTLIT("aOriginalShieldDamageHP"), Ctx.iShieldDamage);
			CCCtx.DefineInteger(CONSTLIT("aOriginalArmorDamageHP"), Ctx.iDamage - Ctx.iAbsorb);
			}

		ICCItem *pResult = CCCtx.Run(Event);

		//	If we return Nil, then we continue processing

		bool bResult;
		if (pResult->IsNil())
			bResult = false;

		//	If this is an integer, we pass damage to armor

		else if (pResult->IsInteger())
			{
			Ctx.iDamage = pResult->GetIntegerValue();
			bResult = true;
			}

		//	If we return a list, then modify variables

		else if (pResult->IsList())
			{
			//	A single value means we modified the damage to armor

			if (pResult->GetCount() == 1)
				{
				if (strEquals(pResult->GetElement(0)->GetStringValue(), STR_SHIELD_REFLECT))
					{
					Ctx.bReflect = true;
					Ctx.iAbsorb = Ctx.iDamage;
					Ctx.iShieldDamage = 0;
					}
				else
					{
					Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(0)->GetIntegerValue(), Ctx.iHPLeft));
					if (Ctx.bReflect)
						{
						Ctx.bReflect = false;
						Ctx.iAbsorb = Ctx.iOriginalAbsorb;
						}
					}
				}

			//	Two values mean we modified both damage to armor and shield damage

			else if (pResult->GetCount() == 2)
				{
				Ctx.bReflect = false;
				Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(0)->GetIntegerValue(), Ctx.iHPLeft));
				Ctx.iAbsorb = Max(0, Ctx.iDamage - Max(0, pResult->GetElement(1)->GetIntegerValue()));
				}

			//	Otherwise, we deal with reflection

			else
				{
				Ctx.bReflect = strEquals(pResult->GetElement(0)->GetStringValue(), STR_SHIELD_REFLECT);
				Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(1)->GetIntegerValue(), Ctx.iHPLeft));
				Ctx.iAbsorb = Max(0, Ctx.iDamage - Max(0, pResult->GetElement(2)->GetIntegerValue()));
				}

			//	Proceed with processing

			bResult = false;
			}

		//	If this is the string "reflect" then we reflect

		else if (strEquals(pResult->GetStringValue(), STR_SHIELD_REFLECT))
			{
			Ctx.bReflect = true;
			Ctx.iAbsorb = Ctx.iDamage;
			Ctx.iShieldDamage = 0;
			bResult = false;
			}

		//	Otherwise, error

		else
			{
			Ctx.pObj->ReportEventError(ON_DAMAGE_OVERLAY_EVENT, pResult);
			bResult = true;
			}

		CCCtx.Discard(pResult);

		return bResult;
		}
	else
		return false;
	}
Exemple #24
0
CString ComposePlayerNameString (const CString &sString, const CString &sPlayerName, int iGenome, ICCItem *pArgs)

//	ComposePlayerNameString
//
//	Replaces the following variables:
//
//		%name%				player name
//		%he%				he or she
//		%his%				his or her (matching case)
//		%hers%				his or hers (matching case)
//		%him%				him or her (matching case)
//		%sir%				sir or ma'am (matching case)
//		%man%				man or woman (matching case)
//		%brother%			brother or sister (matching case)
//		%%					%

{
    //	Prepare output

    CString sOutput;
    int iOutLeft = sString.GetLength() * 2;
    char *pOut = sOutput.GetWritePointer(iOutLeft);

    //	Compose. Loop once for each segment that we need to add

    bool bDone = false;
    bool bVar = false;
    char *pPos = sString.GetASCIIZPointer();
    while (!bDone)
    {
        CString sVar;
        char *pSeg;
        char *pSegEnd;

        if (bVar)
        {
            ASSERT(*pPos == '%');

            //	Skip %

            pPos++;
            char *pStart = pPos;
            while (*pPos != '%' && *pPos != '\0')
                pPos++;

            sVar = CString(pStart, pPos - pStart);

            //	Skip the next %

            if (*pPos == '%')
            {
                pPos++;
                bVar = false;
            }
            else
                bDone = true;

            bool bCapitalize = (*sVar.GetASCIIZPointer() >= 'A' && *sVar.GetASCIIZPointer() <= 'Z');

            //	Setup the segment depending on the variable

            if (sVar.IsBlank())
                sVar = CONSTLIT("%");
            else if (strEquals(sVar, CONSTLIT("name")))
                sVar = sPlayerName;
            else if (strEquals(sVar, CONSTLIT("he")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("he");
                else
                    sVar = CONSTLIT("she");
            }
            else if (strEquals(sVar, CONSTLIT("sir")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("sir");
                else
                    sVar = CONSTLIT("ma'am");
            }
            else if (strEquals(sVar, CONSTLIT("man")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("man");
                else
                    sVar = CONSTLIT("woman");
            }
            else if (strEquals(sVar, CONSTLIT("his")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("his");
                else
                    sVar = CONSTLIT("her");
            }
            else if (strEquals(sVar, CONSTLIT("him")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("him");
                else
                    sVar = CONSTLIT("her");
            }
            else if (strEquals(sVar, CONSTLIT("hers")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("his");
                else
                    sVar = CONSTLIT("hers");
            }
            else if (strEquals(sVar, CONSTLIT("brother")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("brother");
                else
                    sVar = CONSTLIT("sister");
            }
            else if (strEquals(sVar, CONSTLIT("son")))
            {
                if (iGenome == genomeHumanMale)
                    sVar = CONSTLIT("son");
                else
                    sVar = CONSTLIT("daughter");
            }
            else if (pArgs)
            {
                int iArg = strToInt(sVar, 0);
                if (iArg < 0)
                {
                    iArg = -iArg;
                    bCapitalize = true;
                }

                if (iArg > 0)
                {
                    ICCItem *pArg = pArgs->GetElement(iArg + 1);
                    if (pArg)
                        sVar = pArg->GetStringValue();
                }
            }

            //	If we could not find a valid var, then we assume a
            //	single % sign.

            else
            {
                sVar = CONSTLIT("%");
                pPos = pStart;
                bDone = (*pPos == '\0');
                bVar = false;
                bCapitalize = false;
            }

            //	Capitalize, if necessary

            if (bCapitalize)
                sVar = strCapitalize(sVar);

            //	Setup segment

            pSeg = sVar.GetASCIIZPointer();
            pSegEnd = pSeg + sVar.GetLength();
        }
        else
        {
            //	Skip to the next variable or the end of the string

            pSeg = pPos;
            while (*pPos != '%' && *pPos != '\0')
                pPos++;

            if (*pPos == '\0')
                bDone = true;
            else
                bVar = true;

            pSegEnd = pPos;
        }

        //	Add the next segment

        int iLen = pSegEnd - pSeg;
        if (iLen > 0)
        {
            if (iLen > iOutLeft)
            {
                int iAlloc = sOutput.GetLength();
                int iCurLen = iAlloc - iOutLeft;
                int iNewAlloc = max(iAlloc * 2, iAlloc + iLen);
                pOut = sOutput.GetWritePointer(iNewAlloc);
                pOut += iCurLen;
                iOutLeft = iNewAlloc - iCurLen;
            }

            while (pSeg < pSegEnd)
                *pOut++ = *pSeg++;

            iOutLeft -= iLen;
        }
    }

    //	Done

    int iAlloc = sOutput.GetLength();
    int iCurLen = iAlloc - iOutLeft;
    sOutput.Truncate(iCurLen);
    return sOutput;
}
void CRandomEnhancementGenerator::EnhanceItem (CItem &Item)

//	EnhanceItem
//
//	Enhances the given item

	{
	//	See if this item is enhanced

	if (mathRandom(1, 100) > m_iChance)
		return;

	//	If we have code, execute the code to figure out the mod

	if (m_pCode)
		{
		CCodeChainCtx Ctx;

		//	Save the previous value of gItem

		Ctx.SaveItemVar();
		Ctx.DefineItem(Item);

		//	Execute the code

		ICCItem *pResult = Ctx.Run(m_pCode);	//	LATER:Event

		//	If we have an error, report it

		DWORD dwMods;
		if (pResult->IsError())
			{
			CString sError = strPatternSubst(CONSTLIT("Generate Enhancement: %s"), pResult->GetStringValue());
			kernelDebugLogMessage(sError);
			dwMods = 0;
			}

		//	Otherwise, the result code is the mods

		else
			dwMods = (DWORD)pResult->GetIntegerValue();

		//	Done with code

		Ctx.Discard(pResult);

		//	Enhance the item

		Item.AddEnhancement(dwMods);
		}

	//	Otherwise, if we have a constant mod, apply that

	else if (m_dwMods)
		{
		Item.AddEnhancement(m_dwMods);
		}

	//	Otherwise, we need to generate a random mod appropriate to the
	//	particular item

	else
		{
		DWORD dwMods;
		CItemType *pType = Item.GetType();
		int iRoll = mathRandom(1, 100);

		switch (pType->GetCategory())
			{
			case itemcatArmor:
			case itemcatShields:
				if (iRoll < 40)
					//	HP + 10%
					dwMods = 0x0101;
				else if (iRoll < 65)
					//	HP + 20%
					dwMods = 0x0102;
				else if (iRoll < 80)
					//	HP + 30%
					dwMods = 0x0103;
				else if (iRoll < 90)
					//	Damage Adj at 50% (and 75%)
					dwMods = 0x0A05 + (mathRandom(0, 3) << 4);
				else if (iRoll < 95)
					//	Immunity to special ion attacks
					dwMods = 0x0C00;
				else
					//	Regeneration
					dwMods = 0x0200;
				break;

			case itemcatWeapon:
				if (iRoll < 50)
					//	Damage + 10%
					dwMods = 0x0101;
				else if (iRoll < 80)
					//	Damage + 20%
					dwMods = 0x0102;
				else if (iRoll < 95)
					//	Damage + 30%
					dwMods = 0x0103;
				else
					//	Delay time at 70% of original
					dwMods = 0x1003;
				break;

			default:
				dwMods = 0;
			}

		Item.AddEnhancement(dwMods);
		}
	}
Exemple #26
0
void RunFile (const CString &sFilespec, bool bNoLogo)
	{
	ALERROR error;
	CCodeChain &CC = g_pUniverse->GetCC();
	CCodeChainCtx Ctx;

	//	Verify the file

	CString sRunFile = sFilespec;
	if (!strEndsWith(sRunFile, CONSTLIT("."))
			&& pathGetExtension(sRunFile).IsBlank())
		sRunFile.Append(CONSTLIT(".tlisp"));

	//	Open the file

	CFileReadBlock InputFile(sRunFile);
	if (error = InputFile.Open())
		{
		printf("error : Unable to open file '%s'.\n", sRunFile.GetASCIIZPointer());
		return;
		}

	if (!bNoLogo)
		printf("%s\n", sRunFile.GetASCIIZPointer());

	//	Parse

	CString sInputFile(InputFile.GetPointer(0), InputFile.GetLength(), TRUE);
	CString sOutput;
	int iOffset = 0;

	while (true)
		{
		int iCharCount;
		ICCItem *pCode = Ctx.Link(sInputFile, iOffset, &iCharCount);
		if (pCode->IsNil())
			break;
		else if (pCode->IsError())
			{
			printf("error : %s\n", pCode->GetStringValue().GetASCIIZPointer());
			Ctx.Discard(pCode);
			return;
			}

		iOffset += iCharCount;

		//	Execute

		ICCItem *pResult = Ctx.Run(pCode);

		//	Compose output

		if (pResult->IsIdentifier())
			sOutput = pResult->Print(&CC, PRFLAG_NO_QUOTES | PRFLAG_ENCODE_FOR_DISPLAY);
		else
			sOutput = CC.Unlink(pResult);

		//	Free

		Ctx.Discard(pResult);
		Ctx.Discard(pCode);
		}

	//	Output result

	printf("%s\n", sOutput.GetASCIIZPointer());
	}
Exemple #27
0
ICCItem *CCLambda::Execute (CEvalContext *pCtx, ICCItem *pArgs)

//	Execute
//
//	Executes the function and returns a result

	{
	CCodeChain *pCC = pCtx->pCC;
	ICCItem *pItem;
	ICCItem *pOldSymbols;
	ICCItem *pLocalSymbols;
	ICCItem *pVar;
	ICCItem *pArg;
	ICCItem *pResult;
	int i;
	BOOL bNoEval;

	//	We must have been initialized

	if (m_pArgList == NULL || m_pCode == NULL)
		return pCC->CreateNil();

	//	If the argument list if quoted, then it means that the arguments
	//	have already been evaluated. This happens if we've been called by
	//	(apply).

	bNoEval = pArgs->IsQuoted();

	//	Set up the symbol table

	pLocalSymbols = pCC->CreateSymbolTable();
	if (pLocalSymbols->IsError())
		return pLocalSymbols;

	//	Loop over each item and associate it

	for (i = 0; i < m_pArgList->GetCount(); i++)
		{
		pVar = m_pArgList->GetElement(i);
		pArg = pArgs->GetElement(i);

		//	If the name of this variable is %args, then the rest of the arguments
		//	should go into a list

		if (strCompareAbsolute(pVar->GetStringValue(), CONSTLIT("%args")) == 0)
			{
			ICCItem *pVarArgs;

			//	If there are arguments left, add them to a list

			if (pArg)
				{
				int j;
				ICCItem *pError;
				CCLinkedList *pList;

				//	Create a list

				pVarArgs = pCC->CreateLinkedList();
				if (pVarArgs->IsError())
					{
					pLocalSymbols->Discard(pCC);
					return pVarArgs;
					}
				pList = (CCLinkedList *)pVarArgs;

				//	Add each argument to the list

				for (j = i; j < pArgs->GetCount(); j++)
					{
					pArg = pArgs->GetElement(j);

					if (bNoEval)
						pResult = pArg->Reference();
					else
						pResult = pCC->Eval(pCtx, pArg);

					pList->Append(pCC, pResult, &pError);
					pResult->Discard(pCC);
					if (pError->IsError())
						{
						pVarArgs->Discard(pCC);
						pLocalSymbols->Discard(pCC);
						return pError;
						}

					pError->Discard(pCC);
					}
				}
			else
				pVarArgs = pCC->CreateNil();

			//	Add to the local symbol table

			pItem = pLocalSymbols->AddEntry(pCC, pVar, pVarArgs);
			pVarArgs->Discard(pCC);
			}

		//	Bind the variable to the argument

		else if (pArg == NULL)
			pItem = pLocalSymbols->AddEntry(pCC, pVar, pCC->CreateNil());
		else
			{
			ICCItem *pResult;

			//	Evaluate the arg and add to the table

			if (bNoEval)
				pResult = pArg->Reference();
			else
				pResult = pCC->Eval(pCtx, pArg);

			pItem = pLocalSymbols->AddEntry(pCC, pVar, pResult);
			pResult->Discard(pCC);
			}

		//	Check for error

		if (pItem->IsError())
			{
			pLocalSymbols->Discard(pCC);
			return pItem;
			}

		pItem->Discard(pCC);
		}

	//	Setup the context

	pLocalSymbols->SetParent(pCtx->pLexicalSymbols);
	pOldSymbols = pCtx->pLocalSymbols;
	pCtx->pLocalSymbols = pLocalSymbols;

	//	Evalute the code

	pResult = pCC->Eval(pCtx, m_pCode);

	//	Clean up

	pCtx->pLocalSymbols = pOldSymbols;
	pLocalSymbols->Discard(pCC);

	return pResult;
	}
ALERROR CDockScreenCustomList::OnInitList (SInitCtx &Ctx, CString *retsError)

//	OnInitList
//
//	Initialize list

	{
	//	Get the list element

	CXMLElement *pListData = Ctx.pDesc->GetContentElementByTag(LIST_TAG);
	if (pListData == NULL)
		return ERR_FAIL;

	//	See if we define a custom row height

	CString sRowHeight;
	if (pListData->FindAttribute(ROW_HEIGHT_ATTRIB, &sRowHeight))
		{
		CString sResult;
		if (!EvalString(sRowHeight, false, eventNone, &sResult))
			{
			*retsError = sResult;
			return ERR_FAIL;
			}

		int cyRow = strToInt(sResult, -1);
		if (cyRow > 0)
			m_pItemListControl->SetRowHeight(cyRow);
		}

	//	Get the list to show

	CCodeChain &CC = g_pUniverse->GetCC();
	ICCItem *pExp = CC.Link(pListData->GetContentText(0), 0, NULL);

	//	Evaluate the function

	CCodeChainCtx CCCtx;
	CCCtx.SetScreen(m_pDockScreen);
	CCCtx.SaveAndDefineSourceVar(m_pLocation);
	CCCtx.SaveAndDefineDataVar(m_pData);

	ICCItem *pResult = CCCtx.Run(pExp);	//	LATER:Event
	CCCtx.Discard(pExp);

	if (pResult->IsError())
		{
		*retsError = pResult->GetStringValue();
		return ERR_FAIL;
		}

	//	Set this expression as the list

	m_pItemListControl->SetList(CC, pResult);
	CCCtx.Discard(pResult);

	//	Position the cursor on the next relevant item

	SelectNextItem();

	//	Give the screen a chance to start at a different item (other
	//	than the first)

	CString sInitialItemFunc = pListData->GetAttribute(INITIAL_ITEM_ATTRIB);
	if (!sInitialItemFunc.IsBlank())
		{
		bool bMore = IsCurrentItemValid();
		while (bMore)
			{
			bool bResult;
			if (!EvalBool(sInitialItemFunc, &bResult, retsError))
				return ERR_FAIL;

			if (bResult)
				break;

			bMore = SelectNextItem();
			}
		}

	return NOERROR;
	}