/************************************************************************************************
* Name: FuncRay2.c                                                                              *
* Use : Functions for AI of Rayman II                                                           *
* Author: Christophe Giraud                                                                     *
*                                  (c) UBI Simulations Annecy                                   *
************************************************************************************************/
 
/*#include "safe.h" //BART*/
 
/*ANNECY CG {*/
 
#define	ONLY4DEBUG
#include "PO.h"
#include "DataRay2.h"
 
#ifdef __cplusplus
extern "C"{
#endif
 
#define TEXT_MAX_PARAMETERS 10
extern int		TEXT_gai_IntParameters[TEXT_MAX_PARAMETERS];
extern float	TEXT_gaf_FloatParameters[TEXT_MAX_PARAMETERS];
extern char		TEXT_gc_ViewportFixed;
 
#ifdef __cplusplus
}
#endif
 
 
/**********************************************************************************************************
* Function: TEXT_Affiche                                                                                  *
*                                                                                                         *
* Use	  : Event := TEXT_Affiche( DSG_VAR_PersoGenerated, Always, vecteur(X,Y,Z), String, DSG_VAR_DELAY) *
*                                                                                                         *
* Author  : Christophe Giraud                                                                             *
* Date of last modification: 15/10/98                                                                     *
*																						                  *
**********************************************************************************************************/
tdstNodeInterpret *fn_p_stCode4TextAffiche(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam * p_stValue )
{
	tdstGetSetParam stParam ;
	long ulEvent = 0 ;
	tdstEngineObject              *p_stEngineObject        = NULL ;
	HIE_tdxHandleToSuperObject    p_SuperObjPersoGenerated = NULL ,
	p_SuperObjPersoTreated   = NULL;
	MS_tdxHandleToDynam           h_Dynam                  = NULL ;
	POS_tdstCompletePosition      *hPersoGlobalMatrix      = NULL ;

	tdstTfmtStatus                stStatus ;

	MTH3D_tdstVector              stVertex , stTextPosition ;
	MTH_tdxReal                   xPosX = MTH_C_ZERO , xPosY = MTH_C_ZERO ,	xPosZ = MTH_C_ZERO ;

	long  lPosX = 0 , lPosY = 0 , lPosZ = 0 , lStart = 0 , lEnd = -1 ;

	MTH_tdxReal	xxPosX , xxPosY , xxPosZ ;

	unsigned long ulTimer = 0 , ulDeltaTimer = 0 ;
	unsigned long ulDelay ;

	char          *p_szString     = NULL , szCopy[600] ;

	unsigned char     ucPersoId , ucNumberOfCurrentTextAffiche = 0 , ucDelayId ;

	short             wPositionInString = 0 ;

	ACP_tdxBool bFirstTime  = TRUE ;
 
 
	/* Get Perso parameter and his Id for acces to its DsgVar*/
#if defined(__DEBUG_AI__)
	fn_vSetDontCheckNULLFlag(1);
#endif /* __DEBUG_AI__ */

	ucPersoId = (unsigned char) M_ucVarIdInterpret(p_stTree);
	M_EvalNextParameter(&stParam);
	p_SuperObjPersoTreated = M_GetSetParam_p_stEngineObjValue(&stParam) ? M_GetSetParam_p_stSupObjValue(&stParam) : NULL;

#if defined(__DEBUG_AI__)
	fn_vSetDontCheckNULLFlag(-1);
#endif /*__DEBUG_AI__ */


	/* Get always model parameter*/
	M_EvalNextParameter(&stParam);
	#if defined(__DEBUG_AI__)
	M_VerifyTypeOfParamAction(&stParam, E_vt_Perso);
	#endif
	p_stEngineObject = M_GetSetParam_p_stEngineObjValue(&stParam);

	/* Get Coordinates parameters*/
	M_EvalNextParameter(&stParam);
	stTextPosition = M_GetSetParam_stVectorValue(&stParam);
	MTH3D_M_vGetVectorElements( &lPosX, &lPosY, &lPosZ, &stTextPosition);
	MTH3D_M_vGetVectorElements( &xxPosX, &xxPosY, &xxPosZ, &stTextPosition);

	/* Get String parameter or string from Game.txt*/
	M_EvalNextParameter(&stParam);
	p_szString = fn_szGetStringFromTextOrStringParam(&stParam);
	if (p_szString == NULL)
		p_szString = "No Text";
	#ifdef U64
  if (((unsigned long)p_szString == 0xcccccccc)||(((unsigned long)p_szString & 0x80000000) != 0x80000000))
		p_szString = "No Text";
	#endif

	/* process specials string /-?*/
	if ( *p_szString == '/' && *(p_szString+1) == '-' )
	{
		char *szCur ;
		long i ;

		i = 0 ;
		szCur = p_szString + 2 ;
		switch ( *szCur )
		{
		case 'W' :
		case 'w' :
			TFMT_vUpdateSpacingTable(szCur+1);
			break ;

		case 'Z' :
		case 'z' :
			TFMT_vUpdateScaleTable(szCur+1);
			break ;
		}
		/*remove un-interpreted parameters !!*/
		M_Full_GetSetParam_Integer(p_stValue, ulEvent );
		return fn_p_stSkipThisArgument(p_stTree) ;
	}

	SAF_M_AssertWithMsg(strlen(p_szString) < sizeof(szCopy),  "Erreur Interne: la fonction ne peut traiter une chaîne aussi longue");
	strcpy(szCopy, p_szString);
 
	/* Take care of /%Xnnn */
	{
		char	*psz_Temp, *psz_Copy;
		char	asz_Num[20];
		int		i_Num;
 
		psz_Copy = szCopy;
		psz_Temp = p_szString;
		while(*psz_Temp)
		{
			if(psz_Temp[0] == '/')
			{
				if(psz_Temp[1] == '%')
				{
					switch(psz_Temp[2])
					{
					/* Int */
					case 'i':
					case 'I':
						i_Num = atoi(psz_Temp + 3);
						itoa(TEXT_gai_IntParameters[i_Num], asz_Num, 10);
						strcpy(psz_Copy, asz_Num);
						psz_Copy += strlen(asz_Num);
						while(*psz_Temp != ':')
							psz_Temp++;
						psz_Temp++;
						continue;
						break;
 
					/* Float */
					case 'f':
					case 'F':
						i_Num = atoi(psz_Temp + 3);
						sprintf(asz_Num, "%.3f", TEXT_gaf_FloatParameters[i_Num]);
						strcpy(psz_Copy, asz_Num);
						psz_Copy += strlen(asz_Num);
						while(*psz_Temp != ':')
							psz_Temp++;
						psz_Temp++;
						continue;
						break;
					}
				}
			}
			*psz_Copy++ = *psz_Temp++;
		}
		*psz_Copy = 0;
		p_szString = szCopy ;
	}
 
	/* Get delay parameter*/
	ucDelayId = (unsigned char) M_ucVarIdInterpret(p_stTree);
	M_EvalNextParameter(&stParam);
	ulDelay = M_GetSetParam_ulValue(&stParam);
 
	if ( p_SuperObjPersoTreated != NULL )
	{
		/* Get the number of the current TEXT_Affiche function*/
		ucNumberOfCurrentTextAffiche = TFMT_ucNumberOfCurrentTextAffiche( p_SuperObjPersoTreated );

		/* Get the position of the current char to display*/
		wPositionInString = g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].wCurrentLetterInString;

		bFirstTime = g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].bFirstInit;
		ulEvent = g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulEvent;

		/* Exit if string is always fully displayed*/
		if ( wPositionInString >= (short)strlen(p_szString) )
		{
			/* Inform the motor of the type and the value of the variable*/
			M_Full_GetSetParam_Integer(p_stValue, ulEvent );
			return(p_stTree);
		}              
	}
 
	/*------ GENERATION DE L'ALWAYS ------{*/
	/********************************************  
	*  Object is create only for the first time *
	********************************************/
	if (p_SuperObjPersoTreated==NULL)
	{
		MTH3D_M_vFillVector( &stVertex, MTH_C_ONE );

		/* Generated the Always*/
		if (p_stEngineObject!= NULL)
		{
			if (fn_ucIsAnAlwaysModel(p_stEngineObject))
			{			  
				POS_tdstCompletePosition stMatrix;
				//HP 080499
				#ifndef U64		
				tdObjectType otObjectModelType = M_ObjectGetModelType(p_stEngineObject);
				#else
				tdObjectType otObjectPersonalType = M_ObjectGetPersonalType(p_stEngineObject);
				#endif

				POS_fn_vSetIdentityMatrix(&stMatrix);
				POS_fn_vSetTranslationVector(&stMatrix, &stVertex); 

				/* Create the always*/
				#ifndef U64
				p_SuperObjPersoGenerated = fn_p_stAllocateAlways(otObjectModelType, gp_stDynamicWorld, p_SuperObjPerso, 0, &stMatrix);
				#else 
				p_SuperObjPersoGenerated = fn_p_stAllocateAlways(otObjectPersonalType, gp_stDynamicWorld, p_SuperObjPerso, 0, &stMatrix);
				#endif 

				if ( p_SuperObjPersoGenerated != NULL )
				{
					register unsigned long ulTmpDelay = ulDelay;

					/* to be sure that the anim player will not be called, clear the current state of the actor. */
					fn_v3dDataSetFlagEndState(M_GetMSHandle(p_SuperObjPersoGenerated,3dData),TRUE);

					/* Set a number for this new TEXT_Affiche function*/
					ucNumberOfCurrentTextAffiche = TFMT_ucSetNumber4CurrentTextAffiche();

					/* Get the Timer*/
					ulTimer = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount;
					g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulTimer = ulTimer;

					/* Store Delay*/
					g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulCurrentDelay = ulDelay;

					/* Store the new TEXT_Affiche always*/
					gp_SuperObjPersoGenerated[ ucNumberOfCurrentTextAffiche ] = p_SuperObjPersoGenerated;

					/* Restore the DsgVar for the Perso*/
					M_Full_GetSetParam_Perso(&stParam, p_SuperObjPersoGenerated);
					ucPersoId = fn_ucSetDsgVar(ucPersoId, 0, AI_M_stGetMindOfSuperObj(p_SuperObjPerso), &stParam);

					/* ANNECY MT - 18/09/98 { next call is now useless*/
					/*fn_vForceActiveAnObject(M_GetEngineObject( p_SuperObjPersoGenerated ) );*/
					/* END ANNECY MT }*/

					/*------ GENERATION DU TEXTE A LA CREATION DE L'ALWAYS ------{                                             */
					if ( !ulDelay )
					{
						wPositionInString = -1;           
						ulEvent = TFMT_wPositionModulesAccordingToText2(&stStatus, p_SuperObjPersoGenerated, p_szString, lStart, lEnd, &bFirstTime, &wPositionInString, &ulDelay);
						wPositionInString = strlen(p_szString);
					}
					else
					{
						ulEvent = TFMT_wPositionModulesAccordingToText2(&stStatus, p_SuperObjPersoGenerated, p_szString, lStart, lEnd, &bFirstTime, &wPositionInString, &ulDelay);
					}
					/*}------ GENERATION DU TEXTE A LA CREATION DE L'ALWAYS ------    */

					if( ulDelay != ulTmpDelay )
					{
						if((int) ulDelay < 0)
							ulDelay = -((int)ulDelay);
						else
							g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulCurrentDelay = ulDelay;     /* It's a new delay*/
					}



					/*------ AFFICHAGE DANS LE SECOND VIEWPORT -----{*/

					/* Initialize all the stuff*/
					TEXT_vComputeLengthOgString(p_szString,&stStatus);

					h_Dynam = M_GetMSHandle(p_SuperObjPersoGenerated,Dynam);

					/* Get the global matrix of the actor's superobject*/
					hPersoGlobalMatrix = HIE_fn_hGetSuperObjectGlobalMatrix(p_SuperObjPersoGenerated);

					if(TEXT_gc_ViewportFixed)
					{
						HIE_fn_SO_vSetSuperimposedFlag(p_SuperObjPersoGenerated);
						xPosY = MTH_M_xDiv( MTH_M_xLongToReal(lPosY), 1000.0 ) ;
						xPosZ = MTH_M_xDiv( MTH_M_xLongToReal(lPosZ), 1000.0 );
						if ( stStatus.cJustificationMode == 'c' )
						{
							xPosX = MTH_M_xDiv( 500.0, 1000.0 );
							GLI_vGet3DVertexFromScreenPos( &g_stEngineStructure.stFixViewportAttr, &stVertex, xPosX, xPosY, xPosZ);
							/*                      stVertex.xX -= MTH_M_xDiv( (stStatus.xScreenWidth - stStatus.xBaseToAddX), MTH_C_2 ); //total string width - space after the last char*/
							stVertex.xX -= MTH_M_xDiv( stStatus.xScreenWidth, MTH_C_2 ); 
						}
						else
						{
							xPosX = MTH_M_xDiv( MTH_M_xLongToReal(lPosX), 1000.0 ) ;    
							GLI_vGet3DVertexFromScreenPos( &g_stEngineStructure.stFixViewportAttr, &stVertex, xPosX, xPosY, xPosZ);
						}
						#ifndef U64
						hPersoGlobalMatrix->ulType = POS_C_ulCompleteMatrixFlag;
						hPersoGlobalMatrix->stTransformMatrix.stCol_2.xZ = hPersoGlobalMatrix->stTransformMatrix.stCol_0.xX = g_stEngineStructure.stFixViewportAttr.dwWidth / 640.0f;
						#endif /* U64 */
					}
					else
					{
						HIE_fn_SO_vClearSuperimposedFlag(p_SuperObjPersoGenerated);
						stVertex.xX = xxPosX;
						stVertex.xY = xxPosY;
						stVertex.xZ = xxPosZ;
					}

					POS_fn_vSetTranslationVector(hPersoGlobalMatrix,&stVertex);
					if ( h_Dynam )
					{
						DNM_tdstDynamics *p_stDynamics = fn_p_stDynamGetDynamics(h_Dynam);
						MEC_vInitTranslation( p_stDynamics, p_SuperObjPersoGenerated, &stVertex );
					}

					HIE_fn_vComputeNewRelativeMatrix(p_SuperObjPersoGenerated);

					/* update global matrix of all child*/
					PLA_fn_vRefreshGlobalMatrixUnderCharacter(p_SuperObjPersoGenerated);

					/*}------ AFFICHAGE DANS LE SECOND VIEWPORT ------ */
				} /*** Mettre une sortie de secours si le perso n'est pas créer !!!!! ***/
			}
		}          
	}
	else
	{
		/*------ GENERATION DU TEXTE ------{*/
		/*if (!bFirstTime)*/
		{                
			/* Compute delay*/
			ulTimer      = g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulTimer;
			ulDeltaTimer = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount-ulTimer;

			p_SuperObjPersoGenerated = p_SuperObjPersoTreated;
			bFirstTime               = g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].bFirstInit;   

			if ( ulDeltaTimer>=ulDelay)
			{
				unsigned long ulTmpDelay = g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulCurrentDelay;
				ulDelay = ulTmpDelay;

				if (!ulDelay) /* No delay*/
				{
					while( (wPositionInString<(short)strlen(p_szString)) && (!ulDelay) )
					{
						ulEvent = TFMT_wPositionModulesAccordingToText2(&stStatus, p_SuperObjPersoGenerated, p_szString, lStart, lEnd, &bFirstTime, &wPositionInString, &ulDelay);
					}
				}
				else
				{
					ulEvent = TFMT_wPositionModulesAccordingToText2(&stStatus, p_SuperObjPersoGenerated, p_szString, lStart, lEnd, &bFirstTime, &wPositionInString, &ulDelay);                   
				}
				g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulTimer = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount;

				/* Management of the next delay*/
				if( ulDelay != ulTmpDelay )
				{
					if((int) ulDelay < 0)
						ulDelay = -((int)ulDelay);
					else
						g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulCurrentDelay = ulDelay;     /* It's a new delay*/
				}
				g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulTimer = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount;
			}
			else
			{
				if (ulEvent)
				{
					register unsigned long  ulTmpDelay = g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulCurrentDelay;
					unsigned long  ulCptDelay = ulTmpDelay;

					ulEvent = TFMT_wPositionModulesAccordingToText2(&stStatus, p_SuperObjPersoGenerated, p_szString, lStart, lEnd, &bFirstTime, &wPositionInString, &ulCptDelay);
					if( ulCptDelay != ulTmpDelay )
					{
						if((int) ulCptDelay < 0)
							ulCptDelay = -((int)ulCptDelay);
						else
							g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulCurrentDelay = ulCptDelay;     /* It's a new delay*/
						ulDelay = ulCptDelay;
					}
				}
			}
		} /*}------ GENERATION DU TEXTE ------ */
	} /*}------ GENERATION DE L'ALWAYS ------ */

	/* Restore all datas of the current TEXT_Affiche function*/
	g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].bFirstInit             = bFirstTime;
	g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].ulEvent                = ulEvent;
	g_stInfoTextAffiche[ ucNumberOfCurrentTextAffiche ].wCurrentLetterInString = wPositionInString;

	/* Restore the DsgVar for the Delay*/
	M_Full_GetSetParam_Integer( &stParam, ulDelay );
	ucDelayId = fn_ucSetDsgVar(ucDelayId, 0, AI_M_stGetMindOfSuperObj(p_SuperObjPerso), &stParam);

	/* Inform the motor of the type and the value of the variable*/
	M_Full_GetSetParam_Integer(p_stValue, ulEvent);
	return(p_stTree);
}
 
 
/******************************************************************************************
* Function: Code4PointsDair                                                               *
* Use	  : LitPointsDair( )                                                              *
*         : Return the Air point of Rayman                                                *
* Use	  : LitPointsDairMax( )                                                           *
*         : Return the Air point Max of Rayman                                            *
* Use	  : AjouteEtLitPointsDair( Entier Number_Of_Air_Points )                          *
*         : Add Number_Of_Air_Points and return the Air point of Rayman                   *
* Use	  : AjouteEtLitPointsDairMax( Entier Number_Of_Air_Points )                       *
*         : Add Number_Of_Air_Points to Air points max and return the Air point Max       *
* Use	  : EnleveEtLitPointsDair( Entier Number_Of_Air_Points )                          *
*         : Sub Number_Of_Air_Points and return the Air point of Rayman                   *
* Use	  : EnleveEtLitPointsDairMax( Entier Number_Of_Air_Points )                       *
*         : Sub Number_Of_Air_Points to Air points max and return the Air point Max       *
* Author  : Christophe Giraud                                                             *
* Date of last modification: 24/02/98                                                     *
******************************************************************************************/
 
tdstNodeInterpret *fn_p_stCode4PointsDair(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	MTH_tdxReal		xValue = MTH_C_ZERO;				/* Variable to stock the return value*/
	MTH_tdxReal     xNumberOfAirPoints;			/* variable to store the eventual parameter*/
	MTH_tdxReal     xSign = MTH_C_ONE;
	tdstGetSetParam stParam;					/* Structure d'échange*/
	enum tdeFuncId_ eFuncId = M_eFuncIdInterpret(p_stTree-1);
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
	switch(eFuncId)
	{
		case eFunc_LitPointsDair:
			/* Get Air points of Ray*/
			xValue = stExtendDatas4Ray.xAirPoints4Ray;
			break;
 
		case eFunc_LitPointsDairMax:
			/* Get Air points Max of Ray*/
			xValue = stExtendDatas4Ray.xAirPointsMax4Ray;
			break;
 
		case eFunc_EnleveEtLitPointsDair:
			xSign = MTH_C_MinusONE;
			/* No break : enleve = ajoute du négatif*/
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
		case eFunc_AjouteEtLitPointsDair:
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
			{
				/* Get number of Air points to add*/
				M_EvalNextParameter( &stParam );
				SAF_M_AssertWithMsg(MTH_M_bGreaterEqual(M_ReturnParam_xValue( &stParam ), MTH_C_ZERO), "On ne peut manipuler que des points d'air positifs!");
				xNumberOfAirPoints = MTH_M_xMul(xSign, M_ReturnParam_xValue( &stParam ));
 
				/* Add "xNumberOfAirPoints"*/
				xValue = MTH_M_xAdd(stExtendDatas4Ray.xAirPoints4Ray, xNumberOfAirPoints);
 
				/* Test if Number of Air points > Number of Air points max*/
				if ( MTH_M_bGreater(xValue, stExtendDatas4Ray.xAirPointsMax4Ray) )
					xValue = stExtendDatas4Ray.xAirPointsMax4Ray;
				else if ( MTH_M_bLessZero(xValue) )
					xValue = MTH_C_ZERO;
 
				/* Return number of Air points*/
				stExtendDatas4Ray.xAirPoints4Ray = xValue;
			}
			break;
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
	    case eFunc_EnleveEtLitPointsDairMax:
			xSign = MTH_C_MinusONE;
			/* No break : enleve = ajoute du neg*/
 
		case eFunc_AjouteEtLitPointsDairMax:
			{
				/* Get number of Air points to add*/
				M_EvalNextParameter( &stParam );
				SAF_M_AssertWithMsg(MTH_M_bGreaterEqual(M_ReturnParam_xValue( &stParam ), MTH_C_ZERO), "On ne peut manipuler que des points d'air positifs!");
				xNumberOfAirPoints = MTH_M_xMul(xSign, M_ReturnParam_xValue( &stParam ));
 
				/* Add "xNumberOfAirPoints"*/
				xValue = MTH_M_xAdd(stExtendDatas4Ray.xAirPointsMax4Ray, xNumberOfAirPoints);
 
				/* Test if Number of Air points > MAXAirPOINTS*/
				if ( MTH_M_bLessZero(xValue) )
					xValue = MTH_C_ZERO;
				if ( MTH_M_bLess(xValue, stExtendDatas4Ray.xAirPoints4Ray) )
					stExtendDatas4Ray.xAirPoints4Ray = xValue;
 
 
				/* Return number of Air points Max*/
				stExtendDatas4Ray.xAirPointsMax4Ray = xValue;
			}
			break;
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
		default:
#if defined(__DEBUG_AI__) || (defined(U64) && defined(D_CHECK_AI_FPCO))
			  M_AIFatalError(E_uwAIFatalNotValidFunction);
#endif
			  return(p_stTree);
		  break;
  }
 
  M_Full_GetSetParam_Float(p_stValue, xValue );
  return(p_stTree);
}
 
 
/******************************************************************************************
* Function: Code4PointsDeMagie                                                            *
* Use	  : LitPointsDeMagie( )                                                           *
*         : Return the magic point of Rayman                                              *
* Use	  : LitPointsDeMagieMax( )                                                        *
*         : Return the magic point Max of Rayman                                          *
* Use	  : AjouteEtLitPointsDeMagie( Entier Number_Of_Magic_Points )                     *
*         : Add Number_Of_Magic_Points and return the magic point of Rayman               *
* Use	  : AjouteEtLitPointsDeMagieMax( Entier Number_Of_Magic_Points )                  *
*         : Add Number_Of_Magic_Points to Magic points max and return the magic point Max *
* Use	  : EnleveEtLitPointsDeMagie( Entier Number_Of_Magic_Points )                     *
*         : Sub Number_Of_Magic_Points and return the magic point of Rayman               *
* Use	  : EnleveEtLitPointsDeMagieMax( Entier Number_Of_Magic_Points )                  *
*         : Sub Number_Of_Magic_Points to Magic points max and return the magic point Max *
* Author  : Christophe Giraud                                                             *
* Date of last modification: 30/10/97                                                     *
******************************************************************************************/
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
tdstNodeInterpret *fn_p_stCode4PointsDeMagie(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
  long lValue=0,							/* Variable to stock the return value*/
	   lNumberOfMagicPoints;
  tdstGetSetParam stParam		;			/* Structure d'échange*/
  enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
 
 
  switch(eFuncId)
  {
    case eFunc_LitPointsDeMagie:
	  /* Get magic points of Ray*/
	  lValue = stExtendDatas4Ray.iMagicPoints4Ray;
	  break;
 
    case eFunc_LitPointsDeMagieMax:
	  /* Get magic points Max of Ray*/
	  lValue = stExtendDatas4Ray.iMagicPointsMax4Ray;
	  break;
 
    case eFunc_AjouteEtLitPointsDeMagie:
		{
		  /* Evaluation of next parameter*/
		  M_EvalNextParameter( &stParam );
 
		  /* Get number of magic points to add*/
		  lNumberOfMagicPoints = M_ReturnParam_lValue( &stParam );
		  SAF_M_AssertWithMsg(lNumberOfMagicPoints >= 0, "On ne peut manipuler que des points de magie positifs!");
 
 
		  /* Add "lNumberOfMagicPoints"*/
		  stExtendDatas4Ray.iMagicPoints4Ray += lNumberOfMagicPoints;
 
		  /* Test if Number of magic points > Number of magic points max*/
		  if ( stExtendDatas4Ray.iMagicPoints4Ray > stExtendDatas4Ray.iMagicPointsMax4Ray )
			  stExtendDatas4Ray.iMagicPoints4Ray = stExtendDatas4Ray.iMagicPointsMax4Ray;
 
		  /* Return number of magic points*/
		  lValue = stExtendDatas4Ray.iMagicPoints4Ray;
		}
		break;
 
    case eFunc_AjouteEtLitPointsDeMagieMax:
		{
		  /* Evaluation of next parameter*/
		  M_EvalNextParameter( &stParam );
 
		  /* Get number of magic points to add*/
		  lNumberOfMagicPoints = M_ReturnParam_lValue( &stParam );
		  SAF_M_AssertWithMsg(lNumberOfMagicPoints >= 0, "On ne peut manipuler que des points de magie positifs!");
 
		  /* Add "lNumberOfMagicPoints"*/
		  stExtendDatas4Ray.iMagicPointsMax4Ray += lNumberOfMagicPoints;
 
		  /* Return number of magic points Max*/
		  lValue = stExtendDatas4Ray.iMagicPointsMax4Ray;
		}
		break;
 
    case eFunc_EnleveEtLitPointsDeMagie:
		{
		  /* Evaluation of next parameter*/
		  M_EvalNextParameter( &stParam );
 
		  /* Get number of magic points to sub*/
		  lNumberOfMagicPoints = M_ReturnParam_lValue( &stParam );
		  SAF_M_AssertWithMsg(lNumberOfMagicPoints >= 0, "On ne peut manipuler que des points de magie positifs!");
 
		  /* Sub "lNumberOfMagicPoints"*/
		  stExtendDatas4Ray.iMagicPoints4Ray -= lNumberOfMagicPoints;
 
		  /* Test if Number of magic points < 0*/
		  if ( stExtendDatas4Ray.iMagicPoints4Ray < 0 )
			stExtendDatas4Ray.iMagicPoints4Ray = 0;
 
		  /* Return number of magic points*/
		  lValue = stExtendDatas4Ray.iMagicPoints4Ray;
		}
		break;
 
    case eFunc_EnleveEtLitPointsDeMagieMax:
		{
		  /* Evaluation of next parameter*/
		  M_EvalNextParameter( &stParam );
 
		  /* Get number of magic points to sub*/
		  lNumberOfMagicPoints = M_ReturnParam_lValue( &stParam );
		  SAF_M_AssertWithMsg(lNumberOfMagicPoints >= 0, "On ne peut manipuler que des points de magie positifs!");
 
		  /* Sub "lNumberOfMagicPoints"*/
		  stExtendDatas4Ray.iMagicPointsMax4Ray -= lNumberOfMagicPoints;
 
		  /* Test if Number of magic points Max < 0*/
		  if ( stExtendDatas4Ray.iMagicPointsMax4Ray < 0 )
			stExtendDatas4Ray.iMagicPointsMax4Ray = 0;
		  /* Return number of magic points Max*/
		  lValue = stExtendDatas4Ray.iMagicPointsMax4Ray;
		}
		break;
 
		default:
#if defined(__DEBUG_AI__) || (defined(U64) && defined(D_CHECK_AI_FPCO))
			  M_AIFatalError(E_uwAIFatalNotValidFunction);
#endif
			  return(p_stTree);
		  break;
  }
 
  /* Inform the motor of the type and the value of the variable*/
  M_Full_GetSetParam_Integer(p_stValue, lValue );
  return(p_stTree);
}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
 
/**********************************************************************
**********************************************************************/
 
static ACP_tdxBool fn_vGetZoneCenter(ACP_tdxHandleOfObject _hGeoObj, MTH3D_tdstVector *_hZoneCenter)
{
	ACP_tdxBool bZoneIsValid;
		/* deal with type of GEO OBJ*/
	switch ( *_hGeoObj->d_xListOfElementsTypes )
	{
	/* Get center of a sphere*/
	case GEO_C_xElementSpheres :
		{
			ACP_tdxIndex xCenter;
 
			/* get Center of the spehere*/
			xCenter = GEO_xGetCenterPointOfIndexedSphere(_hGeoObj,0,0);
			GEO_vGetPointOfObject(_hGeoObj,_hZoneCenter,xCenter);
			/*we found one, dont bother with module zones*/
			bZoneIsValid = 1;
		}
		break;
	/* Get center of a box*/
 
	case GEO_C_xElementAlignedBoxes :
		{
			ACP_tdxIndex xMin,xMax;
			MTH3D_tdstVector stMin,stMax;
 
			/* get Min & Max of the box*/
			GEO_vGetMinMaxPointOfIndexedAlignedBox(_hGeoObj,0,0,&xMin,&xMax);
			GEO_vGetPointOfObject(_hGeoObj,&stMin,xMin);
			GEO_vGetPointOfObject(_hGeoObj,&stMax,xMax);
 
			/* Compute Center*/
			MTH3D_M_vAddVector(_hZoneCenter,&stMin,&stMax);
			MTH3D_M_vMulScalarVector(_hZoneCenter,MTH_C_Inv2,_hZoneCenter);
			/*we found one, dont bother with module zones*/
			bZoneIsValid = 1;
		}
		break;
 
	default:
		bZoneIsValid = 0;
		break;
	}
	return bZoneIsValid;
}
 
static void fn_vInternGetZDxCenter(
	HIE_tdxHandleToSuperObject _hCharacter,
	GMT_tdxMask _xMask,
	unsigned char _ucZoneType,
	ACP_tdxBool _bInGlobalCoordinates,
	MTH3D_tdstVector *_p_stReturnVector
)
{
	long lI, lMax;
	ACP_tdxHandleOfObject hGeoObj;
	ACP_tdxBool bFoundOne = 0;
 
	/* found the good Zone in the list*/
	lMax = fn_lGetZdxListNumberOfElements(_ucZoneType, _hCharacter);
	for ( lI = 0; lI < lMax; lI ++ )
	{
		hGeoObj = fn_hGetGeometricZdxOfTypeAtIndex(_ucZoneType, (unsigned short)lI, _hCharacter);
		if ( hGeoObj && fn_hIsTypeExistsInGeoObj(hGeoObj, _xMask) && fn_hIsThisZoneActive(_hCharacter, _ucZoneType, (unsigned char) lI) )
		{
			if ( (bFoundOne = fn_vGetZoneCenter(hGeoObj, _p_stReturnVector)) != 0 ) /*VOLUNTARY ASSIGNMENT!*/
			{
				if ( _bInGlobalCoordinates )
				{
					POS_fn_vMulMatrixVertex(_p_stReturnVector,HIE_fn_hGetSuperObjectGlobalMatrix(_hCharacter),_p_stReturnVector);
				}
				else
				{
					MTH3D_tdstMatrix stScaleMatrix;
					POS_tdstCompletePosition *hGlobalMatrix = HIE_fn_hGetSuperObjectGlobalMatrix(_hCharacter);
					/*dont forget to apply the actor's scale to the relative position if necessary*/
					if ( !POS_fn_ulIsNotScaledMatrix(hGlobalMatrix) )
					{
						POS_fn_vGetScaleMatrix(
							hGlobalMatrix,
							&stScaleMatrix.stCol_0,
							&stScaleMatrix.stCol_1,
							&stScaleMatrix.stCol_2
						);
						MTH3D_M_vMulMatrixVector(_p_stReturnVector, &stScaleMatrix, _p_stReturnVector);
					}
				}
				break;
			}
		}
	}
 
	/*we found no zones, check module zones to see if we get what we want there*/
  if ( !bFoundOne )
	{
		PCS_tdxHandleToPhysicalCollSet hPhysicalCollideSet;
		CHN_tdxHandleToChannel hChannel;
		/*ACP_tdxIndex xIndex;*/
		HIE_tdxHandleToSuperObject hModule;
 
		hChannel = fn_h3dDataGetFirstActiveChannel(M_GetMSHandle(_hCharacter,3dData));
		while (hChannel)
		{
			hModule = hChannel->hSupObject;
			if
			(
				hModule 
				&& ( (HIE_fn_ulGetSuperObjectType(hModule) & (HIE_C_ulPO | HIE_C_ulPO_Mirror)) )
				/* beware, the flag name is improper: it is true when the object is visible */
				&& ( ! ( HIE_M_xGetSuperObjectMember(hModule, ulFlags) & HIE_C_Flag_ulHidden ) ) /* don't use a zone when its channel is deactivated */
			)
			{
				hPhysicalCollideSet = PO_fn_hGetCollideSet( (PO_tdxHandleToPhysicalObject)HIE_fn_hGetSuperObjectObject(hModule) );
				switch ( _ucZoneType )
				{
				case C_ucTypeZde:
					hGeoObj = PCS_fn_hGetZdeGeoObjOfPhysicalCollSet(hPhysicalCollideSet);
					break;
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
				case C_ucTypeZdd:
					hGeoObj = PCS_fn_hGetZddGeoObjOfPhysicalCollSet(hPhysicalCollideSet);
					break;
 
				case C_ucTypeZdr:
					hGeoObj = PCS_fn_hGetZdrGeoObjOfPhysicalCollSet(hPhysicalCollideSet);
					break;
 
				case C_ucTypeZdm:
					hGeoObj = PCS_fn_hGetZdmGeoObjOfPhysicalCollSet(hPhysicalCollideSet);
					break;
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
				default:
					hGeoObj = NULL;
					break;
				}
				if ( hGeoObj && fn_hIsTypeExistsInGeoObj(hGeoObj, _xMask) && ( (bFoundOne = fn_vGetZoneCenter(hGeoObj, _p_stReturnVector)) != 0) ) /*VOLUNTARY ASSIGNMENT!*/
			    {
					POS_tdstCompletePosition stGlobToPerso;
 
					#ifdef ACTIVE_EDITOR
					fn_vCheckModuleAccess(_hCharacter, FALSE, &hModule);
					#endif
					/*express the center in perso coordinates (it is in module's coordinates)*/
					/* passing by global coordinates due to possible hierarchy*/
					POS_fn_vMulMatrixVertex(_p_stReturnVector,HIE_fn_hGetSuperObjectGlobalMatrix(hModule),_p_stReturnVector);
					if ( !_bInGlobalCoordinates )
					{
						POS_fn_vInvertMatrix(&stGlobToPerso,HIE_fn_hGetSuperObjectGlobalMatrix(_hCharacter));
						POS_fn_vMulMatrixVertex(_p_stReturnVector,&stGlobToPerso,_p_stReturnVector);
					}
					/*and stop now, because we got what we want*/
					break;
				}
			}
			hChannel = hChannel->p_stNextActiveChannel;
		}
	}
}
 
/**********************************************************************
* Function: PersoLePlusProche                                         *
* Function: CibleLaPlusProche                                         *
* Use	  : Perso = PersoLePlusProche()                               *
*           Return NULL is there is no perso (enemy)                  *
*           !! A enemy is a character with Good  Custom Bit           *
* Use	  : Perso = CibleLaPlusProche()                               *
*           Return NULL is there is no perso (enemy)                  *
*           !! A enemy is a character with Good  Custom Bit           *
*                                                                     *
* Author  : Christophe Giraud                                         *
* Date of last modification: 24/11/97                                 *
* Modif : 15/07/98 Add CibleLaPlusProche - Carlos Torres              *
* Modif : 17/07/98 Add PersoLePlusProcheDansChampsDeVision - jt       *
* Modif : 20/08/98 Add Search direction in CibleLaPlusProche - CT     *
**********************************************************************/
 
HIE_tdxHandleToSuperObject fn_hGetClosestPersoInSector(
  HIE_tdxHandleToSuperObject _hCloserSO, /*the closest perso I found so far*/
  MTH_tdxReal *_p_xBestDist, /* the distance at which I found the closest until now*/
  MTH_tdxReal *_p_xPrevWeight, /*its associated weight*/
  HIE_tdxHandleToSuperObject _hMe, /*identify myself so that I cant be the closet actor to myself...*/
  MTH3D_tdstVector *_p_stMyVector, /*where I am*/
  MTH3D_tdstVector *_p_stActorSighting, /*where I look*/
	POS_tdstCompletePosition *_p_stGlobToPerso, /*matrix to convert positions into my local coordinates*/
  HIE_tdxHandleToSuperObject _hSector, /*sector to search*/
  unsigned long _ulFilterCustomBits, /*custombits to accept*/
  MTH_tdxReal _xXWeight,
  MTH_tdxReal _x2DWeight,
  MTH_tdxReal _x3DWeight,
  GMT_tdxMask _xMask, /*if the test has to be done against a ZDE center, the mask will be non null...*/
  MTH_tdxReal _xCosXoY, /* angle of the the cone in degree*/
  MTH_tdxReal _xSinYoZ, /* angle of the the cone in degree*/
  enum tdeFuncId_ _eFuncId /*what is to be done*/
)
{
	SECT_tdxHandleOfElementLstCharacter hCharacterElement;
	HIE_tdxHandleToSuperObject hCharacterSO;
	int j;
  MTH_tdxReal xTmp;
  MTH3D_tdstVector stVector;
  MS_tdxHandleToStandardGame hStdGame;
#ifdef ONLY4DEBUG
	char					*cName,*cCloserName;
	MS_tdxHandleToBrain	hBrain;
#endif
 
	/* Find all characters in the current sector of the list*/
	SECT_M_ForEachCharListInSector(_hSector, hCharacterElement, j)
	{
		hCharacterSO = SECT_GetCharacterInList( hCharacterElement );
 
		if ( hCharacterSO != _hMe )
		{
 
#ifdef ONLY4DEBUG
			hBrain = M_GetMSHandle(hCharacterSO,Brain);
			if (hBrain)
				cName = AI_M_szGetPersoName(AI_M_stGetMindOfSuperObj(hCharacterSO));
#endif
 
			/* Do this only if CustomBits are set*/
			/* if ( (fn_ulStandardGameGetCustomBits(M_GetMSHandle(hCharacterSO,StandardGame)) & _ulFilterCustomBits) == _ulFilterCustomBits ) */
			hStdGame = M_GetMSHandle(hCharacterSO,StandardGame);

			if( hStdGame &&																						/* always not destroyed */
				!fn_bf1StandardGameGetIsDesactivateAtAll(hStdGame) &&											/* actor not definitively dead */
				( (fn_ulStandardGameGetCustomBits(hStdGame) & _ulFilterCustomBits) == _ulFilterCustomBits ) )	/* wanted custombits */
			{
				/* by default use the coordinates of the character*/
				POS_fn_vGetTranslationVector( HIE_fn_hGetSuperObjectGlobalMatrix( hCharacterSO ), &stVector );
				if ( _xMask ) /*if we want to test a ZDE position, get it now*/
					fn_vInternGetZDxCenter(hCharacterSO, _xMask, C_ucTypeZde, TRUE, &stVector);
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /*{*/
				/* PERSO LE PLUS PROCHE*/
				if ( _eFuncId == eFunc_PersoLePlusProche )
		        {
					/* Distance between My character and other one*/
					xTmp = MTH3D_M_xVectorGap(&stVector, _p_stMyVector);
					if ( MTH_M_bLess(xTmp, *_p_xBestDist) )
					{
						*_p_xBestDist = xTmp;
						_hCloserSO = hCharacterSO;
#ifdef ONLY4DEBUG
						hBrain = M_GetMSHandle(hCharacterSO,Brain);
						if (hBrain)
							cCloserName = AI_M_szGetPersoName(AI_M_stGetMindOfSuperObj(hCharacterSO));
#endif
					}
				}
				/* PERSO LE PLUS PROCHE DANS LE CHAMPS DE VISION*/
				else if ( _eFuncId == eFunc_NearerActorInFieldOfVision )
				{
					MTH3D_M_vSubVector ( &stVector, _p_stMyVector, &stVector );
					MTH3D_M_vNormalizeVector ( &stVector, &stVector );
					xTmp = MTH3D_M_xDotProductVector ( _p_stActorSighting, &stVector );
					if ( MTH_M_bGreater(xTmp, MTH_M_xDoubleToReal(0.5)) )
					{
						xTmp = MTH3D_M_xVectorGap(&stVector, _p_stMyVector);
						if ( MTH_M_bLess(xTmp,*_p_xBestDist) )
						{
							*_p_xBestDist = xTmp;
							_hCloserSO = hCharacterSO;
#ifdef ONLY4DEBUG
						hBrain = M_GetMSHandle(hCharacterSO,Brain);
						if (hBrain)
							cCloserName = AI_M_szGetPersoName(AI_M_stGetMindOfSuperObj(hCharacterSO));
#endif
						}
					}
				}
				else
#endif /* !defined(_AI_EXCLUDE_NEVER_USED_) */ /*}*/
				/* CIBLE LA PLUS PROCHE*/
				{
					MTH3D_tdstVector stTargetPosition;
					MTH_tdxReal	xNorm ,xX, xY, xZ, xWeight = MTH_C_ZERO;
					MTH_tdxReal	xNormXoY, xAngleYoZ ;
 
 					/* get target position in perso coordinates*/
					POS_fn_vMulMatrixVertex(&stTargetPosition,_p_stGlobToPerso,&stVector);
					MTH3D_M_vGetVectorElements(&xX,&xY,&xZ,&stTargetPosition);

					stTargetPosition.xZ = MTH_C_ZERO;
					xNormXoY = MTH3D_M_xNormVector(&stTargetPosition);
					stTargetPosition.xZ = xZ;

					if ( xNormXoY )
						xAngleYoZ = MTH_M_xATan ( MTH_M_xDiv ( xZ , xNormXoY ) ) ;
					else
						xAngleYoZ = MTH_C_PiBy2 ;

					/* compute weight if target is in both detection sectors */
					if
					(
						MTH_M_bGreater ( MTH_M_xNeg ( xY ) , MTH_M_xMul ( _xCosXoY , xNormXoY ) )
						&& MTH_M_bLess ( MTH_M_xSin ( xAngleYoZ ), _xSinYoZ )
					)
					{
						/* if the target is in the back of the fighter, consider the angle only! */
						if ( MTH_M_bGreaterEqualZero ( xY ) )
						{
							if ( MTH_M_bEqualZero(xX) )
							{
								/* the target is straight in the back of the fighter: no way we select it! */
								xWeight = MTH_C_InfinitMinus ;
							}
							else
							{
								/* we use a negative weight to continue favorizing the target in front of the fighter */
								/* but the target with the smaller angle is preferred, ie the less in the back */
								xWeight = MTH_M_xNeg ( MTH_M_xAbs ( MTH_M_xDiv ( xY , xX ) ) ) ;
							}
						}
						else
						{
							/* compute Weight N1/|X| + N2/|XY| + N3/|XYZ|*/
							if ( MTH_M_bEqualZero(xX) )
							{
								xWeight = MTH_C_InfinitPlus;
							}
							else
							{
  								xX = MTH_M_xAbs(xX);
								xNorm = MTH3D_M_xNormVector(&stTargetPosition);

								xWeight = MTH_M_xDiv(_xXWeight, xX);
								xWeight = MTH_M_xAdd(xWeight, MTH_M_xDiv(_x2DWeight, MTH_M_xSqrt(MTH_M_xAdd(MTH_M_xSqr(xX),MTH_M_xSqr(xY)))));
								xWeight = MTH_M_xAdd(xWeight, MTH_M_xDiv(_x3DWeight, xNorm));
							}
						}
 
						/* better target*/
						if ( MTH_M_bGreater(xWeight,*_p_xPrevWeight) )
						{
							*_p_xPrevWeight = xWeight;
							_hCloserSO = hCharacterSO;
#ifdef ONLY4DEBUG
						  hBrain = M_GetMSHandle(hCharacterSO,Brain);
						  if (hBrain)
							  cCloserName = AI_M_szGetPersoName(AI_M_stGetMindOfSuperObj(hCharacterSO));
#endif
						}
					}
				}
			}
		}
	}
	return _hCloserSO ;
}
 
tdstNodeInterpret *fn_p_stCode4PersoLePlusProche(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	tdstGetSetParam									stParam;
	HIE_tdxHandleToSuperObject						hCurrentSectorPerso,hGraphicSectorSO,/*hCharacterSO,*/hCloserSO = NULL;
 
	SECT_tdxHandleOfElementLstGraphicInteraction	hGraphicElement;
	/*SECT_tdxHandleOfElementLstCharacter				hCharacterElement;*/
	MTH3D_tdstVector								stMyVector/*, stVector*/;
	struct POS_stCompletePosition					stGlobToPerso;
	MTH_tdxReal										/*xTmp,*/xBestDist = MTH_C_InfinitPlus;
	unsigned long									ulCustomBitValue;
	MTH_tdxReal										xXWeight = MTH_C_ZERO, x2DWeight = MTH_C_ZERO, x3DWeight = MTH_C_ZERO;
	MTH_tdxReal										xPrevWeight = MTH_M_xDiv ( MTH_C_InfinitMinus , MTH_C_2 ) ;
	MTH3D_tdstVector								*p_stTmpVector1, *p_stTmpVector2, *p_stActorSighting,stDirection;
	GMT_tdxMask										xMask = (GMT_tdxMask) 0;
	/*MTH_tdxReal									xDotProd;*/
	MTH_tdxReal										xCosXoY = MTH_M_xFloatToReal(0.8944f), xSinYoZ = MTH_M_xFloatToReal(0.4473f); /* default angle 26.56deg*/
 
 
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
	/*XB980429*/
	/*  long lValue=0;*/
	/*End XB*/
	int i/*, j*/;
	/*unsigned long ulCurrentBits;*/
 
	/*#ifdef ONLY4DEBUG
	char					*cName,*cCloserName;
	MS_tdxHandleToBrain	hBrain;
#endif*/
 
	/********************************************************************************/
	/* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
	/********************************************************************************/
	HIE_tdxHandleToSuperObject hNewSuperObjPerso;
	fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId), p_SuperObjPerso, &hNewSuperObjPerso);
	/********************************************************************************/
 
	/* Evaluation of next parameter*/
	M_EvalNextParameter( &stParam );
 
	/* Get number the custom bit value*/
	ulCustomBitValue = M_ReturnParam_lValue(&stParam);
 
	switch(eFuncId)
	{
	case eFunc_CibleLaPlusProcheAvecAngles:
	case eFunc_CibleLaPlusProche:
		/* Get weight for x distance*/
		M_EvalNextParameter( &stParam );
		xXWeight = M_ReturnParam_xValue(&stParam);
		SAF_M_AssertWithMsg(MTH_M_bGreaterEqual(xXWeight, MTH_C_ZERO), "Les poids doivent être positifs ou nuls!");
		/* Get weight for distance in plan XY*/
		M_EvalNextParameter( &stParam );
		x2DWeight = M_ReturnParam_xValue(&stParam);
		SAF_M_AssertWithMsg(MTH_M_bGreaterEqual(x2DWeight, MTH_C_ZERO), "Les poids doivent être positifs ou nuls!");
		/* Get weight for global distance*/
		M_EvalNextParameter( &stParam );
		x3DWeight = M_ReturnParam_xValue(&stParam);
		SAF_M_AssertWithMsg(MTH_M_bGreaterEqual(x3DWeight, MTH_C_ZERO), "Les poids doivent être positifs ou nuls!");
		/* Get Search direction (absolute coordinates)*/
		M_EvalNextParameter( &stParam );
		stDirection=M_GetSetParam_stVectorValue(&stParam);
		xMask = (GMT_tdxMask) 0x0001; /* type JaiMalType*/
 
		/* get angle and compute Cosinus*/
		if (eFunc_CibleLaPlusProcheAvecAngles == eFuncId)
		{
			M_EvalNextParameter( &stParam );
			xCosXoY = M_ReturnParam_xValue(&stParam);
			SAF_M_AssertWithMsg(
				MTH_M_bGreaterZero(xCosXoY) && MTH_M_bLessEqual(xCosXoY, MTH_M_xFloatToReal(180.0f)),
				"L'angle horizontal doit être compris entre 0° exclus et 180° inclus !"
			);
			xCosXoY = MTH_M_xCos(MTH_M_xDegToRad(xCosXoY));

			M_EvalNextParameter( &stParam );
			xSinYoZ = M_ReturnParam_xValue(&stParam);
			SAF_M_AssertWithMsg(
				MTH_M_bGreaterZero(xSinYoZ) && MTH_M_bLessEqual(xSinYoZ, MTH_M_xFloatToReal(90.0f)),
				"L'angle vertical doit être compris entre 0° exclus et 90° inclus !"
			);
			xSinYoZ = MTH_M_xSin(MTH_M_xDegToRad(xSinYoZ));
		}
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /*{*/
	case eFunc_PersoLePlusProche:
	case eFunc_NearerActorInFieldOfVision:
#endif /*!defined(_AI_EXCLUDE_NEVER_USED_)*/ /*}*/
		{
			/* Point to the current sector where the character is*/
			hCurrentSectorPerso = fn_h_SectInfoGetCurrentSector( M_GetMSHandle( hNewSuperObjPerso, SectInfo ) );
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /*{*/
			/* PERSO LE PLUS PROCHE*/
			if (eFuncId == eFunc_PersoLePlusProche)
			{
				/* Coordinates of my character*/
				POS_fn_vGetTranslationVector( HIE_fn_hGetSuperObjectGlobalMatrix( hNewSuperObjPerso), &stMyVector );
			}
			/* PERSO LE PLUS PROCHE DANS CHAMPS DE VISION*/
			else if ( eFuncId == eFunc_NearerActorInFieldOfVision )
			{
				POS_tdxHandleToPosition hActorMatrix = HIE_fn_hGetSuperObjectGlobalMatrix( hNewSuperObjPerso);
				POS_fn_vGetTranslationVector( hActorMatrix, &stMyVector );
				POS_fn_vGetRotationVector ( hActorMatrix, &p_stTmpVector1, &p_stActorSighting, &p_stTmpVector2 );
			}
			else
#endif /*!defined(_AI_EXCLUDE_NEVER_USED_)*/ /*}*/
			/* CIBLE LA PLUS PROCHE*/
			{
				MTH3D_tdstVector vI,vJ,vK;
				struct POS_stCompletePosition stGlobPerso;
 
				/* get Glob Matrix & current rotation of perso*/
				POS_fn_vCopyMatrix(&stGlobPerso,HIE_fn_hGetSuperObjectGlobalMatrix(hNewSuperObjPerso));
 
				if (!MTH3D_M_bIsNullVector(&stDirection)) {
					POS_fn_vGetRotationMatrix(&stGlobPerso,&vI,&vJ,&vK);
 
					/* Compute new rotation with the direction*/
					/* compute J*/
					MTH3D_M_vNegVector(&stDirection,&stDirection);
					MTH3D_M_vNormalizeVector(&vJ,&stDirection);
 
					/* compute K before I, if J&K are colinear*/
					if (MTH_M_bEqualWithEpsilon(MTH3D_M_xDotProductVector(&vJ,&vK),MTH_C_ONE,MTH_M_xFloatToReal(0.002)) ) {
						/* compute K*/
						MTH3D_M_vCrossProductVectorWithoutBuffer(&vK,&vI,&vJ);
						/* compute I*/
						MTH3D_M_vCrossProductVectorWithoutBuffer(&vI,&vJ,&vK);
					}
					/* compute I before K*/
					else {
						/* compute I*/
						MTH3D_M_vCrossProductVectorWithoutBuffer(&vI,&vJ,&vK);
						/* compute K*/
						MTH3D_M_vCrossProductVectorWithoutBuffer(&vK,&vI,&vJ);
					}
 
					/* change rotation*/
					POS_fn_vSetRotationMatrix(&stGlobPerso,&vI,&vJ,&vK);
				}
 
				/* build matrix to transform glob coordinates in perso coordinates*/
				POS_fn_vInvertIsoMatrix(&stGlobToPerso,&stGlobPerso);
			}
 
			hCloserSO = fn_hGetClosestPersoInSector(
				hCloserSO, /*the closest perso I found so far*/
				&xBestDist, /* the distance at which I found it*/
				&xPrevWeight, /*its associated weight*/
				hNewSuperObjPerso, /*identify myself so that I cant be the closet actor to myself...*/
				&stMyVector, /*where I am*/
				p_stActorSighting, /*where I look*/
				&stGlobToPerso, /*matrix to convert positions into my local coordinates*/
				hCurrentSectorPerso, /*sector to search*/
				ulCustomBitValue, /*custombits to accept*/
				xXWeight,
				x2DWeight,
				x3DWeight,
				xMask,
				xCosXoY,
				xSinYoZ,
				eFuncId /*what is to be done*/
			);
 
			/* Cover the list of visible sectors*/
			SECT_M_ForEachGraphicNodeInGraphicInteractionList(hCurrentSectorPerso, hGraphicElement, i)
			{
				hGraphicSectorSO = SECT_GetSectorInGraphicList( hGraphicElement );
 
				hCloserSO = fn_hGetClosestPersoInSector(
					hCloserSO, /*the closest perso I found so far*/
					&xBestDist, /* the distance at which I found it*/
					&xPrevWeight, /*its associated weight*/
					hNewSuperObjPerso, /*identify myself so that I cant be the closet actor to myself...*/
					&stMyVector, /*where I am*/
					p_stActorSighting, /*where I look*/
					&stGlobToPerso, /*matrix to convert positions into my local coordinates*/
					hGraphicSectorSO, /*sector to search*/
					ulCustomBitValue, /*custombits to accept*/
					xXWeight,
					x2DWeight,
					x3DWeight,
					xMask,
					xCosXoY,
					xSinYoZ,
					eFuncId /*what is to be done*/
				);
			}
		}
		/* On informe le moteur sur le type et la valeur calculée.*/
		M_Full_GetSetParam_Perso(p_stValue, hCloserSO);
		return(p_stTree);
		break;
 
	default:
		break;
  }
 
  /* La fonction n'existe pas !!*/
  M_AIFatalError(E_uwAIFatalNotValidFunction);
 
  /* On informe le moteur sur l'avancement dans l'interprétation*/
  return p_stTree;
}
 
 
/*ANNECY JMD & BART {*/
tdstNodeInterpret *fn_p_stGraphFunction(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
  enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
  WP_tdHandleOfGraph hGraph ;
  long lValue, lWeight;
  unsigned long ulNewCaps;
/*  struct tdstEngineObject_ * hEngineObj; // there's no "tdhEngineObject" ? ? ? ? ? ? ! ! !*/
/* Oliv' - Portage v14*/
/*  char bIsCircular=0;*/
/* EndOfOliv'*/
  WP_tdhWayPoint hWayPoint1, hWayPoint2 ;
 
  /********************************************************************************/
  /* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
  /********************************************************************************/
/*  HIE_tdxHandleToSuperObject hNewSuperObjPerso;*/
/*  fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewSuperObjPerso);*/
 
  /* Evaluation of parameters*/
  M_EvalNextParameter( p_stValue );
#if defined(__DEBUG_AI__)
  M_VerifyTypeOfParamAction(p_stValue, E_vt_Graph);
#endif /* __DEBUG_AI__*/
  hGraph = M_GetSetParam_GraphValue(p_stValue) ;
  M_EvalNextParameter( p_stValue );
  hWayPoint1 = M_GetSetParam_WayPointValue(p_stValue) ;
  M_EvalNextParameter( p_stValue );
  hWayPoint2 = M_GetSetParam_WayPointValue(p_stValue) ;
 
  if (hGraph == NULL)
  {
    if (eFuncId == eFunc_ReseauLitCapaciteLiaisonDansGraph)
	{
      M_Full_GetSetParam_Caps(p_stValue, (unsigned long)0);
    }
    else
	{
      M_Full_GetSetParam_Integer(p_stValue, -1);
    }
    return(p_stTree);
  }
 
  switch(eFuncId)
  {
    case eFunc_ReseauLitCapaciteLiaisonDansGraph :
    {
      if(WPG_fn_lGetLinkCapabilities (hGraph, hWayPoint1, hWayPoint2, &ulNewCaps ) == -1) { /*-1 if failed !*/
        M_Full_GetSetParam_Caps(p_stValue, (unsigned long)0);
      } else {
        M_Full_GetSetParam_Caps(p_stValue, ulNewCaps);
      }
      return(p_stTree);
	  break;
    }
 
    case eFunc_ReseauChangeCapaciteLiaisonDansGraph :
    {
      M_EvalNextParameter( p_stValue );
      ulNewCaps = M_GetSetParam_CapsValue( p_stValue);
      M_EvalNextParameter( p_stValue );
      lValue = M_GetSetParam_lValue(p_stValue) ;
 
      lValue = WPG_fn_lChangeLinkCapabilities (hGraph, hWayPoint1, hWayPoint2, ulNewCaps, lValue ) ;
 
      /* On informe le moteur sur le type et la valeur calculée.*/
      M_Full_GetSetParam_Integer(p_stValue, lValue);
      return(p_stTree);
	  break;
    }
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
    case eFunc_ReseauLitPoidsLiaisonDansGraph :
    {
      if(WPG_fn_lGetLinkWeight(hGraph, hWayPoint1, hWayPoint2, &lWeight ) == -1) { /*-1 if failed !*/
        M_Full_GetSetParam_Integer(p_stValue, -1);
      } else {
        M_Full_GetSetParam_Integer(p_stValue, lWeight);
      }
      return(p_stTree);
	  break;
    }
 
    case eFunc_ReseauChangePoidsLiaisonDansGraph :
    {
      M_EvalNextParameter( p_stValue );
      lWeight = M_GetSetParam_lValue(p_stValue) ;
 
      lValue = WPG_fn_lChangeLinkWeight(hGraph, hWayPoint1, hWayPoint2, lWeight) ;
 
      /* On informe le moteur sur le type et la valeur calculée.*/
      M_Full_GetSetParam_Integer(p_stValue, lValue);
      return(p_stTree);
	  break;
    }
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
		default:
break;
  }
 
  /* La fonction n'existe pas !!*/
  M_AIFatalError(E_uwAIFatalNotValidFunction);
 
  /* On informe le moteur sur l'avancement dans l'interprétation*/
  return(p_stTree);
}
 
 
tdstNodeInterpret *fn_p_stGraphToWayFunction(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
  enum tdeFuncId_ eFuncId;
  MS_tdxHandleToMSWay h_MSWay;
  WP_tdHandleOfGraph hGraph ;
  long lValue ;
  struct tdstEngineObject_ * hEngineObj; /* there's no "tdhEngineObject" ? ? ? ? ? ? ! ! !*/
  char bIsCircular;
  WP_tdHandleOfGraph hPath ;
  WP_tdhWayPoint hWayPoint1, hWayPoint2 ;
  WP_tdhGraphNode hCurrentNode ; /*Bart*/
  unsigned long ulPersoCapability ;
  int i;
 
  /********************************************************************************/
  /* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
  /********************************************************************************/
  HIE_tdxHandleToSuperObject hNewSuperObjPerso;
 
  eFuncId=M_eFuncIdInterpret(p_stTree-1);
  fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewSuperObjPerso);
 
  h_MSWay = M_GetMSHandle(hNewSuperObjPerso, MSWay);
 SAF_M_AssertWithMsg((h_MSWay != NULL),"MsWay non alloué")
 
  M_EvalNextParameter( p_stValue );
 #if defined(__DEBUG_AI__)
  M_VerifyTypeOfParamAction(p_stValue, E_vt_Graph);
 #endif /* __DEBUG_AI__*/
  hGraph = M_GetSetParam_GraphValue(p_stValue) ;
 
 
  /* 0 is the default (error) return value !*/
  lValue = 0;
  /* The way is not circular by default !*/
  bIsCircular=0;
 
  switch(eFuncId)
  {
    case eFunc_ReseauCheminLePlusCourt :
      {
        /* Evaluation of parameters*/
        M_EvalNextParameter( p_stValue );
        hWayPoint1 = M_GetSetParam_WayPointValue(p_stValue) ;
        M_EvalNextParameter( p_stValue );
        hWayPoint2 = M_GetSetParam_WayPointValue(p_stValue) ;
 
        if ( ( h_MSWay == NULL) || (hGraph == NULL) )
		{
          M_Full_GetSetParam_Integer(p_stValue, 0L);
          return(p_stTree);
		  break;
        }
 
        /* get perso capability */
        hEngineObj = M_GetEngineObject(hNewSuperObjPerso);
        ulPersoCapability = fn_ulGetCapabilities(hEngineObj);
 
        hPath = WPG_fn_lShortestPath (hGraph, hWayPoint1, hWayPoint2, ulPersoCapability ) ;
 
        if ( hPath ) {
          MSWay_fn_vSetPath(h_MSWay, hPath, 0); /* bIsCircular=0;*/
          lValue = WPG_fn_lNumberOfWaypointOfGraph (hPath) ;
        }
        else {
          MSWay_fn_vDesinitPath(h_MSWay) ;
          lValue = 0 ;
        }
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue );
        return(p_stTree);
		break;
      }
 
    case eFunc_NetworkBuildOrderedPathCircular:
      bIsCircular = 1;
    case eFunc_NetworkBuildOrderedPath :
      {
        /* Evaluation of parameters*/
        M_EvalNextParameter( p_stValue );
        hWayPoint1 = M_GetSetParam_WayPointValue(p_stValue);
 
        if ( ( h_MSWay == NULL) || (hGraph == NULL) )
		{
          M_Full_GetSetParam_Integer(p_stValue, 0L);
          return(p_stTree);
		  break;
        }
 
        hPath = WPG_fn_lBuildOrderedPath(hGraph, hWayPoint1 );
 
        if ( hPath ) {
          MSWay_fn_vSetPath(h_MSWay, hPath, bIsCircular);
          lValue = WPG_fn_lNumberOfWaypointOfGraph (hPath);
        }
        else {
          MSWay_fn_vDesinitPath(h_MSWay) ;
          lValue = 0 ;
        }
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue );
        return(p_stTree);
		break;
      }
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
    case eFunc_NetworkAllocateGraphToMSWayCircular:
      bIsCircular = 1;
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
    case eFunc_NetworkAllocateGraphToMSWay:
      {
        /*SAF_M_AssertWithMsg(FALSE,"Ne plus utiliser \"Reseau_AffecteGraphAChemin\" SVP !")*/
 
        /* No more parameter*/
 
        if ( ( h_MSWay == NULL) || (hGraph == NULL) )
		{
          M_Full_GetSetParam_Integer(p_stValue, 0);
          return(p_stTree);
		  break;
        }
 
#if defined(OLD_CODE)
        MSWay_fn_vSetPath(h_MSWay, hGraph, bIsCircular);
        lValue = WPG_fn_lNumberOfWaypointOfGraph (hGraph) ;
#else /*OLD_CODE*/
		LST2_M_DynamicGetElementNumber(&hGraph->m_hListOfNode, hCurrentNode, 0, i); /* first WP*/
 
        hPath = WPG_fn_lBuildOrderedPath(hGraph, hCurrentNode->m_hWayPoint );
 
        if ( hPath ) {
          MSWay_fn_vSetPath(h_MSWay, hPath, bIsCircular);
          lValue = WPG_fn_lNumberOfWaypointOfGraph (hPath);
        }
        else {
          MSWay_fn_vDesinitPath(h_MSWay) ;
          lValue = 0 ;
        }
#endif /*defined(OLD_CODE)*/
 
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue );
        return(p_stTree);
		break;
      }
 
	default:
		break;
  }
 
  /* La fonction n'existe pas !!*/
  M_AIFatalError(E_uwAIFatalNotValidFunction);
 
  /* On informe le moteur sur l'avancement dans l'interprétation*/
  return(p_stTree);
}
 
 
tdstNodeInterpret *fn_p_stWayFunction(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
  enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
  MS_tdxHandleToMSWay h_MSWay;
  long lValue, lIndex, lWeight ;
  unsigned long ulNewCaps;
/*  struct tdstEngineObject_ * hEngineObj; // there's no "tdhEngineObject" ? ? ? ? ? ? ! ! !*/
 
/* Oliv' - Portage v15 - remove unused local variable and 1 warning*/
/*  char bIsCircular=0;*/
/* EndOfOliv'*/
 
  /********************************************************************************/
  /* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
  /********************************************************************************/
  HIE_tdxHandleToSuperObject hNewSuperObjPerso;
  fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewSuperObjPerso);
 
  h_MSWay = M_GetMSHandle(hNewSuperObjPerso, MSWay);
 SAF_M_AssertWithMsg((h_MSWay != NULL),"MsWay non alloué")
  if ( h_MSWay == NULL) {
	  //XB 14/099
#if defined(U64)
	M_PrintfStopErrorN64(("MsWay not allocated SPO=0x%x",hNewSuperObjPerso));
	return NULL;
#endif /* defined(U64) && !defined(FINAL_VERSION) */
//End XB 14/099
    switch(eFuncId)
    {
      case eFunc_ReseauLitWPAIndex :
        M_Full_GetSetParam_WayPoint(p_stValue, NULL );
        break;
      case eFunc_ReseauLitCapaciteLiaisonAIndex :
        M_Full_GetSetParam_Caps(p_stValue, (unsigned long)0);
/* Oliv' - Portage v14*/
			default : break;
/* EndOfOliv'*/
    }
    M_Full_GetSetParam_Integer(p_stValue, -1 );
    return(p_stTree);
  }
 
  switch(eFuncId)
  {
  case eFunc_ReseauLitIndexCourant:
    {
 
      lValue = MSWay_fn_lGetCurrentIndexInPath (h_MSWay) ;
      /* On informe le moteur sur le type et la valeur calculée.*/
      M_Full_GetSetParam_Integer(p_stValue, lValue );
      return(p_stTree);
	  break;
 
    }
 
  case eFunc_ReseauForceIndexCourant:
    {
      M_EvalNextParameter( p_stValue );
      lValue = MSWay_fn_lSetCurrentIndexInPath(h_MSWay, M_GetSetParam_lValue(p_stValue) );
      /* On informe le moteur sur le type et la valeur calculée.*/
      M_Full_GetSetParam_Integer(p_stValue, lValue );
      return(p_stTree);
	  break;
    }
 
  case eFunc_ReseauLitPremierIndex:
    {
      lValue = MSWay_fn_lGetFirstIndexInPath ( h_MSWay ) ;
      /* On informe le moteur sur le type et la valeur calculée.*/
      M_Full_GetSetParam_Integer(p_stValue, lValue );
      return(p_stTree);
	  break;
    }
 
  case eFunc_ReseauLitDernierIndex:
    {
      lValue = MSWay_fn_lGetLastIndexInPath ( h_MSWay ) ;
      /* On informe le moteur sur le type et la valeur calculée.*/
      M_Full_GetSetParam_Integer(p_stValue, lValue );
      return(p_stTree);
	  break;
    }
		case eFunc_ReseauIncrementIndex :
      {
        /* Evaluation of next parameter*/
        M_EvalNextParameter( p_stValue );
        lValue=MSWay_fn_lIncrementCurrentIndexInPath(h_MSWay, M_GetSetParam_lValue(p_stValue) );
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue );
        return(p_stTree);
		break;
      }
    case eFunc_ReseauDecrementIndex :
      {
        /* Evaluation of next parameter*/
        M_EvalNextParameter( p_stValue );
        lValue=MSWay_fn_lIncrementCurrentIndexInPath(h_MSWay, -(M_GetSetParam_lValue(p_stValue)) );
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue );
        return(p_stTree);
		break;
      }
    case eFunc_ReseauLitWPAIndex :
      {
        WP_tdhWayPoint hWayPoint ;
 
        /* Evaluation of next parameter*/
        M_EvalNextParameter( p_stValue );
        hWayPoint=MSWay_fn_hGetWayPointOfPath(h_MSWay, M_GetSetParam_lValue(p_stValue) );
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_WayPoint(p_stValue, hWayPoint );
        return(p_stTree);
		break;
      }
    case eFunc_ReseauLitCapaciteLiaisonAIndex :
      {
        /* Evaluation of parameters*/
        M_EvalNextParameter( p_stValue );
        lIndex = M_GetSetParam_lValue(p_stValue) ;
 
        ulNewCaps = MSWay_fn_ulGetCapsForNextWayPointOfPath (h_MSWay, lIndex) ;
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Caps(p_stValue, ulNewCaps);
        return(p_stTree);
		break;
      }
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
    case eFunc_ReseauChangeCapaciteLiaisonAIndex :
      {
        /* Evaluation of parameters*/
        M_EvalNextParameter( p_stValue );
        lIndex = M_GetSetParam_lValue(p_stValue) ;
        M_EvalNextParameter( p_stValue );
        ulNewCaps = M_GetSetParam_CapsValue( p_stValue);
        M_EvalNextParameter( p_stValue );
        lValue = M_GetSetParam_lValue(p_stValue) ;
 
        lValue = MSWay_fn_lChangeCapsForNextWayPointOfPath (h_MSWay, lIndex, ulNewCaps, lValue) ;
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue);
        return(p_stTree);
		break;
      }
    case eFunc_ReseauLitPoidsLiaisonAIndex :
      {
        /* Evaluation of parameters*/
        M_EvalNextParameter( p_stValue );
        lIndex = M_GetSetParam_lValue(p_stValue) ;
 
        lWeight = MSWay_fn_lGetWeightForNextWayPointOfPath (h_MSWay, lIndex) ;
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lWeight);
        return(p_stTree);
		break;
      }
    case eFunc_ReseauChangePoidsLiaisonAIndex :
      {
        /* Evaluation of parameters*/
        M_EvalNextParameter( p_stValue );
        lIndex = M_GetSetParam_lValue(p_stValue) ;
        M_EvalNextParameter( p_stValue );
        lWeight = M_GetSetParam_lValue(p_stValue) ;
 
        lValue = MSWay_fn_lChangeWeightForNextWayPointOfPath (h_MSWay, lIndex, lWeight) ;
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue);
        return(p_stTree);
		break;
      }
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
      /* To search for a WP in the way, and get its index (-1 if error)*/
    case eFunc_NetworkGetIndexOfWPInMSWay:
      {
        /* Evaluation of parameters*/
        WP_tdhWayPoint hWayPoint;
        M_EvalNextParameter( p_stValue );
        hWayPoint = M_GetSetParam_WayPointValue(p_stValue);
 
        lValue = MSWay_fn_lLookForWPInMSWay(h_MSWay, hWayPoint); /* might be -1 if not found*/
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue );
        return(p_stTree);
		break;
      }
 
      /* To force a WP to be the current WP in a way. Returns the index of the WP in the way(-1 if error)*/
    case eFunc_NetworkForceWPToCurrent:
      {
        long lIndex;
        /* Evaluation of parameters*/
        WP_tdhWayPoint hWayPoint;
        M_EvalNextParameter( p_stValue );
        hWayPoint = M_GetSetParam_WayPointValue(p_stValue) ;
 
        lIndex = MSWay_fn_lLookForWPInMSWay(h_MSWay, hWayPoint); /* might be -1 if not found*/
        if (lIndex != -1)
          lValue = MSWay_fn_lSetCurrentIndexInPath(h_MSWay, lIndex );
        else
          lValue = -1; /* not found !*/
 
        /* On informe le moteur sur le type et la valeur calculée.*/
        M_Full_GetSetParam_Integer(p_stValue, lValue );
        return(p_stTree);
		break;
      }
 
	default:
		break;
  }
 
  /* La fonction n'existe pas !!*/
  M_AIFatalError(E_uwAIFatalNotValidFunction);
 
  /* On informe le moteur sur l'avancement dans l'interprétation*/
  return(p_stTree);
}
 
 
 
 
tdstNodeInterpret *fn_p_stCloserWPInGraph(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_		         eFuncId = M_eFuncIdInterpret(p_stTree-1);
	long                       lValue, lIndex, lNbWPInGraph, lTypeOfWPToTest = 0, lTypeOfWP;
	WP_tdHandleOfGraph         hGraph;
	WP_tdhWayPoint		         hBestWP = (WP_tdhWayPoint)NULL;
	WP_tdhWayPoint		         hWayPoint = NULL, hWayPoint1 = NULL, hWayPoint2 = NULL;
	MTH_tdxReal			           xBestDist = MTH_C_MinusONE;
	MTH_tdxReal                xTmp;
	MTH3D_tdstVector	         stCurrentWPVector, stPosPerso, stTempVector;
	HIE_tdxHandleToSuperObject hCurrentSectorPerso;
 
	/********************************************************************************/
	/* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
	/********************************************************************************/
	HIE_tdxHandleToSuperObject hNewSuperObjPerso;
	fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewSuperObjPerso);
	/********************************************************************************/
 
	/* Evaluation of parameters*/
	/*ANNECY Bart 10/02/98 {*/
	M_EvalNextParameter(p_stValue);
#if defined(__DEBUG_AI__)
	M_VerifyTypeOfParamAction(p_stValue, E_vt_Graph);
#endif /* __DEBUG_AI__*/
	hGraph = M_GetSetParam_GraphValue(p_stValue) ;
 
	M_EvalNextParameter( p_stValue );
	lValue = M_GetSetParam_lValue(p_stValue) ;
 
	/*ENDANNECY Bart }*/
 
	switch(eFuncId)
	{
	case eFunc_NetworkCloserWPOfType:
		M_EvalNextParameter( p_stValue );
		lTypeOfWPToTest = (long)M_GetSetParam_CapsValue(p_stValue);

#if defined(__DEBUG_AI__)
		fn_vSetDontCheckNULLFlag(1); /* BART : we allow to have WayPoints to NoWhere !*/
#endif /*__DEBUG_AI__ */

		M_EvalNextParameter( p_stValue );
		hWayPoint1 = M_GetSetParam_WayPointValue(p_stValue) ;
		M_EvalNextParameter( p_stValue );
		hWayPoint2 = M_GetSetParam_WayPointValue(p_stValue) ;

#if defined(__DEBUG_AI__)
		fn_vSetDontCheckNULLFlag(-1);
#endif /* __DEBUG_AI__ */
 
		/* then as in Func_ReseauWPLePlusProche :*/
	case eFunc_ReseauWPLePlusProche:
		{
 
			if (hGraph == NULL)
			{
				M_Full_GetSetParam_WayPoint(p_stValue, (WP_tdhWayPoint)NULL); /* return NULL as WayPoint ! !*/
				return(p_stTree);
				break;
			}
 
			POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(hNewSuperObjPerso),&stPosPerso);
			/* sorti de la boucle car inutile de le refaire à chaque fois...*/
			hCurrentSectorPerso = fn_h_SectInfoGetCurrentSector(M_GetMSHandle(hNewSuperObjPerso, SectInfo));
 
			lNbWPInGraph = WPG_fn_lNumberOfWaypointOfGraph (hGraph) ;
 
			for ( lIndex = 0; lIndex < lNbWPInGraph; lIndex ++ )
			{
				hWayPoint = WPG_fn_hGetWaypointOfGraph(hGraph, lIndex, &lTypeOfWP); /* Bart*/
				if
					(
					(eFuncId != eFunc_NetworkCloserWPOfType)
					||
					(
					(hWayPoint != hWayPoint1)
					&& (hWayPoint != hWayPoint2)
					&& ((lTypeOfWPToTest & lTypeOfWP) == lTypeOfWPToTest)
					)
					)
				{
					/* dans le if() car inutile de le faire en dehors -> on peut gagner du temps*/
					WP_fnv_WayPoint_ComputeLocation( hWayPoint, &stCurrentWPVector);
					MTH3D_M_vSubVector(&stTempVector, &stCurrentWPVector, &stPosPerso);
					xTmp = MTH3D_M_xNormVector(&stTempVector);
 
					if
						(
						(MTH_M_bEqual(xBestDist, (MTH_tdxReal) -1))
						||
						(MTH_M_bLess(xTmp, xBestDist))
						)
					{
						if ( lValue )
						{
							/* chech way validity*/
							if
								(
								!HIE_bDetectIntersectSegmentWithSuperObject(
								&stPosPerso,
/*								&stCurrentWPVector,*/
								&stTempVector,
								hCurrentSectorPerso
								)
								)
							{
								xBestDist = MTH3D_M_xNormVector(&stTempVector);
								hBestWP = hWayPoint;
							}
						}
						else
						{
							xBestDist = MTH3D_M_xNormVector(&stTempVector);
							hBestWP = hWayPoint;
						}
					}
				}
			}
			M_Full_GetSetParam_WayPoint(p_stValue, hBestWP);
			return(p_stTree);
		}
		break;
 
		/* ANNECY CG CLOSER WAYPOINT WITH AXE 19/06/98 {*/
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
	case eFunc_ReseauWPLePlusDansLAxe2:
		M_EvalNextParameter( p_stValue );
		lTypeOfWPToTest = (long)M_GetSetParam_CapsValue(p_stValue);

#if defined(__DEBUG_AI__)
		fn_vSetDontCheckNULLFlag(1); /* BART : we allow to have WayPoints to NoWhere !*/
#endif /* __DEBUG_AI__ */


		M_EvalNextParameter( p_stValue );
		hWayPoint1 = M_GetSetParam_WayPointValue(p_stValue) ;
		M_EvalNextParameter( p_stValue );
		hWayPoint2 = M_GetSetParam_WayPointValue(p_stValue) ;

#if defined(__DEBUG_AI__)
		fn_vSetDontCheckNULLFlag(-1);
#endif /* __DEBUG_AI__ */

 
		/* then as in Func_ReseauWPLePlusDansLAxe :*/
	case eFunc_ReseauWPLePlusDansLAxe:
		{
 
		/*
		-->
		Axe
		Perso  ----------------->
		\                |
		\              |
		\            |                            -->   ------->
		\          | distance Axe/Waypoint = // Axe x PersoWP //
		\        |                         -----------------
		\      |                               -->
		\    |                            // Axe //
		\  |
		\|
		Waypoint
            */
 
			MTH3D_tdstVector stAxisVector,
				stPersoWaypointVector;
			/*stTmpVector;*/
			tdstGetSetParam  stParam;
 
			/* Get the axis vector*/
			M_EvalNextParameter(&stParam);
			stAxisVector = M_GetSetParam_stVectorValue(&stParam);
 
			if (hGraph == NULL)
			{
				M_Full_GetSetParam_WayPoint(p_stValue, (WP_tdhWayPoint)NULL); /* return NULL as WayPoint ! !*/
				return(p_stTree);
				break;
			}
 
			/* Get the position of the perso*/
			POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(hNewSuperObjPerso),&stPosPerso);
 
			/* Get the current sector of the perso*/
			hCurrentSectorPerso = fn_h_SectInfoGetCurrentSector(M_GetMSHandle(hNewSuperObjPerso, SectInfo));
 
			lNbWPInGraph = WPG_fn_lNumberOfWaypointOfGraph (hGraph) ;
			hBestWP	   = NULL;
 
			for ( lIndex = 0; lIndex < lNbWPInGraph; lIndex ++ )
			{
				hWayPoint = WPG_fn_hGetWaypointOfGraph(hGraph, lIndex, &lTypeOfWP);
 
				if (
					(eFuncId != eFunc_ReseauWPLePlusDansLAxe2) ||
					( (hWayPoint != hWayPoint1)	&& (hWayPoint != hWayPoint2) &&
					((lTypeOfWPToTest & lTypeOfWP) == lTypeOfWPToTest) )
					)
				{
 
 
					/* Compute Position of the Waypoint*/
					WP_fnv_WayPoint_ComputeLocation( hWayPoint, &stCurrentWPVector);
 
					/* Compute Vector PersoWaypoint*/
					MTH3D_M_vSubVector( &stPersoWaypointVector, &stCurrentWPVector, &stPosPerso );
 
 
					/*
					Compute       -->   ------->
					// Axe x PersoWP //
					-------------------
					-->
					// Axe //
					*/
 
 
					/*MTH3D_M_vCrossProductVector( &stTmpVector, &stAxisVector, &stPersoWaypointVector );*/
					/*xTmp = MTH3D_M_xNormVector(&stTmpVector)/MTH3D_M_xNormVector(&stAxisVector);*/
 
					/* in fact, it is better to test the cosinus :*/
					xTmp = MTH3D_M_xDotProductVector(&stAxisVector, &stPersoWaypointVector )/MTH3D_M_xNormVector(&stPersoWaypointVector );
 
 
					/*if ( (MTH_M_bEqual(xBestDist, (MTH_tdxReal) -1)) || (MTH_M_bLess(xTmp, xBestDist)) )*/
					if ( (MTH_M_bEqual(xBestDist, (MTH_tdxReal) -1)) || (MTH_M_bGreater(xTmp, xBestDist)) )
					{
						if (lValue)
						{
							/* chech way validity*/
							if (
								!HIE_bDetectIntersectSegmentWithSuperObject( &stPosPerso,
/*								&stCurrentWPVector,*/
								&stPersoWaypointVector,
								hCurrentSectorPerso )
								)
							{
								xBestDist = xTmp;
								hBestWP   = hWayPoint;
							}
						}
						else
						{
							xBestDist = xTmp;
							hBestWP   = hWayPoint;
						}
					}
				}
			}
 
 
			M_Full_GetSetParam_WayPoint(p_stValue, hBestWP);
			return(p_stTree);
		}
		break;
		/* } ENDANNECY CG CLOSERWAYPOINT WITH AXE 19/06/98*/
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
	default:
		break;
  }
 
  /* La fonction n'existe pas !!*/
  M_AIFatalError(E_uwAIFatalNotValidFunction);
 
  /* On informe le moteur sur l'avancement dans l'interprétation*/
  return(p_stTree);
}
 
tdstNodeInterpret *fn_p_stTravelOnAGraph(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_		         eFuncId = M_eFuncIdInterpret(p_stTree-1);
	long                       lIndex, lTypeOfWP;
	unsigned long ulCapaToTest;
	WP_tdHandleOfGraph         hGraph;
	WP_tdhWayPoint		         hWayPoint, hWayPoint2;
	WP_tdhGraphNode				hCurrentNode; /* the node currently examine*/
	WP_tdHandleOfListOfArc		hListOfArc = NULL;
	long lValue = 0;
 
	/* Evaluation of parameters*/
	M_EvalNextParameter(p_stValue);
#if defined(__DEBUG_AI__)
	M_VerifyTypeOfParamAction(p_stValue, E_vt_Graph);
#endif /* __DEBUG_AI__*/
	hGraph = M_GetSetParam_GraphValue(p_stValue) ;
 
	lTypeOfWP = 0L;
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
	if ( (eFuncId == eFunc_NetworkAffectTypeOfConnectedWP) || (eFuncId == eFunc_NetworkAffectTypeOfConnectedWPWithCapa) ) {
		/*get the TypeOfWP to affect to the WP*/
		M_EvalNextParameter( p_stValue );
		lTypeOfWP = (long)M_GetSetParam_CapsValue(p_stValue);
	}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
	/*get the waypoint from which we want to search*/
	M_EvalNextParameter( p_stValue );
	hWayPoint = M_GetSetParam_WayPointValue(p_stValue) ;
 
	ulCapaToTest = (unsigned long)0;
//#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
	if(
			(eFuncId == eFunc_NetworkNextWPWithCapa) 
//XB
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
			||
			(eFuncId == eFunc_NetworkAffectTypeOfConnectedWPWithCapa)  
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
//End XB
		)
	{
		/*get the capability to match*/
		M_EvalNextParameter( p_stValue );
		ulCapaToTest = (unsigned long)M_GetSetParam_CapsValue(p_stValue);
	}
//#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
	if ( (eFuncId == eFunc_NetworkAffectTypeOfConnectedWP) || (eFuncId == eFunc_NetworkAffectTypeOfConnectedWPWithCapa) ) {
		M_EvalNextParameter(p_stValue);
#if defined(__DEBUG_AI__)
		M_VerifyTypeOfParamAction(p_stValue, E_vt_Integer);
#endif /* __DEBUG_AI__*/
		lValue = (unsigned char) M_GetSetParam_lValue(p_stValue);
	}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
	/* now scan the list of connections from the current waypoint*/
	lIndex = -1; /* juste pour faire plaisir à YLG !*/
	hWayPoint2 = (WP_tdhWayPoint)NULL;
 
	/* looking for the starting WP :*/
	LST2_M_DynamicForEachElementOf(&hGraph->m_hListOfNode, hCurrentNode, lIndex) {
		if ( hCurrentNode->m_hWayPoint == hWayPoint ) {
			hWayPoint2 = hWayPoint;
			break ;
		}
	}
 
	/* we found the waypoint in the graph -> get its connections*/
	if ( hWayPoint2 ) {
		hListOfArc = WPG_fn_hGetArcList(hCurrentNode);
	}
 
	switch(eFuncId)
	{
	case eFunc_NetworkNextWPWithCapa: /* find next waypoint from the specified one that we can get from the current one*/
		{
			hWayPoint2 = (WP_tdhWayPoint) NULL; /*re-nullify because Nowhere is the default return value*/
			if ( hListOfArc ) {
				/*scan each arc of the node to see if its capability matches ours*/
				long lBestWeight = (long) ( ((unsigned long) (1 << 31)) - 1 ); /* max possible Weight*/
				WP_tdHandleOfArc hElement;
				LST2_M_DynamicForEachElementOf(&hListOfArc->m_hArc, hElement, lIndex) { /* if already exists !*/
 
					hWayPoint = hElement->m_hNode->m_hWayPoint;
					/* if the capabilities match and the arc has a higher weight, proceed*/
					if ( (hElement->m_ulCapability & ulCapaToTest) && (hElement->m_lWeight < lBestWeight) ) {
						lBestWeight = hElement->m_lWeight;
						hWayPoint2 = hWayPoint;
					}
				}
			}
			M_Full_GetSetParam_WayPoint(p_stValue, hWayPoint2); /* return NULL as WayPoint ! !*/
		}
		break;
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
	case eFunc_NetworkAffectTypeOfConnectedWP:
	case eFunc_NetworkAffectTypeOfConnectedWPWithCapa:
		{
			long lNbOfConnectedWP = 0;
 
			/* first, erase this type in the types Field of all the nodes of the graph*/
			if (lValue == 2)
			{
				LST2_M_DynamicForEachElementOf(&hGraph->m_hListOfNode, hCurrentNode, lIndex) {
					hCurrentNode->m_lTypeOfWP &= ~lTypeOfWP;
				}
			}
			if (lValue == 3)
			{
				LST2_M_DynamicForEachElementOf(&hGraph->m_hListOfNode, hCurrentNode, lIndex) {
					hCurrentNode->m_lTypeOfWP = 0;
				}
			}
 
			if ( hListOfArc ) {
				/*scan each arc of the node to see if its capability matches ours*/
				WP_tdHandleOfArc hElement;
				LST2_M_DynamicForEachElementOf(&hListOfArc->m_hArc, hElement, lIndex) { /* if already exists !*/
 
					if ( (eFuncId != eFunc_NetworkAffectTypeOfConnectedWPWithCapa)
						|| (hElement->m_ulCapability & ulCapaToTest) ) {
						lNbOfConnectedWP++;
						/*hElement->m_hNode->m_lTypeOfWP |= lTypeOfWP;*/
						switch (lValue)
						{
						case 0:
						case 2:
							hElement->m_hNode->m_lTypeOfWP |= lTypeOfWP; /* add the type*/
							break;
						case 1:
						case 3:
							hElement->m_hNode->m_lTypeOfWP = lTypeOfWP; /* change all the types field*/
							break;
						case 4:
							hElement->m_hNode->m_lTypeOfWP &= ~lTypeOfWP;; /* sub the type*/
							break;
						case 5:
							hElement->m_hNode->m_lTypeOfWP = 0; /* erase all the types field*/
							break;
						}
 
					}
				}
			}
			M_Full_GetSetParam_Integer(p_stValue, lNbOfConnectedWP ); /* 0 if no connected WP*/
 
		}
		break;
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
	default:
		/* La fonction n'existe pas !!*/
		M_AIFatalError(E_uwAIFatalNotValidFunction);
		break;
	}
 
	/* On informe le moteur sur l'avancement dans l'interprétation*/
	return(p_stTree);
}
 
 
tdstNodeInterpret *fn_p_stMiscFuncOnTypeOfWP(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	long                       lTypeOfWP, lIndex;
	WP_tdHandleOfGraph         hGraph;
	WP_tdhWayPoint		         hWayPoint;
	WP_tdhGraphNode            hCurrentNode, hTheNode; /* the node currently examine*/
 
	/* Evaluation of parameters*/
	M_EvalNextParameter(p_stValue);
 #if defined(__DEBUG_AI__)
  M_VerifyTypeOfParamAction(p_stValue, E_vt_Graph);
 #endif /* __DEBUG_AI__*/
  hGraph = M_GetSetParam_GraphValue(p_stValue) ;
 
	/*get the waypoint to search*/
	M_EvalNextParameter( p_stValue );
	hWayPoint = M_GetSetParam_WayPointValue(p_stValue) ;
 
	/* now scan the list of connections from the current waypoint*/
	lIndex = -1; /* juste pour faire plaisir à YLG !*/
	hTheNode = (WP_tdhGraphNode)NULL;
 
	/* looking for the starting WP :*/
	LST2_M_DynamicForEachElementOf(&hGraph->m_hListOfNode, hCurrentNode, lIndex) {
		if ( hCurrentNode->m_hWayPoint == hWayPoint ) {
      hTheNode = hCurrentNode;
			break ;
		}
	}
 
  lTypeOfWP = 0L;
 
	/* we found the waypoint in the graph -> get its type*/
	if ( hTheNode )
		lTypeOfWP = hTheNode->m_lTypeOfWP;
 
  M_Full_GetSetParam_Caps(p_stValue, lTypeOfWP);
 
  /* On informe le moteur sur l'avancement dans l'interprétation*/
	return(p_stTree);
}
 
/*ENDANNECY JMD & BART  }*/
 
/**********************************************************************
* Function: RESEAU_ExtremiteDeRail                                    *
* Use	  : CONSTANT = RESEAU_ExtremiteDeRail(Dist)			          *
* Return :															  *
*					-1 -> No Rail									  *
*					0 -> Is not	on the first or the last wp			  *
*					1 -> is on the first Wp							  *
*                   2 -> Is on the last Wp                            *
* Author  : Yann Le Guyader                                           *
* Date of last modification: 26/11/97                                 *
**********************************************************************/
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
tdstNodeInterpret *fn_p_stGetSituationOnRail(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_				eFuncId=M_eFuncIdInterpret(p_stTree-1);
	HIE_tdxHandleToSuperObject	hNewPerso;
    tdstGetSetParam				stParam;
	MTH_tdxReal					xDist;
	MS_tdxHandleToMSWay			h_MSWay;
	long						lCurrentIndex;
	long						lNbWp;
	WP_tdhWayPoint				hWayPoint;
	long						lValue=0;
	MTH3D_tdstVector			stWpPosition;
	MTH3D_tdstVector			stPersoPosition;
 
 
	/********************************************************************************/
	/* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
	/********************************************************************************/
	fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewPerso);
	/********************************************************************************/
 
	M_EvalNextParameter(&stParam);
	xDist = M_GetSetParam_xValue(&stParam);
 
	h_MSWay = M_GetMSHandle(hNewPerso, MSWay);
	if ( h_MSWay == NULL)
	{
		M_Full_GetSetParam_Integer(p_stValue, -1 );
	    return (p_stTree);
	}
 
	/* Number of Wp */
	lNbWp = MSWay_fn_lGetNumberWayPointInPath(h_MSWay);
 
	/* Get the current Wp */
	lCurrentIndex = MSWay_fn_lGetCurrentIndexInPath(h_MSWay);
 
	if (lCurrentIndex == 1)
	{
		lValue = 1;
		/*Test if perso is on the first Wp*/
		hWayPoint = MSWay_fn_hGetWayPointOfPath (h_MSWay,0);
	}
	else
	{
		if (lCurrentIndex == (lNbWp -1))
		{
			lValue = 2;
			/*Test if perso is on the first Wp*/
			hWayPoint = MSWay_fn_hGetWayPointOfPath (h_MSWay,lCurrentIndex);
		}
		else
		{
			M_Full_GetSetParam_Integer(p_stValue, 0 );
		    return (p_stTree);
		}
 
	}
 
	if (MTH_M_bEqualZero(xDist))
		xDist = WP_fnx_WayPoint_GetRadius(hWayPoint);
 
	/*
	 * Get perso position
	 */
 	POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectMatrix(hNewPerso), &stPersoPosition);
 
 
	/* Position of the Wp */
	WP_fnv_WayPoint_GetVertex(hWayPoint, &stWpPosition);
 
	if (
		(!MTH3D_M_bEqualVector(&stWpPosition, &stPersoPosition))
		&&
		MTH_M_bLess(MTH3D_M_xVectorGap(&stWpPosition, &stPersoPosition), xDist)
	   )
	{
		M_Full_GetSetParam_Integer(p_stValue, lValue);
	}
	else
	{
		M_Full_GetSetParam_Integer(p_stValue, 0 );
	}
 
	return(p_stTree);
}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
 
/* Capability functions*/
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
tdstNodeInterpret *fn_p_stPersoCapabilityFunction(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
  unsigned long ubf32Capabilities = 0;
 
  struct tdstEngineObject_ * hEngineObj; /* there's no "tdhEngineObject" ? ? ? ? ? ? ! ! !*/
 
  /********************************************************************************/
	/* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
	/********************************************************************************/
  HIE_tdxHandleToSuperObject hNewSuperObjPerso;
	fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewSuperObjPerso);
	/********************************************************************************/
  hEngineObj = M_GetEngineObject(hNewSuperObjPerso);
 
 #if defined(__DEBUG_AI__) || (defined(U64) && defined(D_CHECK_AI_FPCO))
  if (eFuncId != eFunc_GetCapabilities) {
    M_AIFatalError(E_uwAIFatalNotValidFunction);
    return(p_stTree);
  }
 #endif
 
  ubf32Capabilities = fn_ulGetCapabilities(hEngineObj);
 
  M_Full_GetSetParam_Caps(p_stValue, ubf32Capabilities);
 
	return(p_stTree);
}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT 08/06/99 { */
tdstNodeInterpret *fn_p_stCapabilityFunction(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
  unsigned char ucBitNumber;
  unsigned long ubf32Capabilities;
 
  ubf32Capabilities = 0;
 
  M_EvalNextParameter( p_stValue );
  ucBitNumber = (unsigned char) M_GetSetParam_lValue(p_stValue);
  if (ucBitNumber >= 32)
  {
    ubf32Capabilities = 0;
  }
 
  ubf32Capabilities = 1<<ucBitNumber;
 
 
  M_Full_GetSetParam_Caps(p_stValue, ubf32Capabilities);
 
	return(p_stTree);
}
#endif /* _AI_EXCLUDE_NEVER_USED_ } */
 
 
/*ANNECY CT 02/02/98{*/
/**********************************************************************
* Function: MAT_ScrollingVitesse                                      *
* Use	  : Vecteur = MAT_ScrollingVitesse(GMT,SurfaceType)           *
*				Surface Type Value :								  *
*					0 -> Ground										  *
*					1 -> Wall										  *
*					2 -> Ceiling									  *
*                                                                     *
* Author  : Carlos Torres                                             *
* Date of last modification: 24/11/97                                 *
**********************************************************************/
tdstNodeInterpret *fn_p_stGetScrollSpeed(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
    tdstGetSetParam stParam		;		/* Structure d'échange*/
 
	if (eFuncId==eFunc_GetScrollSpeed)
	{
		MTH3D_tdstVector stVector;		/* Reaction Vector*/
		unsigned long ulObstacleType;	/* first param : collided obstacle type*/
 
		/* get the type of obstacle (ground, wall or ceiling)*/
		M_EvalNextParameter(&stParam);
		ulObstacleType = M_GetSetParam_ulValue(&stParam);
		/*switch(M_GetSetParam_ucValue(&stParam)) {
		case 0 : ulObstacleType=C_WOT_ulGround;
			break;
		case 1 : ulObstacleType=C_WOT_ulWall;
			break;
		case 2 : ulObstacleType=C_WOT_ulCeiling;
			break;
		default : ulObstacleType=C_WOT_ulGround;
		}*/
		fn_vGetScrollSpeedMatCollided(p_SuperObjPerso,&stVector,ulObstacleType);
 
		/* return the Reaction vector*/
		M_Full_GetSetParam_p_stVertex(p_stValue,&stVector);
		return (p_stTree);
	}
 
	M_AIFatalError(E_uwAIFatalNotValidFunction);
	return(p_stTree);
}
/*ENDANNECY CT}*/
 
/*ANNECY CT 17/02/98{*/
/**********************************************************************
* Function: ANI_LitNbFrame                                            *
* Use	  : Integer = Perso.ANI_LitNbFrame()                          *
*                                                                     *
* Author  : Carlos Torres                                             *
* Date of last modification: 17/02/98                                 *
**********************************************************************/
tdstNodeInterpret *fn_p_stGetNbFrame(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
 
	/********************************************************************************/
	/* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
	/********************************************************************************/
	HIE_tdxHandleToSuperObject hNewSuperObjPerso;
	fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewSuperObjPerso);
	/********************************************************************************/
 
	switch(eFuncId)
	{
		case eFunc_GetNbFrame:
			{
				M_Full_GetSetParam_Integer(p_stValue,PLA_fn_uwGetNbFrameInCurrAnim(hNewSuperObjPerso));
				return (p_stTree);
			}
			return p_stTree;
			break;

		/*case eFunc_GetCurrentFrame:
			{
				M_Full_GetSetParam_Integer(p_stValue,PLA_fn_uwGetCurrFrameOfAnim(hNewSuperObjPerso));
				return (p_stTree);
			}
			return (p_stTree);
			break;*/

		default:
			break;
	}
 
	M_AIFatalError(E_uwAIFatalNotValidFunction);
	return(p_stTree);
}

/*ENDANNECY CT}*/
 
/*ANNECY CT 18/02/98{*/
/**********************************************************************
* Function: VEC_ProduitVectoriel                                      *
*           VEC_Normer                                                *
* Use	  : Vector = VEC_ProduitVectoriel(Vector,Vector)              *
*           Vector = VEC_Normer(Vector)                               *
*                                                                     *
* Author  : Carlos Torres                                             *
* Date of last modification: 18/02/98                                 *
**********************************************************************/
tdstNodeInterpret *fn_p_stVectorOperations(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId = M_eFuncIdInterpret(p_stTree-1);
	MTH3D_tdstVector *p_stV = &M_GetSetParam_stVertexValue(p_stValue);			/* Param Vector*/
 
	/* get the first vector*/
	M_EvalNextParameter(p_stValue);
	/*stV1=M_GetSetParam_stVectorValue(&stParam);*/
 
	switch ( eFuncId )
	{
	/* CROSS PRODUCT*/
	case eFunc_CrossProduct:
		{
			MTH3D_tdstVector stV1 = *p_stV, stV2;
 
			/* get the second vector*/
			M_EvalNextParameter(p_stValue);
			stV2 = M_GetSetParam_stVectorValue(p_stValue);
 
			MTH3D_M_vCrossProductVectorWithoutBuffer(p_stV,&stV1,&stV2);
 
			/* return cross product*/
			/*M_Full_GetSetParam_p_stVertex(p_stValue,&stV1xV2);*/
		}
		return p_stTree;
		break;
 
	/* NORMALIZE*/
	case eFunc_Normalize:
        if ( !(	MTH_M_bEqualWithEpsilon ( MTH3D_M_xGetXofVector(p_stV), MTH_C_ZERO, MTH_M_xDoubleToReal(1e-9) )
				&&	MTH_M_bEqualWithEpsilon ( MTH3D_M_xGetYofVector(p_stV), MTH_C_ZERO, MTH_M_xDoubleToReal(1e-9) )
				&&	MTH_M_bEqualWithEpsilon ( MTH3D_M_xGetZofVector(p_stV), MTH_C_ZERO, MTH_M_xDoubleToReal(1e-9) )
			  )
		   ) /*AR9902 Avoid too small values for N64*/
        {
            /*SAF_M_AssertWithMsg((! MTH3D_M_bIsNullVector(&stV1)),"Normalisation d'un vecteur nul")*/
            MTH3D_M_vNormalizeVector(p_stV, p_stV);
 
            /* return cross product*/
            /*M_Full_GetSetParam_p_stVertex(p_stValue,&stVNorm);*/
        }
		return (p_stTree);
		break;
 
	default:
		break;
	}
 
	M_AIFatalError(E_uwAIFatalNotValidFunction);
	return p_stTree;
}
/*ENDANNECY CT}*/
 
/*ANNECY CT 26/02/98{*/
/**********************************************************************
* Function: SPO_LitCoordonnees                                        *
* Use	  : Vector = SPO_LitCoordonnees(SPO)                          *
*                                                                     *
* Author  : Carlos Torres                                             *
* Date of last modification: 26/02/98                                 *
**********************************************************************/
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
tdstNodeInterpret *fn_p_stGetSPOCoordinates(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
    tdstGetSetParam stParam		;		/* Structure d'échange*/
	HIE_tdxHandleToSuperObject hSpo;
 
	/* get the first vector*/
	M_EvalNextParameter(&stParam);
	hSpo=M_GetSetParam_SuperObjectValue(&stParam);
 
	if (eFuncId == eFunc_GetSPOCoordinates) {
		MTH3D_tdstVector stCoordinates;
 
		if (HIE_fn_bIsSuperObjectValid(hSpo))
			POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectMatrix(hSpo),&stCoordinates);
		else
			MTH3D_M_vNullVector(&stCoordinates);
 
		/* return Position*/
		M_Full_GetSetParam_p_stVertex(p_stValue,&stCoordinates);
 
		return (p_stTree);
	}
 
	M_AIFatalError(E_uwAIFatalNotValidFunction);
	return(p_stTree);
}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
/*ENDANNECY CT}*/
 
/*ANNECY CT 02/03/98{*/
/**********************************************************************
* Function: ACT_LitNbPersoActifs                                      *
* Use	  : Entier = ACT_LitNbPersoActifs()                           *
*                                                                     *
* Author  : Carlos Torres                                             *
* Date of last modification: 02/03/98                                 *
**********************************************************************/
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
tdstNodeInterpret *fn_p_stGetNbActivePerso(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
 
	if (eFuncId == eFunc_GetNbActivePerso) {
		/* return Nb Active Perso*/
		M_Full_GetSetParam_Integer(p_stValue,GAM_fn_lGetNbPersoActive());
 
		return (p_stTree);
	}
 
	M_AIFatalError(E_uwAIFatalNotValidFunction);
	return(p_stTree);
}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
/*ENDANNECY CT}*/
 
 
/*
----------------------------------------------------------------------------------------
  Description   : *fn_p_stTractionFactorFunction
----------------------------------------------------------------------------------------
  Author        : Fred 'Bart#02' Compagnon
  Date          : 11/03/98
----------------------------------------------------------------------------------------
*/
tdstNodeInterpret *fn_p_stTractionFactorFunction(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
  unsigned char ucTractionFactor = 0;
 
  struct tdstEngineObject_ * hEngineObj; /* there's no "tdhEngineObject" ? ? ? ? ? ? ! ! !*/
 
  /********************************************************************************/
	/* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
	/********************************************************************************/
  HIE_tdxHandleToSuperObject hNewSuperObjPerso;
	fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId),p_SuperObjPerso,&hNewSuperObjPerso);
	/********************************************************************************/
  hEngineObj = M_GetEngineObject(hNewSuperObjPerso);
 
  switch(eFuncId)
	{
	  case eFunc_GetTractionFactor :
      ucTractionFactor = fn_ucStandardGameGetTractionFactor(hEngineObj->h_StandardGame);
			break;
 
    default:
			#if defined(__DEBUG_AI__) || (defined(U64) && defined(D_CHECK_AI_FPCO))
			M_AIFatalError(E_uwAIFatalNotValidFunction);
			#endif
			break;
  }
 
  /*M_Full_GetSetParam_Integer(p_stValue, ucTractionFactor);*/
 
  M_GetSetParam_ucValue(p_stValue) = ucTractionFactor;
  M_GetSetParam_Type(p_stValue) = E_vt_0To255;
 
	return(p_stTree);
}
 
/**********************************************************************
* Function: ZON_LitCentreZDEType                                      *
* Use	  : Vecteur = ZON_LitCentreZDEType(Perso,CMT)                 *
* Function: ZON_LitCentreZDMType                                      *
* Use	  : Vecteur = ZON_LitCentreZDMType(Perso,CMT)                 *
* Function: ZON_LitCentreZDRType                                      *
* Use	  : Vecteur = ZON_LitCentreZDRType(Perso,CMT)                 *
* Function: ZON_LitCentreZDDType                                      *
* Use	  : Vecteur = ZON_LitCentreZDDType(Perso,CMT)                 *
*                                                                     *
* Author  : Carlos Torres 28/04/98                                    *
* Modif : 18/05/98 check if zone is active Carlos Torres
**********************************************************************/
/* Modif 21/08/98 : take care of hierarchy for Module ZDE - Carlos Torres*/
tdstNodeInterpret *fn_p_stGetZDxCenter(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
	HIE_tdxHandleToSuperObject hCharacter;
	GMT_tdxMask xMask;
	MTH3D_tdstVector *p_stCenter = &M_GetSetParam_stVertexValue(p_stValue);
	unsigned char ucZoneType;
	/* XB 05/05/99 */
	/* ACP_tdxBool bFoundOne = 0; */
	/* End XB */
 
	/* 1 - get the perso*/
	M_EvalNextParameter(p_stValue);
	hCharacter=M_GetSetParam_p_stSupObjValue(p_stValue);
	SAF_M_AssertWithMsg(hCharacter, "le perso spécifié est invalide!");
 
	/* 2 - get the CMT*/
	M_EvalNextParameter(p_stValue);
	xMask=(GMT_tdxMask) M_GetSetParam_xMaskValue(p_stValue);
 
	/* Set default return value*/
	MTH3D_M_vNullVector(p_stCenter);
 
	/* get type of zone*/
	switch(eFuncId)
	{
	case eFunc_GetCenterZDEType :
		ucZoneType = C_ucTypeZde;
		break;
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
	case eFunc_GetCenterZDMType :
		ucZoneType = C_ucTypeZdm;
		break;
 
	case eFunc_GetCenterZDRType :
		ucZoneType = C_ucTypeZdr;
		break;
 
	case eFunc_GetCenterZDDType :
		ucZoneType = C_ucTypeZdd;
		break;
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
	default :
		ucZoneType = 0xff; /*prevent a compilation warning*/
#if defined(__DEBUG_AI__) || (defined(U64) && defined(D_CHECK_AI_FPCO))
		M_AIFatalError(E_uwAIFatalNotValidFunction);
#endif
		break;
	}
 
	/* return center in perso coordinates*/
	M_GetSetParam_Type(p_stValue) = E_vt_Vector;
	fn_vInternGetZDxCenter(hCharacter, xMask, ucZoneType, FALSE, p_stCenter);
	/*M_Full_GetSetParam_p_stVertex(p_stValue,&stCenter);*/
	return(p_stTree);
}
 
 
/**********************************************************************
* Function: fn_hGetNearestActorInSectorWithAnyCustombit               *
* Author  : Yann Le Tensorer                                          *
* Date of last modification: 21/08/98                                 *
**********************************************************************/
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
 
/**********************************************************************
* Function: fn_hGetNearestActorInSectorWithAnyCustombit               *
* Author  : Yann Le Tensorer                                          *
* Date of last modification: 21/08/98                                 *
**********************************************************************/
 
HIE_tdxHandleToSuperObject fn_hGetNearestActorInSectorWithAnyCustombit(
  HIE_tdxHandleToSuperObject _hMe,				/*identify myself so that I cant be the closet actor to myself...*/
  HIE_tdxHandleToSuperObject _hSector,			/*sector to search*/
  unsigned long _ulFilterCustomBits				/*custombits to accept*/
)
{
	SECT_tdxHandleOfElementLstCharacter hCharacterElement;		/* current list of character*/
	HIE_tdxHandleToSuperObject			hCharacterSO=NULL;			/* current actor tested*/
	HIE_tdxHandleToSuperObject			hCloserSO=NULL;				/* current actor tested*/
	MTH_tdxReal							xBestDist= MTH_C_InfinitPlus;
	int									i;
	MTH_tdxReal							xTmp;
	MTH3D_tdstVector					stMyPosition,stActorsPosition;
 
	/* Get The Position of my character*/
	POS_fn_vGetTranslationVector( HIE_fn_hGetSuperObjectGlobalMatrix( _hMe), &stMyPosition );
 
	/* Find all characters in the current sector of the list*/
	SECT_M_ForEachCharListInSector(_hSector, hCharacterElement, i)
	{
		hCharacterSO = SECT_GetCharacterInList( hCharacterElement );
 
		if ( hCharacterSO != _hMe )
		{
 
			/* Do this only if any of the CustomBits is set*/
			if ( (fn_ulStandardGameGetCustomBits(M_GetMSHandle(hCharacterSO,StandardGame)) & _ulFilterCustomBits) != 0 )
			{
				/* Coordinates of the character*/
				POS_fn_vGetTranslationVector( HIE_fn_hGetSuperObjectGlobalMatrix( hCharacterSO ), &stActorsPosition );
				/* Square of Distance between My character and other one*/
				xTmp = MTH3D_M_xVectorGapSqr(&stActorsPosition, &stMyPosition);
				if ( MTH_M_bLess(xTmp, xBestDist) )
				{
					xBestDist = xTmp;
					hCloserSO = hCharacterSO;
				}
			}
		}
	}
  return hCloserSO;
}
 
tdstNodeInterpret *fn_p_stGetNearestActorInCurrentSector(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	tdstGetSetParam								stParam;
	HIE_tdxHandleToSuperObject					hCurrentSectorPerso,hCloserSO = NULL;
	unsigned long								ulCustomBitValue;
 
	enum tdeFuncId_ eFuncId=M_eFuncIdInterpret(p_stTree-1);
 
	/********************************************************************************/
	/* BEWARE THE ULTRA OPERATOR : Must be at the beginning and respect this syntax */
	/********************************************************************************/
	HIE_tdxHandleToSuperObject hNewSuperObjPerso;
	fn_vGetUltraOperatorPerso(fn_ucGetFunctionUltraOperator(eFuncId), p_SuperObjPerso, &hNewSuperObjPerso);
	/********************************************************************************/
 
	/* Evaluation of next parameter*/
	M_EvalNextParameter( &stParam );
 
	/* Get number the custom bit value*/
	ulCustomBitValue = M_ReturnParam_lValue(&stParam);
 
	/* Point to the current sector where the character is*/
	hCurrentSectorPerso = fn_h_SectInfoGetCurrentSector( M_GetMSHandle( hNewSuperObjPerso, SectInfo ) );
 
	hCloserSO = fn_hGetNearestActorInSectorWithAnyCustombit(
				hNewSuperObjPerso, /*identify myself so that I cant be the closet actor to myself...*/
				hCurrentSectorPerso, /*sector to search*/
				ulCustomBitValue /*custombits to accept*/
 			);
 
	/* give the engine the closest actor*/
	M_Full_GetSetParam_Perso(p_stValue, hCloserSO);
	return(p_stTree);
 
}
 
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
/**********************************************************************
* Function: fn_hGetNearestActorInSectorWithAnyCustombit               *
* Author  : Yann Le Tensorer                                          *
* Date of last modification: 26/08/98                                 *
**********************************************************************/
 
/* merci de ne pas mettre cette fonction avec d'autres dans un case, ça ralentit le code...*/
tdstNodeInterpret *fn_p_stDotProduct(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	/* XB 05/05/99 */
	/* enum tdeFuncId_		eFuncId=M_eFuncIdInterpret(p_stTree-1); */
	/* End XB */
	MTH3D_tdstVector	stV1, *p_stV2;			/* first and second vectors*/
	MTH_tdxReal			xReturnValue;		/* dot product*/
 
	p_stV2 = &M_GetSetParam_stVectorValue(p_stValue);
 
	/* get the first vector*/
	M_EvalNextParameter(p_stValue);
	stV1 = *p_stV2;
	/* get the second vector*/
	M_EvalNextParameter(p_stValue);
 
	xReturnValue = MTH3D_M_xDotProductVector (&stV1,p_stV2);
 
	/* return dot product*/
	M_Full_GetSetParam_Float(p_stValue, xReturnValue );
    return p_stTree;
}
 
 
/**********************************************************************
* Function: fn_p_stGetCPUCounter									  *
* Author  : Marc Trabucato                                            *
* Date of last modification: 24/10/98                                 *
**********************************************************************/
 
#if !defined(_AI_EXCLUDE_NEVER_USED_) /* MT {*/
tdstNodeInterpret *fn_p_stGetCPUCounter(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	/* XB 05/05/99 */
	/* enum tdeFuncId_		eFuncId=M_eFuncIdInterpret(p_stTree-1); */
	/* End XB */
	unsigned long		ulValue;
 
	ulValue = TMR_fn_ulFastGetInternalCounter();
	/* return cross product*/
	M_Full_GetSetParam_Integer(p_stValue, ulValue);
    return(p_stTree);
}
#endif /* _AI_EXCLUDE_NEVER_USED_ }*/
 
tdstNodeInterpret *fn_GetCheatFlags(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	// Dummy for editor
	M_Full_GetSetParam_Integer(p_stValue, 0);

	return (p_stTree);	
}

tdstNodeInterpret *fn_GetBacklight(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	// Dummy for editor
	M_Full_GetSetParam_Integer(p_stValue, 0);

	return (p_stTree);	
}

extern unsigned char g_ucCalibrationDone;

tdstNodeInterpret *fn_DoneAnalogCalibration(HIE_tdxHandleToSuperObject p_SuperObjPerso, tdstNodeInterpret *p_stTree, tdstGetSetParam *p_stValue)
{
	// Dummy for editor
	M_Full_GetSetParam_Integer(p_stValue, 0);

	return (p_stTree);	
}
