bool CAI_BehaviorBase::IsCurSchedule( int schedule, bool fIdeal )
{
	if ( AI_IdIsLocal( schedule ) )
		schedule = GetClassScheduleIdSpace()->ScheduleLocalToGlobal(schedule);

	return GetOuter()->IsCurSchedule( schedule, fIdeal );
}
bool CAI_LocalIdSpace::SetLocalBase( int newBase )
{
	AssertMsg( AI_IdIsLocal( newBase ), ("Global symbol ID passed to CAI_LocalIdSpace::SetLocalBase()") );

	if (m_localBase == MAX_STRING_INDEX)
	{
		// UNDONE: Make sure this is the largest Index in the list so far??
		m_localBase = newBase;
		if ( !m_pParentIDSpace || !m_pParentIDSpace->IsLocalBaseSet() || m_localBase > m_pParentIDSpace->m_localBase )// @Note (toml 08-20-02): this doesn't actually catch namespace collisions, only woefully bad situations where a derived class' offset is less than the base
			return true;
	}
	return false;
}
CAI_Schedule *CAI_BehaviorBase::GetSchedule(int schedule)
{
	if (!GetClassScheduleIdSpace()->IsGlobalBaseSet())
	{
		Warning("ERROR: %s missing schedule!\n", GetSchedulingErrorName());
		return g_AI_SchedulesManager.GetScheduleFromID(SCHED_IDLE_STAND);
	}
	if ( AI_IdIsLocal( schedule ) )
	{
		schedule = GetClassScheduleIdSpace()->ScheduleLocalToGlobal(schedule);
	}

	if ( schedule == -1 )
		return NULL;

	return g_AI_SchedulesManager.GetScheduleFromID( schedule );
}
int CAI_LocalIdSpace::LocalToGlobal( int localID ) const
{
	if ( localID == -1 )
		return -1;

	AssertMsg( AI_IdIsLocal( localID ), ("Global symbol ID passed to CAI_LocalIdSpace::LocalToGlobal()") );

	const CAI_LocalIdSpace *pCurrentMap = this;
	
	do 
	{
		if ( pCurrentMap->IsLocalBaseSet() && localID >= pCurrentMap->GetLocalBase() && localID <= pCurrentMap->GetLocalTop() )
			return ( localID + pCurrentMap->GetGlobalBase() - pCurrentMap->GetLocalBase() );
		pCurrentMap = pCurrentMap->m_pParentIDSpace;
	} while ( pCurrentMap != NULL );
	
	// AssertMsg( 0, ("Invalid ID passed to CAI_LocalIdSpace::LocalToGlobal()") );
	return -1;
}
bool CAI_LocalIdSpace::AddSymbol( const char *pszSymbol, int localId, const char *pszDebugSymbolType, const char *pszDebugOwner )
{
	AssertMsg( AI_IdIsLocal( localId ), ("Global symbol ID passed to CAI_LocalIdSpace::AddSymbol()") );
	
	if ( !m_pGlobalNamespace )
	{
		DevMsg( "ERROR: Adding symbol to uninitialized table %s\n", pszDebugOwner );
		return false;
	}
	
	if ( !IsLocalBaseSet() && !SetLocalBase( localId ) )
	{
		DevMsg( "ERROR: Bad %s LOCALID for %s\n", pszDebugSymbolType, pszDebugOwner );
		return false;
	}
	else if (localId < GetLocalBase() )
	{
		DevMsg("ERROR: %s First added %s must be first LOCALID!\n", pszDebugSymbolType, pszDebugOwner);
		return false;
	}

	AssertMsg3( LocalToGlobal( localId ) == -1 || !m_pGlobalNamespace->IdToSymbol( LocalToGlobal( localId ) ) , "Duplicate symbol ID passed to CAI_LocalIdSpace::AddSymbol(): %s (%d), had %s", pszSymbol, localId, m_pGlobalNamespace->IdToSymbol( LocalToGlobal( localId ) ) );
	AssertMsg( m_pGlobalNamespace->SymbolToId( pszSymbol ) == -1, "Duplicate symbol passed to CAI_LocalIdSpace::AddSymbol()" );

	if ( m_localTop != -1 )
	{
		if ( localId > m_localTop )
		{
			m_localTop = localId;
			m_globalTop = ( m_localTop - m_localBase ) + m_globalBase;
		}
	}
	else
	{
		m_localTop = m_localBase;
		m_globalTop = m_globalBase;
	}
	
	m_pGlobalNamespace->AddSymbol( pszSymbol, LocalToGlobal( localId ) );
	return true;
}
bool CAI_SchedulesManager::LoadSchedulesFromBuffer( const char *prefix, char *pfile, CAI_ClassScheduleIdSpace *pIdSpace )
{
	char token[1024];
	char save_token[1024];
	pfile = engine->COM_ParseFile(pfile, token);

	while (!stricmp("Schedule",token))
	{
		pfile = engine->COM_ParseFile(pfile, token);

		// -----------------------------
		// Check for duplicate schedule
		// -----------------------------
		if (GetScheduleByName(token))
		{
			Msg("ERROR: file contains a schedule (%s) that has already been defined!\n",token);
			Msg("       Aborting schedule load.\n");
			Assert(0);
			return false;
		}

		int scheduleID = CAI_BaseNPC::GetScheduleID(token);
		if (scheduleID == -1)
		{
			Msg( "ERROR: LoadSchd (%s): Unknown schedule type (%s)\n", prefix, token);
			// FIXME: .sch's not being in code/perforce makes it hard to share branches between developers
			// for now, just stop processing this entities schedules if one is found that isn't in the schedule registry
			break;
			// return false;
		}

		CAI_Schedule *new_schedule = CreateSchedule(token,scheduleID);

		pfile = engine->COM_ParseFile(pfile, token);
		if (stricmp(token,"Tasks"))
		{
			Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting 'Tasks' keyword.\n",prefix,new_schedule->GetName());
			Assert(0);
			return false;
		}

		// ==========================
		// Now read in the tasks
		// ==========================
		// Store in temp array until number of tasks is known
		Task_t tempTask[50];
		int	   taskNum = 0;

		pfile = engine->COM_ParseFile(pfile, token);
		while ((token[0]!=NULL) && (stricmp("Interrupts",token)))
		{
			// Convert generic ID to sub-class specific enum
			int taskID = CAI_BaseNPC::GetTaskID(token);
			tempTask[taskNum].iTask = (pIdSpace) ? pIdSpace->TaskGlobalToLocal(taskID) : AI_RemapFromGlobal( taskID );
			
			// If not a valid condition, send a warning message
			if (tempTask[taskNum].iTask == -1)
			{
				Msg( "ERROR: LoadSchd (%s): (%s) Unknown task %s!\n", prefix,new_schedule->GetName(), token);
				Assert(0);
				return false;
			}

			Assert( AI_IdIsLocal( tempTask[taskNum].iTask ) );

			// Read in the task argument
			pfile = engine->COM_ParseFile(pfile, token);

			if (!stricmp("Activity",token))
			{
				// Skip the ";", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'ACTIVITY.\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the activity and make sure its valid
				pfile = engine->COM_ParseFile(pfile, token);
				tempTask[taskNum].flTaskData = CAI_BaseNPC::GetActivityID(token);
				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Unknown activity %s!\n", prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if (!stricmp("Task",token))
			{
				// Skip the ";", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'ACTIVITY.\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the activity and make sure its valid
				pfile = engine->COM_ParseFile(pfile, token);

				// Convert generic ID to sub-class specific enum
				int taskID = CAI_BaseNPC::GetTaskID(token);
				tempTask[taskNum].flTaskData = (pIdSpace) ? pIdSpace->TaskGlobalToLocal(taskID) : AI_RemapFromGlobal( taskID );

				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Unknown task %s!\n", prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if (!stricmp("Schedule",token))
			{
				// Skip the ";", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'ACTIVITY.\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the schedule and make sure its valid
				pfile = engine->COM_ParseFile(pfile, token);

				// Convert generic ID to sub-class specific enum
				int schedID = CAI_BaseNPC::GetScheduleID(token);
				tempTask[taskNum].flTaskData = (pIdSpace) ? pIdSpace->ScheduleGlobalToLocal(schedID) : AI_RemapFromGlobal( schedID );

				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd %d (%s): (%s) Unknown shedule %s!\n", __LINE__, prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if (!stricmp("State",token))
			{
				// Skip the ";", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'STATE.\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the activity and make sure its valid
				pfile = engine->COM_ParseFile(pfile, token);
				tempTask[taskNum].flTaskData = CAI_SchedulesManager::GetStateID(token);
				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd %d (%s): (%s) Unknown shedule %s!\n", __LINE__, prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if (!stricmp("Memory",token))
			{

				// Skip the ";", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'STATE.\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the activity and make sure its valid
				pfile = engine->COM_ParseFile(pfile, token);
				tempTask[taskNum].flTaskData = CAI_SchedulesManager::GetMemoryID(token);
				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd %d (%s): (%s) Unknown shedule %s!\n", __LINE__, prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if (!stricmp("Path",token))
			{
				// Skip the ";", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'PATH.\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the activity and make sure its valid
				pfile = engine->COM_ParseFile(pfile, token);
				tempTask[taskNum].flTaskData = CAI_SchedulesManager::GetPathID( token );
				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Unknown path type %s!\n", prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if (!stricmp("Goal",token))
			{
				// Skip the ";", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'GOAL.\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the activity and make sure its valid
				pfile = engine->COM_ParseFile(pfile, token);
				tempTask[taskNum].flTaskData = CAI_SchedulesManager::GetGoalID( token );
				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Unknown goal type  %s!\n", prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if ( !stricmp( "HintFlags",token ) )
			{
				// Skip the ":", but make sure it's present
				pfile = engine->COM_ParseFile(pfile, token);
				if (stricmp(token,":"))
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Malformed AI Schedule.  Expecting ':' after type 'HINTFLAG'\n",prefix,new_schedule->GetName());
					Assert(0);
					return false;
				}

				// Load the flags and make sure they are valid
				pfile = engine->COM_ParseFile( pfile, token );
				tempTask[taskNum].flTaskData = CAI_Hint::GetFlags( token );
				if (tempTask[taskNum].flTaskData == -1)
				{
					Msg( "ERROR: LoadSchd (%s): (%s) Unknown hint flag type  %s!\n", prefix,new_schedule->GetName(), token);
					Assert(0);
					return false;
				}
			}
			else if (!stricmp("Interrupts",token) || !strnicmp("TASK_",token,5) )
			{
				// a parse error.  Interrupts is the next section, TASK_ is probably the next task, missing task argument?
				Warning( "ERROR: LoadSchd (%s): (%s) Bad syntax at task #%d (wasn't expecting %s)\n", prefix, new_schedule->GetName(), taskNum, token);
				Assert(0);
				return false;
			}
			else
			{
				tempTask[taskNum].flTaskData = atof(token);
			}
			taskNum++;

			// Read the next token
			Q_strncpy(save_token,token,sizeof(save_token));
			pfile = engine->COM_ParseFile(pfile, token);

			// Check for malformed task argument type
			if (!stricmp(token,":"))
			{
				Msg( "ERROR: LoadSchd (%s): Schedule (%s),\n        Task (%s), has a malformed AI Task Argument = (%s)\n",
						prefix,new_schedule->GetName(),taskID,save_token);
				Assert(0);
				return false;
			}
		}

		// Now copy the tasks into the new schedule
		new_schedule->m_iNumTasks = taskNum;
		new_schedule->m_pTaskList = new Task_t[taskNum];
		for (int i=0;i<taskNum;i++)
		{
			new_schedule->m_pTaskList[i].iTask		= tempTask[i].iTask;
			new_schedule->m_pTaskList[i].flTaskData = tempTask[i].flTaskData;

			Assert( AI_IdIsLocal( new_schedule->m_pTaskList[i].iTask ) );
		}

		// ==========================
		// Now read in the interrupts
		// ==========================
		pfile = engine->COM_ParseFile(pfile, token);
		while ((token[0]!=NULL) && (stricmp("Schedule",token)))
		{
			// Convert generic ID to sub-class specific enum
			int condID = CAI_BaseNPC::GetConditionID(token);

			// If not a valid condition, send a warning message
			if (condID == -1)
			{
				Msg( "ERROR: LoadSchd (%s): Schedule (%s), Unknown condition %s!\n", prefix,new_schedule->GetName(),token);
				Assert(0);
			}

			// Otherwise, add to this schedules list of conditions
			else
			{
				int interrupt = AI_RemapFromGlobal(condID);
				Assert( AI_IdIsGlobal( condID ) && interrupt >= 0 && interrupt < MAX_CONDITIONS );
				new_schedule->m_InterruptMask.SetBit(interrupt);
			}

			// Read the next token
			pfile = engine->COM_ParseFile(pfile, token);
		}
	}
	return true;
}