Goals and the Agenda explained a bit (for DrJustice) // a line from the CTNode header file virtual Symbol RealizeGoal(CGoal* goal) { return _undefined ; } // The CGoal class does not over-ride or call this function // It’s use will be explaind later ///////////////////////////////////////////////////////////////////////////////////////// class CGoal : public CTNode // the children of CGoal are pointers to CSubGoalRecord objects { DECLARE_SERIAL( CGoal ) public : // empty constructor is necessary for MFCs crumby serialization method CGoal(){}; CGoal(CTNode* dirObj, Symbol goalType, CValQualf* valQ) ; ~CGoal() ; void Serialize( CArchive& archive ); CTNode* m_directObject ; Symbol m_state ; CValQualf* m_valQ ; CString m_goalName ; }; ///////////////////////////////////////////////////////////////////////////////////////// // from the CAgenda.cpp file //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CAgenda::ExecuteAgendaTop() { Symbol result = _undefined ; CGoal* topGoal = NULL ; POSITION pos = NULL ; CString str ; if(IsEmpty()) { return false ; } topGoal = ReadGoal() ; result = topGoal->m_directObject->RealizeGoal(topGoal) ; switch(result) { case _attained : pos = Find(topGoal) ; // just in case it was moved during // realization if(!pos) { return false ; } RemoveAt(pos) ; delete topGoal ; break ; case _waitingOnSubGoals : break ; case _operationCanceled : SingleStep = true ; break ; default : str = "Unknown result from goal: " ; str += topGoal->m_goalName ; AfxMessageBox(str,MB_OK, false) ; ExecuteAgenda = false ; break ; } DisplayAgenda() ; if(SingleStep) { ExecuteAgenda = false ; } return true ; } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Nearly every object in the program inherits from CTNode, which is a list node. Any such object can over-ride CTNode’s virtual RealizeGoal(…) function. The composition object and movement objects so inherit. The create composition goal actually constructs the movement objects and places them in the composition’s list (a composition is a list of one or more movements). The create composition goal then creates its sub goals thus: //here mvmt is a pointer to a movement object g = new CGoal(mvmt, _createSchematic, NULL) ; g->m_goalName = " Create Schematic of " ; g->m_goalName += *(mvmt->GetName()) ; m_agenda->PushGoal(g) ; So the goal contains the movement object as a data member and that object has an over-ride of RealizeGoal(). ExecuteAgendaTop() is called as a background process from the OnIdle loop whenever the global variable ExecuteAgenda is true. Now say that the CGoal g above is on the top of the Agenda. When we get to this line in ExecuteAgendaTop() result = topGoal->m_directObject->RealizeGoal(topGoal) ; m_directObject points to the movement object and its RealizeGoal(…) function is called. In general RealizeGoal(…) functions looks like this: //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Symbol CMvmt::RealizeGoal(CGoal* goal) { // GetType() is inherited from CTNode switch(goal->GetType()) { case _createSchematic : return RealizeCreateSchematicGoal(goal) ; default : return _undefined ; } } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This allows an object to respond to multiple goal types. I hope that makes things a bit clearer.