/*##########################################################################################*/
/*## PlayAnim.cpp :																																				##*/
/*##																																											##*/
/*##													PLAYER d'ANIMATIONS 3D																			##*/
/*##												--------------------------																		##*/
/*## Version              1.0																															##*/
/*## Creation date        21/10/96			Sebastien DAVID			symbol : DVD (Gizmo)					##*/
/*## Revision date				04/11/96																												##*/
/*##																																											##*/
/*## That file needs to be compatible for all platforms.																	##*/
/*##																																											##*/
/*## (c) Ubi Studios 1996																																	##*/
/*##########################################################################################*/
 
/*                              ###########################                             */
/*             ##################### ---RUBRIQUES--- ######################             */
/*     ############################################################################     */
/* ######################## MANAGMENT of ANIMATIONS FRAMES      ####################### */
/* ######################## MANAGMENT of the SUPEROBJECTS HEAP  ####################### */
/* ######################## MANAGMENT of Anim's Datas           ####################### */
/* ######################## MANAGMENT of SUB-ANIMS              ####################### */
/* ######################## MANAGMENT of MATRIX CONTROL         ####################### */
/* ######################## MANAGMENT of STATES STATUS         #######################  */
/*     ############################################################################     */
/*             ############################################################             */
/*                              ###########################                             */
 
/* if speed is a discreet function :*/
/* character move only when frame change*/
/*#define DISCREET_SPEED*/
 
#define D_State_Define /* tmp 05/02/97*/
#define  D_ObjsTbls_Define
 
/*#define D_GIZMO_TEST		/* maj DVD (Gizmo)   */
#ifdef D_GIZMO_TEST
#endif /* D_GIZMO_TEST */
 
#include "TOOLSCPA.h"
#include "cpa_std.h"
 
#include "prf.h"
#include "Actions/AllActs.h"
/* ANNECY AV {*/
#include "Actions/3dData.h"
/* ENDANNECY AV }*/
 
#include "Structur/ErrGame.h"
#include "Structur/MemGame.h"
#include "STRUCTUR/Objects.h"
#include "STRUCTUR/Anim_s.h"
#include "Structur/StdObjSt.h"
#include "Structur/EngMode.h"
#include "Structur/State.h"
 
#include "Family.h"
#include "PlayAnim/PlayAnim.h"
#include "PlayAnim/PlayEvts.h"
#include "ZeMem.h"
#include "Physicol.h"
#include "PO.h"
#include "Structur/ObjsTbls.h"
#include "ia_dnm.h"
#include "ZdxStuff.h"
 
#include "ChanList.h"
#include "LipsSync.h"
#include "Basic.h"
/* Add on for father son links management*/
#include "GameEng.h"
 
#include "mor.h"
/* For interpolated animations*/
#include "PlayAnim/Interpol/specif/a3x_pref.h"
#include "PlayAnim/Interpol/a3x_intn.h"
#include "PlayAnim/Interpol/a3x_glob.h"
#include "PlayAnim/Interpol/a3x_mem.h"
#include "PlayAnim/Interpol/a3x_cach.h"
 
/* ******************* */
/* variables globales */
/* ******************* */
 
 
#if defined (ACTIVE_EDITOR) || defined (RETAIL)
#define ENGassert(param)
#else
 
#ifndef U64 
#define ENGassert(param) assert(param)
#else
#define ENGassert(param) { assert(param); if((param)==FALSE) ASM_BREAK; }
#endif /*U64*/
 
#endif
 
/* Oliv' - Portage v14 - remove warnings*/
/*#ifdef USE_PROFILER*/
/*static long lNbSO = 0;*/
/*static long lNbSOMax = 0;*/
/*#endif*/
/* EndOfOliv'*/
 
/*static char info[512];*/
/*static char *p_cName = "";*/
/*static char *p_cOldName = "";*/
 
RND_tdxHandleToRandomIndex g_Randomhandle;
 
/* for sub-animation object*/
/*tdstSubAnim3d *PLA_g_d_stSubAnimHeap;*/
/*unsigned short PLA_g_a_wStateOfSubAnimHeap[__PLA_NB_MAX_SUBANIM__];*/
/*unsigned long PLA_g_ulCurrentPosInSubAnimHeap; // position in PLA_g_a_ucStateOfSubAnimHeap*/
/*unsigned long PLA_g_ulMaxInSubAnimHeap; // Number of SupAnim allocated in PLA_g_a_ucStateOfSubAnimHeap*/
unsigned long PLA_g_ulMaxOccupationOfSupObjHeap;
unsigned long PLA_g_ulMaxOccupationOfChannels;
 
/* for hierarchic graphic object*/
HIE_tdxHandleToSuperObject PLA_fn_hFindNextFreeSupObj(void);
static HIE_tdxHandleToSuperObject PLA_g_d_stSupObjHeap;
 
#ifdef _DEBUG
static unsigned short PLA_g_a_wStateOfSupObjHeap[__PLA_LIM_SUPOBJ_ALLOC__];
#else
static unsigned short PLA_g_a_wStateOfSupObjHeap[__PLA_NB_MAX_SUPOBJ__];
#endif
static unsigned long PLA_g_ulCurrentPosInSupObjHeap; /* position in PLA_g_a_ucStateOfSupObjHeap*/
static unsigned long PLA_g_ulNbAllocInSupObjHeap; /* Number of SupObj allocated in PLA_g_a_ucStateOfSupObjHeap*/
 
/* for hierarchic graphic object*/
void PLA_fn_vCreateMatrixHeap(void);
/*POS_tdxHandleToPosition  PLA_fn_hFindNextFreeMatrix(void);*/
/*void PLA_fn_vReleaseMatrixInHeap(POS_tdxHandleToPosition _hMatrix);*/
void PLA_fn_vReleaseSuperObjectInHeap(HIE_tdxHandleToSuperObject _hSupObj);
static POS_tdxHandleToPosition  PLA_g_d_stMatrixHeap;
/*static unsigned short PLA_g_a_wStateOfMatrixHeap[__PLA_NB_MAX_MATRIX__];*/
/*static unsigned long PLA_g_ulCurrentPosInMatrixHeap; // position in PLA_g_a_ucStateOfMatrixHeap*/
/*static unsigned long PLA_g_ulMaxInMatrixHeap; // Number of Matrix allocated in PLA_g_a_ucStateOfMatrixHeap*/
/*unsigned long PLA_g_ulMaxOccupationOfMatrixHeap; // Max of PLA_g_ulMaxInMatrixHeap*/
BOOL g_bAnimConstantSpeed=FALSE;
 
 
 
/*----------------------------------------------------------------------------
--  Description : GAM_fn_ucGetMorphAmount
--  Get the morph amount into the array of morphing data of an animation
------------------------------------------------------------------------------
--  Methods : Nothing to say
------------------------------------------------------------------------------
--  Input :		_p_stAnim : Pointer to the morphed animation
--				_ulChannelNumber : Number of the channel
--				_uwFrameNumber : Number of the frame
--  Output :   the amount of morphing
------------------------------------------------------------------------------
--  Creation date : Mar 97		                Author: Alain Robin
------------------------------------------------------------------------------
--  Modifications :     
--  Modification date :                         Modification author : 
----------------------------------------------------------------------------*/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 04/06/99 */
unsigned char GAM_fn_ucGetMorphAmount(tdstAnim3d  *_p_stAnim, unsigned long _ulChannelNumber, unsigned short _uwFrameNumber) 
{
	/* Animation is a interpolated animation*/
	tdstA3dGENERAL	*p_stCurrentA3dGENERAL;
	long i;
 
#ifndef FORCE_REAL_TIME_LOAD
	if(g_bRealTimeAnimationLoad)
#endif
		p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL( p_uwLastA3dGENERAL[_p_stAnim->uwNumOfA3dGENERAL], _uwFrameNumber );
#ifndef FORCE_REAL_TIME_LOAD
	else
		p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL( _p_stAnim->uwNumOfA3dGENERAL, _uwFrameNumber );
#endif 
	_p_stAnim->d_stMorphDataArray=&p_stMorphData[p_stCurrentA3dGENERAL->uwNumOfFirstMorphData];
	for(i=0;i<p_stCurrentA3dGENERAL->uwNumberOfMorphData;++i)
		if((_p_stAnim->d_stMorphDataArray[i].uwChannelNumber==_ulChannelNumber)&&(_p_stAnim->d_stMorphDataArray[i].uwFrameNumber==_uwFrameNumber))
			return _p_stAnim->d_stMorphDataArray[i].ucMorphingAmount;
	return 0;
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 04/06/99 */

 
/*----------------------------------------------------------------------------
--  Description : GAM_fn_ucGetMorphTarget
--  Get the morph amount into the array of morphing data of an animation
------------------------------------------------------------------------------
--  Methods : Nothing to say
------------------------------------------------------------------------------
--  Input :		_p_stAnim : Pointer to the morphed animation
--				_ulChannelNumber : Number of the channel
--				_uwFrameNumber : Number of the frame
--  Output :   the target of morphing
------------------------------------------------------------------------------
--  Creation date : Mar 97		                Author: Alain Robin
------------------------------------------------------------------------------
--  Modifications :     
--  Modification date :                         Modification author : 
----------------------------------------------------------------------------*/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 04/06/99 */
unsigned char GAM_fn_ucGetMorphTarget(tdstAnim3d  *_p_stAnim, unsigned long _ulChannelNumber, unsigned short _uwFrameNumber) 
{
	/* Animation is a interpolated animation*/
	tdstA3dGENERAL	*p_stCurrentA3dGENERAL;
	long i;
 
#ifndef FORCE_REAL_TIME_LOAD
	if(g_bRealTimeAnimationLoad)
#endif
		p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL( p_uwLastA3dGENERAL[_p_stAnim->uwNumOfA3dGENERAL], _uwFrameNumber );
#ifndef FORCE_REAL_TIME_LOAD
	else
		p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL( _p_stAnim->uwNumOfA3dGENERAL, _uwFrameNumber );
#endif 
	_p_stAnim->d_stMorphDataArray=&p_stMorphData[p_stCurrentA3dGENERAL->uwNumOfFirstMorphData];
	for(i=0;i<p_stCurrentA3dGENERAL->uwNumberOfMorphData;++i)
		if((_p_stAnim->d_stMorphDataArray[i].uwChannelNumber==_ulChannelNumber)&&(_p_stAnim->d_stMorphDataArray[i].uwFrameNumber==_uwFrameNumber))
			return _p_stAnim->d_stMorphDataArray[i].ucTarget;
	return 0;
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 04/06/99 */
 
 
/*----------------------------------------------------------------------------
--  Description : GAM_fn_p_stGetMorphData
--  Get the morph data into the array of morphing data of an animation
------------------------------------------------------------------------------
--  Methods : Nothing to say
------------------------------------------------------------------------------
--  Input :		_p_stAnim : Pointer to the morphed animation
--				_ulChannelNumber : Number of the channel
--				_uwFrameNumber : Number of the frame
--  Output :   the target of morphing
------------------------------------------------------------------------------
--  Creation date : Jun 98		                Author: Alain Robin
------------------------------------------------------------------------------
--  Modifications :     
--  Modification date :                         Modification author : 
----------------------------------------------------------------------------*/
tdstMorphData* GAM_fn_p_stGetMorphData(tdstAnim3d  *_p_stAnim, unsigned long _ulChannelNumber, unsigned short _uwFrameNumber) 
{
	/* Animation is a interpolated animation*/
	tdstA3dGENERAL	*p_stCurrentA3dGENERAL;
	long i;
 
#ifndef FORCE_REAL_TIME_LOAD
	if(g_bRealTimeAnimationLoad)
#endif
		p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL( p_uwLastA3dGENERAL[_p_stAnim->uwNumOfA3dGENERAL], _uwFrameNumber );
#ifndef FORCE_REAL_TIME_LOAD
	else
		p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL( _p_stAnim->uwNumOfA3dGENERAL, _uwFrameNumber );
#endif 
	_p_stAnim->d_stMorphDataArray=&p_stMorphData[p_stCurrentA3dGENERAL->uwNumOfFirstMorphData];
	for(i=0;i<p_stCurrentA3dGENERAL->uwNumberOfMorphData;++i)
		if((_p_stAnim->d_stMorphDataArray[i].uwChannelNumber==_ulChannelNumber)&&(_p_stAnim->d_stMorphDataArray[i].uwFrameNumber==_uwFrameNumber))
			return &(_p_stAnim->d_stMorphDataArray[i]);
	return NULL;
}
 
/* **************************************************************************************/
/* *  Description : Stop all morphing task fot the current anim begin at the current frame*/
/* *                For the character give in argument*/
/* *===================================================================================**/
/* *  Input : SO of the character*/
/* *-----------------------------------------------------------------------------------**/
/* *  Creation date : 13/05/98          Author : Carlos Torres*/
/* **************************************************************************************/
void PLA_fn_vStopCurrentMorphAnim(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	tdstAnim3d  * p_stCurrentAnim=fn_h3dDataGetCurrentState(h_Current3dData)->p_stAnim;
#ifndef U64
	unsigned short uwCurrentFrame=fn_uw3dDataGetCurrentFrame(h_Current3dData);
#endif
	short i;
 
	/* if is a morphing anim and anim is display (array of element initilize)*/
	if (p_stCurrentAnim && p_stCurrentAnim->d_stMorphDataArray && fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d)
	{
//AR9904 Because on N64, we are sure that p_stArrayOfElts3d isn't NULL
#ifndef U64
		/* for all channel*/
		for (i=0;i < p_stCurrentAnim->ucMaxNumberOfElements;i++)
		{
			/* check if element was morphing*/
			if (GAM_fn_ucGetMorphAmount(p_stCurrentAnim,i,uwCurrentFrame)  <100 )
				MOR_fn_xStopMorph(p_stSuperObject,(fn_p_st3dDataGetCurrentFrame(h_Current3dData))->p_stArrayOfElts3d[i].ucChannelNumber);
		}
#else
		/* for all channel*/
		for (i=0;i<256;++i)
			MOR_fn_xStopMorph(p_stSuperObject,(ACP_tdxIndex)i);
#endif
	}
}
 
/*            ######################################################################## */
/*        ############################################################################ */
/*      ########################## MANAGMENT of ANIMATIONS FRAMES #################### */
/*     ############################################################################### */
/*     ############################################################################### */
/*     #########                                                                       */
/* #################                                                                   */
/*   #############                                                                     */
/*     #########                                                                       */
/*       #####                                                                         */
/*         #                                                                           */
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/* **************************************************************************************/
/* *  Description : overwrite super Object Matrix of active channel*/
/* *                and update matrix for UCC*/
/* *                (use when frame is skip to update control channel)*/
/* *===================================================================================**/
/* *-----------------------------------------------------------------------------------**/
/* *  Creation date : 20/04/98          Author : Carlos Torres*/
/* **************************************************************************************/
 
/* **************************************************************************************/
/* *  Description :   Do one frame of anim and subanims for one object                 **/
/* *===================================================================================**/
/* *-----------------------------------------------------------------------------------**/
/* *  Creation date : 27/07/97          Author : DVD (Gizmo)*/
/* *  Modif : 12/03/98	Morphing		Author : Alain Robin(Carlos Torres)*/
/* *  Modif : 22/04/98  Stop Morphing when element is no more morph - Carlos Torres*/
/* *  Modif : 15/05/98  Reset SO for non-graphic element - Carlos Torres*/
/* *  Modif : 20/05/98  Reset Link object for Event and Light - Carlos Torres*/
/* **************************************************************************************/
void PLA_fn_vDoFrame(tdstAnim3d  *p_stCurrentAnim, unsigned short uwCurrentFrame
					 ,HIE_tdxHandleToSuperObject p_stSuperObject)
{
/*	long i;*/
	struct tdstFrame3d_				*p_stCurrentFrame3d;
	register struct tdstElement3d_	*p_stElt3d;
	struct tdstElement3d_			*p_stElt3dStop;
	MS_tdxHandleTo3dData			h_Current3dData;
	HIE_tdxHandleToSuperObject		p_stTargetSO;
	tdstAChannel					*p_stChannel;
	struct tdstObjectsTableElement_ *d_stCurrentObjectsTable, *p_stCurrentObjectsTableElement;
	short							wElement;
/* Oliv' - Portage v14 - remove warnings*/
/*	BOOL							bTestActivation=FALSE;*/
/* EndOfOliv'*/
	float f_Transparence;
    PO_tdxHandleToPhysicalObject hPhysicalObject;
 
	h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
 
	f_Transparence = HIE_fn_fGetSuperObjectTransparenceLevel(p_stSuperObject);
	d_stCurrentObjectsTable = fn_h3dDataGetCurrentObjectsTable(h_Current3dData)->d_stObjectsTable;
 
	/* update frame*/
	p_stCurrentFrame3d = fn_p_st3dDataGetCurrentFrame(h_Current3dData);
	fn_vUpdateFrame(p_stSuperObject,p_stCurrentFrame3d,p_stCurrentAnim,uwCurrentFrame);
 
	p_stElt3d = p_stCurrentFrame3d->p_stArrayOfElts3d;
	p_stElt3dStop = p_stElt3d + p_stCurrentAnim->ucMaxNumberOfElements;
	/* For each Channel*/
	while (p_stElt3d != p_stElt3dStop)
	{
		if (p_stElt3d->ucChannelNumber == C_ucUnknownChannel )
		{
			p_stElt3d++;
	/*		ENGassert(0);*/
			continue; /* erreur*/
		}
 
		/* get the channel and its target SO*/
		p_stChannel = fn_hGetCSOForChannel(fn_h3dDataGetChannelSOList(h_Current3dData),p_stElt3d->ucChannelNumber);
		p_stTargetSO = p_stChannel->hSupObject;
 
#if defined(ANIM_DEBUG) && defined(U64)
		if(p_stTargetSO==NULL)
		{
			osSyncPrintf("Error : Target SO is null\n");
			osSyncPrintf("Anim : %d, Frame : %d, Channel : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,uwCurrentFrame,p_stElt3d->ucChannelNumber);
		}
#endif
#ifndef RETAIL
		ENGassert(p_stTargetSO);
#endif
 
		/* Graphic element in an active channel*/
		if (p_stElt3d->eTypeOfElement == TE_GraphicObject && p_stElt3d->bf1ActiveStatus)
		{
#ifdef D_USE_LIPSYNC
			/* get element checkin lip synchro*/
			wElement = fn_vGetLipsSynchObject(p_stSuperObject,p_stElt3d->ucChannelNumber);
			if ( wElement == -1000 )
				wElement = (short)p_stElt3d->wElement;
#else
			wElement = (short)p_stElt3d->wElement;
#endif /*D_USE_LIPSYNC*/
 
			p_stCurrentObjectsTableElement = d_stCurrentObjectsTable + wElement;
 
			/* Element Defined*/
			if ( p_stCurrentObjectsTableElement->wTypeOfTarget != C_wTdO_Undefined )
			{
				if ( p_stCurrentObjectsTableElement->p_stCustomZoom )
				{
					MTH3D_tdstVector stCustomZoomI,stCustomZoomJ,stCustomZoomK;
					MTH_tdxReal f0,f4,f8;
					HIE_tdxHandleToSuperObject p_stSO_Child;
					/* Element with Custom Zoom ++++++++++++++++++++++++++++++++++++++++*/
					/* check if the channel is adapted...*/
					if (p_stChannel->hZoomSupObject == NULL)
					{
						/* we must create the zoom hierarchy*/
						/* channel superobject has no asociated object*/
						/* zoom superobject has the physical object associated*/
						/* zoom superobject is child of channel superobject*/
 
						/* remove associated object from channel SO*/
						HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,NULL,HIE_C_ulSuperObject);
						/* create zoom superobject*/
/*						p_cName = p_stCurrentAnim->szAnimName;*/
						p_stSO_Child = PLA_fn_hFindNextFreeSupObj();
						/* zoom SO is son of channel SO*/
						HIE_fn_vSuperObjectAddTail(p_stTargetSO,p_stSO_Child);
						/* put a new matrix in zoom superobject*/
#if defined(ANIM_DEBUG) && defined(U64)
						if(p_stSO_Child->hLocalMatrix==NULL)
						{
							osSyncPrintf("Error : Local matrix is null\n");
							osSyncPrintf("Anim : %d, Frame : %d, Channel : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,uwCurrentFrame,p_stElt3d->ucChannelNumber);
						}
#endif
#ifndef RETAIL
						ENGassert(p_stSO_Child->hLocalMatrix != NULL);
#endif
						/*						HIE_fn_vSetSuperObjectMatrix(p_stSO_Child,PLA_fn_hFindNextFreeMatrix());*/
						p_stChannel->hZoomSupObject = p_stSO_Child;
					}
					else
					{
						/* ok, hierarchy is good, just signal it*/
						p_stSO_Child = p_stChannel->hZoomSupObject;
					}
 
					/* NOT a Morphing Anim ------------------------------------------*/
					if ( p_stCurrentAnim->d_stMorphDataArray == NULL )
					{
						/* Physical Object*/
						if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_PhysicalObject )
						{
							/* Look if there is a morphed object in the channel*/
							hPhysicalObject = fn_hGetMorphedObjectInChannel (fn_h3dDataGetMorphList (h_Current3dData),p_stElt3d->ucChannelNumber);
							/* If not, we take the object of the animation*/
							if ( !hPhysicalObject )
								hPhysicalObject = p_stCurrentObjectsTableElement->h_Target;
 
							/* put the object in the right superobject*/
							HIE_fn_vSetSuperObjectObjectAndType(p_stSO_Child,hPhysicalObject,HIE_C_ulPO);
						}
#ifndef U64	/* no mirror on U64*/
						/* Mirror*/
						else if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_Mirror )
							HIE_fn_vSetSuperObjectObjectAndType(p_stSO_Child,p_stCurrentObjectsTableElement->h_Target,HIE_C_ulPO_Mirror);
#endif
					}
					/* Morphing Anim ------------------------------------------------*/
					else
					{
						/* Physical Object*/
						if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_PhysicalObject )
						{
							ACP_tdxIndex xMorphTaskIndex;
							tdstMorphData* p_stMorphData;
 
							p_stMorphData=GAM_fn_p_stGetMorphData(p_stCurrentAnim,p_stElt3d->ucChannelNumber,uwCurrentFrame);
 
							/* element not morphed -- > Stop Morphing*/
							if (p_stMorphData == NULL )
							{
								MOR_fn_xStopMorph(p_stSuperObject,p_stElt3d->ucChannelNumber);
								HIE_fn_vSetSuperObjectObjectAndType(p_stSO_Child,p_stCurrentObjectsTableElement->h_Target,HIE_C_ulPO);
							}
							/* element morphed*/
							else
							{
								/* Morphing*/
								if ( p_stMorphData->ucMorphingAmount < 100 )
								{
									/* Create a new morph task*/
									xMorphTaskIndex = MOR_fn_xMorphing( p_stSuperObject, wElement,
										p_stMorphData->ucTarget,
										p_stMorphData->ucMorphingAmount, p_stElt3d->ucChannelNumber);
									if(xMorphTaskIndex!=-1)
									{
										MOR_fn_vDoMorph(xMorphTaskIndex);																			/* Execute morphing*/
										hPhysicalObject = MOR_fn_hGetMorphedObject (xMorphTaskIndex);												/* Get result*/
										HIE_fn_vSetSuperObjectObjectAndType ( p_stSO_Child, hPhysicalObject, HIE_C_ulPO );					/* Put the result into the hierarchy*/
									}
									else
									{
#if !defined(RETAIL) && defined(U64)
										osSyncPrintf("Problem in anim %d, frame %d, Channel %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,uwCurrentFrame,p_stElt3d->ucChannelNumber);
#endif
										HIE_fn_vSetSuperObjectObjectAndType(p_stSO_Child,d_stCurrentObjectsTable[wElement].h_Target,HIE_C_ulPO);
									}
								}
								/* Complete transformation*/
								else
								{
									MOR_fn_xStopMorph( p_stSuperObject, p_stElt3d->ucChannelNumber);
									/* target of the morphing*/
									hPhysicalObject = d_stCurrentObjectsTable[p_stMorphData->ucTarget].h_Target;
									HIE_fn_vSetSuperObjectObjectAndType ( p_stSO_Child, hPhysicalObject, HIE_C_ulPO );
								}
							}
						}
#ifndef U64	/* no mirror on U64*/
						else if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_Mirror )
							HIE_fn_vSetSuperObjectObjectAndType(p_stSO_Child,p_stCurrentObjectsTableElement->h_Target,HIE_C_ulPO_Mirror);
#endif
					}
 
					HIE_fn_vSetSuperObjectBoundingVolume(p_stSO_Child,NULL);
 
					/* build the zoom matrix*/
					POS_fn_vSetIdentityMatrix(HIE_fn_hGetSuperObjectMatrix(p_stSO_Child));
					MTH3D_M_vGetVectorElements(&f0,&f4,&f8,p_stCurrentObjectsTableElement->p_stCustomZoom);
					MTH3D_M_vSetVectorElements(&stCustomZoomI,f0,MTH_C_ZERO,MTH_C_ZERO);
					MTH3D_M_vSetVectorElements(&stCustomZoomJ,MTH_C_ZERO,f4,MTH_C_ZERO);
					MTH3D_M_vSetVectorElements(&stCustomZoomK,MTH_C_ZERO,MTH_C_ZERO,f8);
					POS_fn_vSetScaleMatrix(HIE_fn_hGetSuperObjectMatrix(p_stSO_Child),&stCustomZoomI, &stCustomZoomJ, &stCustomZoomK);
 
					/* Invert faces depending on the number of symmetry*/
					if( MTH_M_bLessZero(MTH_M_xMul(f0, MTH_M_xMul(f4, f8))) )
					{
						HIE_fn_vSetSuperObjectDrawMask(p_stSO_Child, HIE_fn_lGetSuperObjectDrawMask(p_stSO_Child)&(GLI_C_lAllIsEnable-(GLI_C_lNotInvertBackfaces)));
					}
 
					/* Module transparency isn't setting in IA*/
					if ((HIE_fn_SO_ulGetFlags(p_stSO_Child) & HIE_C_Flag_ModuleTransparency) !=  HIE_C_Flag_ModuleTransparency )
					{
						/* NO charcter transparency*/
						if ( (HIE_fn_lGetSuperObjectDrawMask(p_stSuperObject)&GLI_C_lIsNotGrided) == GLI_C_lIsNotGrided ) {
 
							/* no anim transparency for that module*/
							if (p_stElt3d->ucTransparency == 0xFF) {
								HIE_fn_vSetSuperObjectTransparenceLevel(p_stSO_Child,f_Transparence);
								HIE_fn_vSetSuperObjectDrawMask(p_stSO_Child, HIE_fn_lGetSuperObjectDrawMask(p_stSO_Child) | GLI_C_lIsNotGrided );
							}
							/* set anim transparency for the module*/
							else {
								HIE_fn_vSetSuperObjectTransparenceLevel(p_stSO_Child,(float)p_stElt3d->ucTransparency);
								HIE_fn_vSetSuperObjectDrawMask(p_stSO_Child, HIE_fn_lGetSuperObjectDrawMask(p_stSO_Child) & ~GLI_C_lIsNotGrided );
							}
						}
						/* set the charcter transparency to its modules*/
						else
							HIE_fn_vSetSuperObjectTransparenceLevel(p_stSO_Child,f_Transparence);
					}
				}
				/* NO Custom Zoom +++++++++++++++++++++++++++++++++++++++++++++++++++*/
				else
				{
					/* there is no custom zoom...*/
					/* let's see if the hierarchy is good*/
					if (p_stChannel->hZoomSupObject != NULL)
					{
						/* hierarchy not good, we have a zoom in there*/
						/* let's remove it !*/
						/* isolate zoom superobject*/
						LST2_M_DynamicIsolate(p_stChannel->hZoomSupObject);
						/* release its matrix*/
/*						PLA_fn_vReleaseMatrixInHeap(HIE_fn_hGetSuperObjectMatrix(p_stChannel->hZoomSupObject));*/
						/* release zoom superobject*/
						PLA_fn_vReleaseSuperObjectInHeap(p_stChannel->hZoomSupObject);
						p_stChannel->hZoomSupObject = NULL;
					}
					/* NOT a Morphing Anim ------------------------------------------*/
					if ( p_stCurrentAnim->d_stMorphDataArray == NULL )
					{
						/* Physical Object*/
						if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_PhysicalObject )
						{
							/* Look if there is a morphed object in the channel*/
							hPhysicalObject = fn_hGetMorphedObjectInChannel (fn_h3dDataGetMorphList (h_Current3dData),p_stElt3d->ucChannelNumber);
							/* If not, we take the object of the animation*/
							if ( !hPhysicalObject )
								hPhysicalObject = p_stCurrentObjectsTableElement->h_Target;
 
							HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,hPhysicalObject,HIE_C_ulPO);
						}
						/* Mirror*/
#ifndef U64	/* no mirror on U64*/
						else if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_Mirror )
							HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,p_stCurrentObjectsTableElement->h_Target,HIE_C_ulPO_Mirror);
#endif
					}
					/* Morphing Anim ------------------------------------------------*/
					else
					{
						/* Physical Object*/
						if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_PhysicalObject )
						{
							ACP_tdxIndex xMorphTaskIndex;
							tdstMorphData* p_stMorphData;
 
							p_stMorphData=GAM_fn_p_stGetMorphData(p_stCurrentAnim,p_stElt3d->ucChannelNumber,uwCurrentFrame);
 
							/* element not morphed -- > Stop Morphing*/
							if ( p_stMorphData==NULL ) 
							{
								MOR_fn_xStopMorph(p_stSuperObject,p_stElt3d->ucChannelNumber);
								HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,p_stCurrentObjectsTableElement->h_Target,HIE_C_ulPO);
							}
							/* element morphed*/
							else
							{
								/* Morphing*/
								if ( p_stMorphData->ucMorphingAmount < 100 )
								{
									/* Create a new morph task*/
									xMorphTaskIndex = MOR_fn_xMorphing( p_stSuperObject, wElement,
										p_stMorphData->ucTarget ,
										p_stMorphData->ucMorphingAmount, p_stElt3d->ucChannelNumber); /* Create a new morph task*/
									if(xMorphTaskIndex!=-1)
									{
										MOR_fn_vDoMorph(xMorphTaskIndex); /* Execute morphing*/
										hPhysicalObject = MOR_fn_hGetMorphedObject (xMorphTaskIndex); /* Get result*/
										HIE_fn_vSetSuperObjectObjectAndType ( p_stTargetSO, hPhysicalObject, HIE_C_ulPO ); /* Put the result into the hierarchy*/
									}
									else
									{
#if !defined(RETAIL) && defined(U64)
										osSyncPrintf("Problem in anim %d, frame %d, channel %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,uwCurrentFrame,p_stElt3d->ucChannelNumber);
#endif
										HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,d_stCurrentObjectsTable[wElement].h_Target,HIE_C_ulPO);
									}
								}
								/* Complete transformation*/
								else
								{
									MOR_fn_xStopMorph( p_stSuperObject, p_stElt3d->ucChannelNumber);
									/* target of the morphing*/
									hPhysicalObject = d_stCurrentObjectsTable [ p_stMorphData->ucTarget ] . h_Target; /* target of the morphing*/
									HIE_fn_vSetSuperObjectObjectAndType ( p_stTargetSO, hPhysicalObject, HIE_C_ulPO );
								}
							}
						}
#ifndef U64	/* no mirror on U64*/
						/* Mirror*/
						else if ( p_stCurrentObjectsTableElement->wTypeOfTarget == C_wTdO_Mirror ) /* AR980304 little optimisation...*/
							HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,p_stCurrentObjectsTableElement->h_Target,HIE_C_ulPO_Mirror);
#endif
					}
 
					HIE_fn_vSetSuperObjectBoundingVolume(p_stTargetSO,NULL);
				}
			}
			/* Undefined Element*/
			else
			{
#ifndef RETAIL
#ifdef U64
				osSyncPrintf("Undefined element in anim %d, Channel %d, Frame %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,uwCurrentFrame,p_stElt3d->ucChannelNumber);
#endif
				ENGassert(0);
#endif
				HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,NULL,HIE_C_ulSuperObject);
			}
		}
		/* END - Graphic element in an active channel*/
 
		/* Only 3DObject Active have a link object*/
		if ((p_stElt3d->eTypeOfElement == TE_EmptyObject) ||
			(p_stElt3d->eTypeOfElement == TE_Event) ||
			(p_stElt3d->eTypeOfElement == TE_Fake) || 
			!p_stElt3d->bf1ActiveStatus)
		{
			/* warning, it is possible that this channel has a zoom hierarchy...*/
			if (p_stChannel->hZoomSupObject)
			{
				/* there is one !*/
				/* let's remove it !*/
				/* isolate zoom superobject*/
				LST2_M_DynamicIsolate(p_stChannel->hZoomSupObject);
				/* release its matrix*/
/*				PLA_fn_vReleaseMatrixInHeap(HIE_fn_hGetSuperObjectMatrix(p_stChannel->hZoomSupObject));*/
				/* release zoom superobject*/
				PLA_fn_vReleaseSuperObjectInHeap(p_stChannel->hZoomSupObject);
				p_stChannel->hZoomSupObject = NULL;
			}
			HIE_fn_vSetSuperObjectObjectAndType(p_stTargetSO,NULL,HIE_C_ulSuperObject);
		}
 
 
		/* Module transparency isn't setting in IA*/
		if ((HIE_fn_SO_ulGetFlags(p_stTargetSO) & HIE_C_Flag_ModuleTransparency) !=  HIE_C_Flag_ModuleTransparency )
		{
			/* NO charcter transparency*/
			if ( (HIE_fn_lGetSuperObjectDrawMask(p_stSuperObject)&GLI_C_lIsNotGrided) == GLI_C_lIsNotGrided ) {
 
				/* no anim transparency for that module*/
				if (p_stElt3d->ucTransparency == 0xFF) {
					HIE_fn_vSetSuperObjectTransparenceLevel(p_stTargetSO,f_Transparence);
					HIE_fn_vSetSuperObjectDrawMask(p_stTargetSO, HIE_fn_lGetSuperObjectDrawMask(p_stTargetSO) | GLI_C_lIsNotGrided );
				}
				/* set anim transparency for the module*/
				else {
					HIE_fn_vSetSuperObjectTransparenceLevel(p_stTargetSO,(float)p_stElt3d->ucTransparency);
					HIE_fn_vSetSuperObjectDrawMask(p_stTargetSO, HIE_fn_lGetSuperObjectDrawMask(p_stTargetSO) & ~GLI_C_lIsNotGrided );
				}
			}
			/* set the charcter transparency to its modules*/
			else
				HIE_fn_vSetSuperObjectTransparenceLevel(p_stTargetSO,f_Transparence);
		}
		fn_vUpdateSPOFlagsOfChannelForActivation (
			p_stChannel -> hZoomSupObject ? p_stChannel -> hZoomSupObject : p_stChannel -> hSupObject ,
			p_stChannel -> bActiveChannel
		) ;
 
		p_stElt3d++;
	}
 
	/* now that everything is ready, let's update matrix !*/
	fn_vUpdateFrameMatrix(p_stSuperObject,p_stCurrentFrame3d,p_stCurrentAnim,uwCurrentFrame,(unsigned char) fn_b3dDataHasAnimMatrixChanged(h_Current3dData),fn_h3dDataGetChannelSOList(h_Current3dData));
	fn_v3dDataResetAnimMatrixHasChanged(h_Current3dData);
	/* update global matrix of all child*/
	PLA_fn_vRefreshGlobalMatrixUnderCharacter(p_stSuperObject);
}
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
/* Modif : check if char is freezed		Carlos Torres	13/03/98*/
/* Modif : del test last frame compute	Carlos Torres	13/03/98*/
/* Modif : continuous speed Carlos Torres 21/04/98*/
ACP_tdxBool PLA_fn_bSkipCurrentFrame(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData h_Current3dData;
	struct tdstState_  *p_stCurrentState;
	struct tdstAnim3d_ *p_stCurrentAnim;
	unsigned long ulNbFrames;
	unsigned short uwNbFrames;
	unsigned short NbFramesSLME;
 
	h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
 
	if (p_stCurrentState==NULL)
	{
#ifndef RETAIL
		ENGassert(0);
#endif
		return TRUE; /* not a good object !!! mettre un message d'erreur !!! ...*/
	}
	p_stCurrentAnim = p_stCurrentState->p_stAnim;
 
	/* for instance : a camera ...*/
	if (p_stCurrentAnim==NULL)
		return FALSE;
 
	/* skip if char is freezed*/
	if(!fn_uc3dDataGetFrameRate(h_Current3dData))
		return TRUE;
 
	/* unset all user flags */
	fn_v3dDataSetUserEventFlags( h_Current3dData, 0 );
 
	if (fn_l3dDataGetLastComputeEngineFrame(h_Current3dData)==0)
	{
		/* the frame is at 0 after a reinit or a pause or a change map or at the first time the anim is played...*/
		fn_v3dDataSetStartTime(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount-g_stEngineStructure.stEngineTimer.ulPauseTime+fn_ul3dDataGetStartTime(h_Current3dData));
		fn_v3dDataSetTimePreviousFrame(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount);
	}
 
	fn_v3dDataSetLastComputeEngineFrame(h_Current3dData,HIE_fn_lGetGlobalMatrixFrameCounter());
 
	/* update nb frame passed since last MechEvent*/
	NbFramesSLME=fn_uw3dDataGetNbEngineFrameSinceLastMechEvent(h_Current3dData);
	if (NbFramesSLME!=LME_INVALID)
	{
		NbFramesSLME++;
		fn_v3dDataSetNbEngineFrameSinceLastMechEvent(h_Current3dData,NbFramesSLME);
	}
 
	/* The current frame is the same as the previous skip it (anim too fast)*/
	if (fn_b3dDataGetSkipCurrentFrame(h_Current3dData))
	{
#ifdef D_USE_LIPSYNC
		unsigned short uwAddFrame;
#endif
 
#ifndef DISCREET_SPEED
		if(fn_p_stGetLinearSpeedVector(p_stCurrentAnim, fn_uw3dDataGetCurrentFrame(h_Current3dData)))
		{
			fn_vTransferSpeedInformationPLA_DNM(p_stSuperObject,fn_s3dDataGetLastFrame(h_Current3dData));
		}
#endif
		/* next frame don't be skipped*/
		fn_v3dDataSetSkipCurrentFrame(h_Current3dData,FALSE);
 
		/* compute current frame*/
		if (g_bAnimConstantSpeed)
			ulNbFrames=fn_uw3dDataGetCurrentFrame(h_Current3dData)+1;
		else
			ulNbFrames=fn_uc3dDataGetFrameRate(h_Current3dData)*(g_stEngineStructure.stEngineTimer.ulCurrentTimerCount-fn_ul3dDataGetStartTime(h_Current3dData))/1000;
 
#ifdef D_USE_LIPSYNC
		/* update synchro frame for lip synchro*/
		uwAddFrame=(short)(ulNbFrames-fn_uw3dDataGetCurrentFrame(h_Current3dData));
		fn_v3dDataSetCurrentSynchroFrame(h_Current3dData,(unsigned short)(fn_uw3dDataGetCurrentSynchroFrame(h_Current3dData)+uwAddFrame));
#endif
		/* set NbFrame and TimeDelay - depend if frame is over the last*/
		if (ulNbFrames>p_stCurrentAnim->uwNumberOfFrames)
		{
			fn_v3dDataSetTimeDelay(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount-1000*p_stCurrentAnim->uwNumberOfFrames/fn_uc3dDataGetFrameRate(h_Current3dData)-fn_ul3dDataGetStartTime(h_Current3dData));
			uwNbFrames=p_stCurrentAnim->uwNumberOfFrames;
		}
		else
		{
			fn_v3dDataSetTimeDelay(h_Current3dData,0);
			uwNbFrames=(unsigned short)ulNbFrames;
		}
 
		/* same frame but not over -> skip the next frame*/
		if ( (fn_uw3dDataGetCurrentFrame(h_Current3dData) == uwNbFrames) && (uwNbFrames != p_stCurrentAnim->uwNumberOfFrames) )
			fn_v3dDataSetSkipCurrentFrame(h_Current3dData,TRUE);
 
		/* if the current anim has only one frame, and if the current state has not been forced, and if the next state is the same*/
		/* as the current state, then skip !*/
		if (p_stCurrentAnim->uwNumberOfFrames == 1 &&
			!fn_b3dDataGetStateJustModified(h_Current3dData) &&
			fn_hGetNextStateInState(p_stCurrentState) == p_stCurrentState)
		{
			fn_v3dDataSetSkipCurrentFrame(h_Current3dData,TRUE);
			fn_v3dDataSetCurrentFrame(h_Current3dData,0);
		}
		else
			fn_v3dDataSetCurrentFrame(h_Current3dData,uwNbFrames);
 
		/* if frame over the last --> End Of Anim*/
		if (fn_uw3dDataGetCurrentFrame(h_Current3dData) == p_stCurrentAnim->uwNumberOfFrames )
			fn_v3dDataSetFlagEndOfAnim(h_Current3dData,TRUE);
 
		/* End of State when End Of Anim & No Repeat & No Next State*/
		if (fn_uc3dDataGetRepeatAnimation(h_Current3dData) == 0
			&& fn_uw3dDataGetCurrentFrame(h_Current3dData) == p_stCurrentAnim->uwNumberOfFrames
			&& fn_hGetNextStateInState(p_stCurrentState) == NULL)
		{
			fn_v3dDataSetFlagEndState(h_Current3dData,TRUE);
		}
		return TRUE;
	}
	/* frame different from the previous*/
	else
		return FALSE;
}
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/* **************************************************************************************/
/* *  Description :   Change frame of current anim, and change anim if we have reached **/
/* *									end, Make sure that fn_vDoAnim is not called for objects without **/
/* *									Anim or State                                                    **/
/* *===================================================================================**/
/* *-----------------------------------------------------------------------------------**/
/* *  Creation date : 21/10/96            Author : DVD (Gizmo)                         **/
/* **************************************************************************************/
 
ACP_tdxBool PLA_fn_bDoAnimPlayerForCharacter(HIE_tdxHandleToSuperObject p_stSuperObject, ACP_tdxBool bNoDisplay, ACP_tdxBool _bHandleSkippedEventsIfRelevant )
{
	MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	struct tdstState_  *p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
	struct tdstState_  *p_stTmpState;
	struct tdstAnim3d_ *p_stCurrentAnim;

	unsigned char         FlagModifyState;
	/*	tdstSubAnim3d         stTmpSubAnim;*/
	ACP_tdxBool bDidChangeState = FALSE;
	/* MR2204*/
	unsigned long ulAddFrames=0;
	POS_tdstCompletePosition *p_stCharMatrix;
	MTH3D_tdstVector stCharTransVect/*,stOffsetAnim*/;
 
#ifdef D_USE_LIPSYNC
	/* MR0407*/
	unsigned short uwAddFrame;
#endif
	unsigned char ucStateSpeed;		/* MR2407*/
 
	if (p_stCurrentState==NULL)
	{
#ifndef RETAIL
		ENGassert(0);
#endif
		return FALSE; /* not a good object !!! mettre un message d'erreur !!! ...*/
	}
 
	p_stCurrentAnim   = p_stCurrentState->p_stAnim;
 
	/* for instance : a camera ...*/
	if (p_stCurrentAnim==NULL)
	{
		PLA_fn_vComputeNextFrame(p_stSuperObject);
		return TRUE;
	}
 
/*	p_cOldName = p_stCurrentAnim->szAnimName;*/
 
	/*	update the stCurrent3dData structure*/
	if(fn_uw3dDataGetCurrentFrame(h_Current3dData) == p_stCurrentAnim->uwNumberOfFrames	|| fn_uc3dDataGetFlagModifState(h_Current3dData) == TRUE)
	{
		/* the current anim has reached its end... or a new state has been set for this perso*/
		if (fn_uc3dDataGetFlagModifState(h_Current3dData) == FALSE)
		{
			/* the current anim has reached its end.*/
			/* it will loop, or carry on another animation. Play remaining events*/
			/* if no frame has been skipped since the last one, then this call will set up the next event to play.*/
			fn_vPlayLastEventsBeforeRestart( p_stSuperObject );
		}
		else
		{
			/* a new state has been set for this perso*/
			/* desinit all events. the next anim interrupt the current one, so call with a TRUE to stop events*/
			fn_vDesInitAllEvents(p_stSuperObject,fn_h3dDataGetWantedState(h_Current3dData),TRUE);
		}
 
		if(fn_uc3dDataGetRepeatAnimation(h_Current3dData) > 0 && fn_uc3dDataGetFlagModifState(h_Current3dData) == FALSE )
		{
			/* the anim will repeat, and no state change has occured --> normal progression*/
			/* look how many frames must be skiped according to the time delay*/
			if (g_bAnimConstantSpeed)
				ulAddFrames=fn_uw3dDataGetCurrentFrame(h_Current3dData)+1;
			else
				ulAddFrames=fn_uc3dDataGetFrameRate(h_Current3dData)*fn_ul3dDataGetTimeDelay(h_Current3dData)/1000;
 
			/* this calcul is strange !*/
#ifdef D_USE_LIPSYNC
			uwAddFrame=(unsigned short)(ulAddFrames-fn_uw3dDataGetCurrentFrame(h_Current3dData));
			fn_v3dDataSetCurrentSynchroFrame(h_Current3dData,(unsigned short)(fn_uw3dDataGetCurrentSynchroFrame(h_Current3dData)+uwAddFrame));
#endif
 
			/* the next frame number must be within the right interval... (from 0 to number of frames -1)*/
			ulAddFrames%=p_stCurrentAnim->uwNumberOfFrames;
 
			/* compute start time for this new anim sequence*/
			/* this is current time - (number of frames skipped / framerate)*/
			fn_v3dDataSetStartTime(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount-(1000*ulAddFrames)/fn_uc3dDataGetFrameRate(h_Current3dData));
 
			/* set the current new frame*/
			fn_v3dDataSetCurrentFrame(h_Current3dData,(unsigned short)ulAddFrames);
			/* ??? last frame == -1 ???*/
			fn_v3dDataSetLastFrame(h_Current3dData,-1);
			/* BUG state just modified ????*/
/*			fn_v3dDataSetStateJustModified(h_Current3dData,TRUE);*/
			/* decrease the number of repeat for this anim*/
			fn_v3dDataDecRepeatAnimation(h_Current3dData);
		}
		else
		{
			/* two cases :*/
			/* - a change of state has been asked to interrupt the current one*/
			/* or*/
			/* - the anim is finished and will not repeat --> carry on next anim*/
			if(fn_uc3dDataGetFlagModifState(h_Current3dData) == FALSE)
			{
				/* anim finished and carry on a new one*/
				/* set the nex state*/
				fn_v3dDataSetWantedState(h_Current3dData,fn_hGetNextStateInState(fn_h3dDataGetCurrentState(h_Current3dData)));
			}
 
#ifndef RETAIL
			if(fn_h3dDataGetWantedState(h_Current3dData)==NULL) M_GameFatalError(E_uwGamePLA_NoWantedState);
#endif
 
			/* get the next state*/
			p_stTmpState = fn_h3dDataGetWantedState(h_Current3dData);
 
			if (fn_h3dDataGetCurrentState(h_Current3dData) != p_stTmpState && fn_uc3dDataGetFlagModifState(h_Current3dData) == FALSE )
			{
				/* anim finished, carry on the next state which is different from the current one*/
				/* so desinit all events. the next anim normally follows the current one, so call with a FALSE so that it does not stop events*/
				fn_vDesInitAllEvents(p_stSuperObject,NULL,FALSE);
			}
 
			/* bDidchangestate is TRUE if the new state is different from the current one, or if the current state has been interrupted*/
			bDidChangeState = ( ACP_tdxBool ) ( p_stCurrentState != p_stTmpState || fn_uc3dDataGetFlagModifState ( h_Current3dData ) == TRUE ) ;
 
			if ( bDidChangeState )
			{
				FlagModifyState = TRUE ;
 
				/* Calcul Offset ici (MR1504)*/
				p_stCharMatrix = HIE_fn_hGetSuperObjectMatrix(p_stSuperObject);
				MTH3D_M_vSubVector( &stCharTransVect , POS_fn_p_stGetTranslationVector(p_stCharMatrix) , /*POS_fn_p_stGetTranslationVector(*/&p_stTmpState->p_stAnim->stOffsetMatrix/*)*/ ); /*AR9811*/
				MTH3D_M_vAddVector( &stCharTransVect , &stCharTransVect , /*POS_fn_p_stGetTranslationVector(*/&p_stCurrentState->p_stAnim->stOffsetMatrix/*)*/ ); /*AR9811*/
				POS_fn_vSetTranslationVector(p_stCharMatrix,&stCharTransVect);
				POS_fn_vMulMatrixMatrix(HIE_fn_hGetSuperObjectGlobalMatrix(p_stSuperObject),HIE_fn_hGetSuperObjectGlobalMatrix(HIE_fn_hGetSuperObjectFather(p_stSuperObject)),p_stCharMatrix);
 
				/* we change of state, so we change of anim. If new anim has not the same number of elements as the current one*/
				/* then we must change the elements array allocation*/
				if (p_stCurrentAnim->ucMaxNumberOfElements != p_stTmpState->p_stAnim->ucMaxNumberOfElements || fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d == NULL)
				{
/* ANNECY MT - 22/09/98 {*/
					/*
					if (fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d)
					{
                        MMG_fn_vAddMemoryInfo( MMG_C_lTypeFamily , MMG_C_lSubTypeAnimation , h_Current3dData->h_Family);
						TMP_M_Free(fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d);
					}
                    MMG_fn_vAddMemoryInfo( MMG_C_lTypeFamily , MMG_C_lSubTypeAnimation , h_Current3dData->h_Family);
					fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d = (tdstElement3d*)TMP_M_p_Malloc(sizeof(tdstElement3d) * p_stTmpState->p_stAnim->ucMaxNumberOfElements);
					memset(fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d,0,sizeof(tdstElement3d) * p_stTmpState->p_stAnim->ucMaxNumberOfElements);
					*/
					fn_vAllocArrayOfElts3d (h_Current3dData , p_stTmpState->p_stAnim->ucMaxNumberOfElements);
/* END ANNECY MT }*/
				}
 
				fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAnim = NULL;
				/* current state is the new state*/
				fn_v3dDataSetCurrentState(h_Current3dData,p_stTmpState);
				fn_vUpdateCurrentActivationForCharacter(p_stSuperObject);
				/* get new values*/
				p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);

				p_stCurrentAnim   = p_stCurrentState->p_stAnim;
 
				ucStateSpeed=fn_scGetSpeedInState(fn_h3dDataGetCurrentState(h_Current3dData));
				/* init events */
				if ( _bHandleSkippedEventsIfRelevant )
				{
					tdstEvent * p_stEvent ;
					int i ;
					unsigned char ucEventCount ;

					/* we force all skipped events to be replayed. */
					fn_vInitAllEvents ( p_stSuperObject , 0 ) ;
					/* the thing is: we don't want sound events to be played, hence we have to make them not playable this time */
					p_stEvent = fn_p_GetEventsAddress( p_stCurrentAnim , 0 ,fn_h3dDataGetCurrentObjectsTable(h_Current3dData) );
					if ( p_stEvent )
					for
					(
						i = 0 ;
						( i < p_stCurrentAnim -> ucNumberOfEvents )
						&& ( p_stEvent -> uwFrameNumber <= fn_uw3dDataGetForcedFrame ( h_Current3dData ) ) ;
						i ++ , p_stEvent ++
					)
					if ( GAM_fn_ucGetTypeOfEvent(p_stEvent) == C_ucSOUND_EVENT )
					{
						ucEventCount = GAM_fn_ucGetFirstCallOfEvent ( p_stEvent ) ;
						fn_v3dDataSetEventActivationByIndex ( h_Current3dData , i , ( unsigned char ) ( ucEventCount ? ucEventCount : ( unsigned char ) 1 ) ) ;
					}
				}
				else
				{
					fn_vInitAllEvents ( p_stSuperObject , fn_uw3dDataGetForcedFrame ( h_Current3dData ) ) ;
				}
				/* init frame rate*/
				fn_v3dDataSetFrameRate(h_Current3dData,ucStateSpeed);	/* MR0306*/
			}
			else
			{
				/* here, the current state has not been interrupted, and the next state is the same as the current one*/
				ucStateSpeed = fn_uc3dDataGetFrameRate(h_Current3dData);
			}
 
			/* look how many frames must be skiped according to the time delay*/
			if (g_bAnimConstantSpeed)
				ulAddFrames = fn_uw3dDataGetCurrentFrame(h_Current3dData)+1;
			else
				ulAddFrames = ucStateSpeed * fn_ul3dDataGetTimeDelay(h_Current3dData) / 1000 ;
 
			/* the next frame number must be within the right interval... (from 0 to number of frames -1)*/
			ulAddFrames %= p_stCurrentAnim->uwNumberOfFrames;
 
			/* the state has been modified*/
			/* set flag if next state is different from current state*/
			if (bDidChangeState)
				fn_v3dDataSetStateJustModified(h_Current3dData,TRUE);
 
			/* ??? forced frame ??? kesako*/
			if(fn_uw3dDataGetForcedFrame(h_Current3dData)!=0)
			{
#if defined(ANIM_DEBUG) && defined(U64)
				if(fn_uw3dDataGetForcedFrame(h_Current3dData) >= p_stCurrentAnim->uwNumberOfFrames)
				{
					osSyncPrintf("Error : Forced frame out of range\n");
					osSyncPrintf("Anim : %d, Frame : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,fn_uw3dDataGetForcedFrame(h_Current3dData));
				}
#endif
#ifndef RETAIL
				ENGassert(fn_uw3dDataGetForcedFrame(h_Current3dData) < p_stCurrentAnim->uwNumberOfFrames);
#endif
				fn_v3dDataSetCurrentFrame(h_Current3dData,fn_uw3dDataGetForcedFrame(h_Current3dData));
				fn_v3dDataSetForcedFrame(h_Current3dData,0);
			}
			else
			{
				/* not forced frame... (???)*/
				/* ??? strange calcul*/
				fn_v3dDataSetStartTime(h_Current3dData,fn_ul3dDataGetTimePreviousFrame(h_Current3dData) - fn_ul3dDataGetTimeDelay(h_Current3dData));
 
				/* the current frame is the new frame number (the one computed up there)*/
				fn_v3dDataSetCurrentFrame(h_Current3dData,(unsigned short)ulAddFrames);
				/* ??? last frame == -1 ???*/
				fn_v3dDataSetLastFrame(h_Current3dData,-1);
			}
 
			/* beginning of new (or same) state, so set the new repeat value*/
			fn_v3dDataSetRepeatAnimation(h_Current3dData,p_stCurrentState->ucRepeatAnimation);
			/* no more end of state now*/
			fn_v3dDataSetFlagEndState(h_Current3dData,FALSE);
			/* no more modif state now*/
			fn_v3dDataSetFlagModifState(h_Current3dData,FALSE);
			/* ???*/
			fn_v3dDataSetWantedState(h_Current3dData,p_stCurrentState);
		}
	}
 
	if (!bNoDisplay)
	{
		PLA_fn_vInitAllChildInHeapNewAnim(p_stSuperObject,p_stCurrentAnim,fn_uw3dDataGetCurrentFrame(h_Current3dData));

		PLA_fn_vDoFrame(p_stCurrentAnim,fn_uw3dDataGetCurrentFrame(h_Current3dData),p_stSuperObject);
	}

	/*
	 * this flag is true when we are called from the AI by a change action procedure -> if we launch
	 * the events now, the anim player at the beginning of the next frame will clear them, and the AI
	 * will miss them as well -> do not launch them now, but next frame, when the flag is false in the
	 * normal game loop course.
	 */
	if ( ! _bHandleSkippedEventsIfRelevant )
	{
		/* last event played is set correctly by*/
		/* - previous call to this function*/
		/* - init of all events*/
		/* - call to fn_vPlayLastEventsBeforeRestart() for previous loop of the same anim*/
		fn_vPlayEventsSinceLastOneNoLoop( p_stSuperObject );
	}
 
	/* Takes the speed in the anim and transfers it to the mechanics*/
	fn_vTransferSpeedInformationPLA_DNM(p_stSuperObject,fn_s3dDataGetLastFrame(h_Current3dData));
 
	PLA_fn_vComputeNextFrame(p_stSuperObject);
	return TRUE;
}
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
void PLA_fn_vComputeNextFrame(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	struct tdstState_  *p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
	struct tdstAnim3d_ *p_stCurrentAnim;
	unsigned long ulNextFrameNumber;
	unsigned short uwNextFrameInAnim;
#ifdef D_USE_LIPSYNC
	unsigned short uwFrameDifference;
#endif
 
	if (p_stCurrentState==NULL)
		return; /* not a good object !!! mettre un message d'erreur !!! ...*/
 
	p_stCurrentAnim   = p_stCurrentState->p_stAnim;
 
	/* for instance : a camera ...*/
	if (p_stCurrentAnim==NULL)  return;
 
	/* last played frame is the current one*/
	fn_v3dDataSetLastFrame(h_Current3dData,fn_uw3dDataGetCurrentFrame(h_Current3dData));
 
	/* compute next frame number*/
	if (g_bAnimConstantSpeed)
	{
		/* constant speed --> next frame is current frame +1*/
		ulNextFrameNumber = fn_uw3dDataGetCurrentFrame(h_Current3dData)+1;
	}
	else
	{
		/* not constant speed --> next frame is (current time - time of start of anim) * framerate*/
		/* == (time since beginning of anim) * framerate*/
		ulNextFrameNumber = fn_uc3dDataGetFrameRate(h_Current3dData)*(g_stEngineStructure.stEngineTimer.ulCurrentTimerCount-fn_ul3dDataGetStartTime(h_Current3dData))/1000;
	}
 
#ifdef D_USE_LIPSYNC
	/* update synchro frame for lip synchro*/
	uwFrameDifference = (short)(ulNextFrameNumber - fn_uw3dDataGetCurrentFrame(h_Current3dData));
	fn_v3dDataSetCurrentSynchroFrame(h_Current3dData,(unsigned short)(fn_uw3dDataGetCurrentSynchroFrame(h_Current3dData)+uwFrameDifference));
#endif
	/* analyse the next frame number, and compute the real next frame for this anim*/
	if (ulNextFrameNumber > p_stCurrentAnim->uwNumberOfFrames)
	{
		/* the next frame is too big, it exceeds the total number of frames in this anim*/
		if (!fn_uc3dDataGetFlagEndOfAnim(h_Current3dData))
		{
			/* flag end of anim not signaled*/
			/* memorize the extra time :*/
			/* extra time = (current time - start time) - (total number of frames / frame rate)*/
			/*            = total time to get to this point - anim total duration*/
			fn_v3dDataSetTimeDelay(h_Current3dData, g_stEngineStructure.stEngineTimer.ulCurrentTimerCount - fn_ul3dDataGetStartTime(h_Current3dData) - (1000 * p_stCurrentAnim->uwNumberOfFrames) / fn_uc3dDataGetFrameRate(h_Current3dData));
			/* the next frame will be the total number of frame, to signal that we went past the end of the anim*/
			uwNextFrameInAnim = p_stCurrentAnim->uwNumberOfFrames;
		}
		else
		{
			/* flag end of anim signaled*/
			/* so reset*/
			uwNextFrameInAnim = 0;
			fn_v3dDataSetTimeDelay(h_Current3dData,0);
			fn_v3dDataSetStartTime(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount);
		}
	}
	else
	{
		/* the next frame number didn't exceed the total number of frames in the anim*/
		/* so there is no time delay*/
		fn_v3dDataSetTimeDelay(h_Current3dData,0);
		/* and the real frame number = the next frame number*/
		/* Note : it is possible that next frame number == total number of frames in the anim*/
		/* this will signal then that we just went past the end of the anim*/
		uwNextFrameInAnim = (unsigned short)ulNextFrameNumber;
	}
 
	if ((fn_uw3dDataGetCurrentFrame(h_Current3dData) == uwNextFrameInAnim) && !fn_b3dDataGetStateJustModified(h_Current3dData)
		&&(uwNextFrameInAnim != p_stCurrentAnim->uwNumberOfFrames))
	{
		/* if next frame is the current one, and if state was not just modified, and if we did not just pass the end of the anim, then skip next frame*/
		fn_v3dDataSetSkipCurrentFrame(h_Current3dData,TRUE);
	}
 
	/* the next frame becomes the official current frame*/
	/* if the current anim has only one frame, and if the current state has not been forced, and if the next state is the same*/
	/* as the current state, then skip !*/
	if (p_stCurrentAnim->uwNumberOfFrames == 1 &&
		!fn_b3dDataGetStateJustModified(h_Current3dData) &&
		fn_hGetNextStateInState(p_stCurrentState) == p_stCurrentState)
	{
		fn_v3dDataSetSkipCurrentFrame(h_Current3dData,TRUE);
		fn_v3dDataSetCurrentFrame(h_Current3dData,0);
	}
	else
		fn_v3dDataSetCurrentFrame(h_Current3dData,uwNextFrameInAnim);
 
 
	/* update end of anim flag*/
	fn_v3dDataSetFlagEndOfAnim(h_Current3dData, (unsigned char)(uwNextFrameInAnim == p_stCurrentAnim->uwNumberOfFrames));
 
	/* End of State when End Of Anim & No Repeat & No Next State*/
	if( fn_uc3dDataGetRepeatAnimation(h_Current3dData) == 0 &&
		fn_uw3dDataGetCurrentFrame(h_Current3dData) == p_stCurrentAnim->uwNumberOfFrames &&
		fn_hGetNextStateInState(p_stCurrentState) == NULL )
	{
		fn_v3dDataSetFlagEndState(h_Current3dData,TRUE);
	}
 
 
 
 
	fn_v3dDataSetStateJustModified(h_Current3dData,FALSE);
	/* ????*/
	fn_v3dDataSetTimePreviousFrame(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount);
}
 
 
/*            ######################################################################## */
/*        ############################################################################ */
/*      ########################## MANAGMENT of the SUPEROBJECTS HEAP ################ */
/*     ############################################################################### */
/*     ############################################################################### */
/*     #########                                                                       */
/* #################                                                                   */
/*   #############                                                                     */
/*     #########                                                                       */
/*       #####                                                                         */
/*         #                                                                           */
 
 
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
 
 
 
 
void PLA_fn_vInitMatrixHeap(void)
{
	unsigned long i;
	
	/* matrix array has the same size as the SO array*/
#ifdef _DEBUG
	for(i=0; i<__PLA_LIM_SUPOBJ_ALLOC__ + 1; i++)
	{
		POS_fn_vSetIdentityMatrix(&PLA_g_d_stMatrixHeap[i]);
	}
	
#else
	for(i=0; i<__PLA_NB_MAX_SUPOBJ__ + 1; i++)
	{
		POS_fn_vSetIdentityMatrix(&PLA_g_d_stMatrixHeap[i]);
	}
#endif
}
 
 
void PLA_fn_vCreateMatrixHeap(void)
{
	/* matrix array has the same size as the SO array*/
    MMG_fn_vAddMemoryInfo(MMG_C_lTypeGAM, MMG_C_lSubTypePlayer, 0);
 
#ifdef _DEBUG
	/* the '+1' is for the matrix associated to the emergency SO*/
	//XB 08/04/99
	//PLA_g_d_stMatrixHeap = ( GEO_tdxHandleToMatrix) TMP_M_p_Malloc(sizeof(POS_tdstCompletePosition) * (__PLA_LIM_SUPOBJ_ALLOC__ + 1));
	GEO_M_CPAMalloc(PLA_g_d_stMatrixHeap,GEO_tdxHandleToMatrix,sizeof(POS_tdstCompletePosition)*(__PLA_LIM_SUPOBJ_ALLOC__+1),E_uwGEONotEnoughtMemory);
	//End XB 08/04/99
#else
	/* the '+1' is for the matrix associated to the emergency SO*/
	//XB 08/04/99
	//PLA_g_d_stMatrixHeap = ( GEO_tdxHandleToMatrix) TMP_M_p_Malloc(sizeof(POS_tdstCompletePosition) * (__PLA_NB_MAX_SUPOBJ__ + 1));
	GEO_M_CPAMalloc(PLA_g_d_stMatrixHeap,GEO_tdxHandleToMatrix,sizeof(POS_tdstCompletePosition)*(__PLA_NB_MAX_SUPOBJ__+1),E_uwGEONotEnoughtMemory);
	//End XB 08/04/99
#endif
 
}
 
 
void PLA_fn_vInitSupObjHeap(void)
{
	GEO_tdxHandleToMatrix		p_stMatrix;
	HIE_tdxHandleToSuperObject	p_stSO, p_stSOStop;
	/*unsigned long				i;*/
	
	/* initialise state array for heap, and */
	/* make SO local matrix point to the right matrix in the matrix array*/
	p_stMatrix = PLA_g_d_stMatrixHeap;
	p_stSO = PLA_g_d_stSupObjHeap;
	p_stSOStop = p_stSO + __PLA_LIM_SUPOBJ_ALLOC__ +1;
 
#ifdef _DEBUG
	memset(PLA_g_a_wStateOfSupObjHeap, 0, sizeof(short) * __PLA_LIM_SUPOBJ_ALLOC__);
 
	p_stSOStop = p_stSO + __PLA_LIM_SUPOBJ_ALLOC__ +1;
	while (p_stSO != p_stSOStop)
	{
		p_stSO->hLocalMatrix = p_stMatrix;
		p_stMatrix++;
		p_stSO++;
	}
#else
	memset(PLA_g_a_wStateOfSupObjHeap, 0, sizeof(short) * __PLA_NB_MAX_SUPOBJ__);
 
	p_stSOStop = p_stSO + __PLA_NB_MAX_SUPOBJ__ +1;
	while (p_stSO != p_stSOStop)
	{
		p_stSO->hLocalMatrix = p_stMatrix;
		p_stMatrix++;
		p_stSO++;
	}
#endif
	
	PLA_g_ulCurrentPosInSupObjHeap = 0L;
	PLA_g_ulNbAllocInSupObjHeap = 0L;
}
 
 
void PLA_fn_vCreateSupObjHeap(void)
{
#ifdef _DEBUG
	PLA_g_d_stSupObjHeap = HIE_fn_p_stCreateSuperObjectTab(__PLA_LIM_SUPOBJ_ALLOC__ + 1);		/* + 1 is for the emergency SO*/
#else
	PLA_g_d_stSupObjHeap = HIE_fn_p_stCreateSuperObjectTab(__PLA_NB_MAX_SUPOBJ__ + 1);			/* + 1 is for the emergency SO*/
#endif
	g_Randomhandle = 0;
}
 
 
void PLA_fn_vInitHeaps(void)
{
	PLA_fn_vInitMatrixHeap();
	PLA_fn_vInitSupObjHeap();
}
 
 
void PLA_fn_vCreateAndInitHeaps(void)
{
	/* always init SO heap after matrix heap*/
	PLA_fn_vCreateMatrixHeap();
	PLA_fn_vCreateSupObjHeap();
	PLA_fn_vInitMatrixHeap();
	PLA_fn_vInitSupObjHeap();
	PLA_g_ulMaxOccupationOfSupObjHeap = 0L;
	PLA_g_ulMaxOccupationOfChannels = 0L;
}
 
 
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
HIE_tdxHandleToSuperObject PLA_fn_hFindNextFreeSupObj(void)
{
	HIE_tdxHandleToSuperObject p_stSO_Child;
	/* one more SO allocated*/
	PLA_g_ulNbAllocInSupObjHeap ++;
	/* check if there is some room left*/
 
/* _______________________ DEBUG CASE _____________________________________ */
#ifdef _DEBUG
 
	if (PLA_g_ulNbAllocInSupObjHeap >= __PLA_LIM_SUPOBJ_ALLOC__) 
	{
		/* not enough memory, so return the emergency SO*/
		p_stSO_Child = HIE_fn_hGetElementFromSuperObjectTab(PLA_g_d_stSupObjHeap,__PLA_LIM_SUPOBJ_ALLOC__);
	}
	else
	{
		while( PLA_g_a_wStateOfSupObjHeap[PLA_g_ulCurrentPosInSupObjHeap] ) 
		{
			PLA_g_ulCurrentPosInSupObjHeap ++; 
			if (PLA_g_ulCurrentPosInSupObjHeap == __PLA_LIM_SUPOBJ_ALLOC__)
				PLA_g_ulCurrentPosInSupObjHeap = 0L; 
		}
 
/* _______________________ RELEASE CASE _____________________________________ */
#else
	if (PLA_g_ulNbAllocInSupObjHeap >= __PLA_NB_MAX_SUPOBJ__) 
	{
		/* not enough memory, so return the emergency SO*/
		p_stSO_Child = HIE_fn_hGetElementFromSuperObjectTab(PLA_g_d_stSupObjHeap,__PLA_NB_MAX_SUPOBJ__);
	}
	else
	{
		while( PLA_g_a_wStateOfSupObjHeap[PLA_g_ulCurrentPosInSupObjHeap] ) 
		{
			PLA_g_ulCurrentPosInSupObjHeap ++; 
			if (PLA_g_ulCurrentPosInSupObjHeap == __PLA_NB_MAX_SUPOBJ__)
				PLA_g_ulCurrentPosInSupObjHeap = 0L; 
		}
#endif	
/* _______________________ END _____________________________________ */
 
		/* get the new superobject*/
		PLA_g_a_wStateOfSupObjHeap[PLA_g_ulCurrentPosInSupObjHeap] = 1;
 
		p_stSO_Child = HIE_fn_hGetElementFromSuperObjectTab(PLA_g_d_stSupObjHeap,PLA_g_ulCurrentPosInSupObjHeap);
	}
 
	/*enable all display properties*/
	HIE_fn_vSetSuperObjectDrawMask(p_stSO_Child,GLI_C_lAllIsEnable);
	HIE_fn_SO_vSetFlags(p_stSO_Child,0);
 
	/* compute new max*/
	if (PLA_g_ulMaxOccupationOfSupObjHeap < PLA_g_ulNbAllocInSupObjHeap)
		PLA_g_ulMaxOccupationOfSupObjHeap++;
	
	/* update rasters vars*/
	PRF_fn_vSetIndependantVariable(PRF_C_ulIdpNbAllocSPO,PLA_g_ulNbAllocInSupObjHeap);
	PRF_fn_vSetIndependantVariable(PRF_C_ulIdpNbMaxAllocSPO,PLA_g_ulMaxOccupationOfSupObjHeap);
 
	/* reset Father link & linked object*/
	HIE_M_vIsolate(p_stSO_Child);
	HIE_fn_vSetSuperObjectObjectAndType(p_stSO_Child,NULL,HIE_C_ulSuperObject);
 
	/* return the handle to the reserved superobject*/
	return p_stSO_Child;
}
 
 
void PLA_fn_vReleaseSuperObjectInHeap(HIE_tdxHandleToSuperObject _hSupObj)
{
	long lPos;
	
/* _______________________ DEBUG CASE _____________________________________ */
#ifdef _DEBUG
	
	/* check if the given SO is not  the emergency SO*/
	if (_hSupObj != HIE_fn_hGetElementFromSuperObjectTab(PLA_g_d_stSupObjHeap,__PLA_LIM_SUPOBJ_ALLOC__))
	{
		lPos = HIE_fn_hGetIndexFromSuperObjectTabAndElement(PLA_g_d_stSupObjHeap, _hSupObj); 
		assert(lPos >= 0 && lPos < __PLA_LIM_SUPOBJ_ALLOC__ && PLA_g_a_wStateOfSupObjHeap[lPos] != 0) ;
		PLA_g_a_wStateOfSupObjHeap[lPos] = 0;
	}
 
/* _______________________ RELEASE CASE _____________________________________ */
#else
	/* check if the given SO is not  the emergency SO*/
	if (_hSupObj != HIE_fn_hGetElementFromSuperObjectTab(PLA_g_d_stSupObjHeap,__PLA_NB_MAX_SUPOBJ__))
	{
		lPos = HIE_fn_hGetIndexFromSuperObjectTabAndElement(PLA_g_d_stSupObjHeap, _hSupObj); 
		assert(lPos >= 0 && lPos < __PLA_LIM_SUPOBJ_ALLOC__ && PLA_g_a_wStateOfSupObjHeap[lPos] != 0);
		PLA_g_a_wStateOfSupObjHeap[lPos] = 0;
	}
 
#endif	
/* _______________________ END _____________________________________ */
	
	PLA_g_ulNbAllocInSupObjHeap--;
 
	/* update rasters vars*/
	PRF_fn_vSetIndependantVariable(PRF_C_ulIdpNbAllocSPO,PLA_g_ulNbAllocInSupObjHeap);
}
 
 
 
#ifdef ACTIVE_EDITOR
void PLA_fn_vUpdateFrameCounterForModules(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData		h_Current3dData;
	tdstAChannel				*p_stChannel;
	
	h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	p_stChannel = fn_h3dDataGetFirstActiveChannel(h_Current3dData);
	while (p_stChannel)
	{
		/* update only if it was valid before !*/
		if (p_stChannel->hSupObject->llastComputeFrameForModule >= HIE_gs_lCurrentFrame-1)
		{
			p_stChannel->hSupObject->llastComputeFrameForModule = HIE_gs_lCurrentFrame;
		}
		p_stChannel = p_stChannel->p_stNextActiveChannel;
	}
}
#endif

/* called when the actor's transparency changed */
void PLA_fn_vUpdateTransparencyForModules(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData		h_Current3dData;
	tdstAChannel				*p_stChannel;
	HIE_tdxHandleToSuperObject		p_stTargetSO;
	float fTransparence = HIE_fn_fGetSuperObjectTransparenceLevel(p_stSuperObject);
	register ACP_tdxBool bPersoTransparencyActive = (ACP_tdxBool) ((HIE_fn_lGetSuperObjectDrawMask(p_stSuperObject)&GLI_C_lIsNotGrided) == GLI_C_lIsNotGrided);
	
	h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	p_stChannel = fn_h3dDataGetFirstActiveChannel(h_Current3dData);
	while (p_stChannel)
	{
		/* get the channel and its target SO*/
		p_stTargetSO = p_stChannel->hSupObject;

		/* Module transparency isn't setting in IA*/
		if ((HIE_fn_SO_ulGetFlags(p_stTargetSO) & HIE_C_Flag_ModuleTransparency) !=  HIE_C_Flag_ModuleTransparency )
		{
			HIE_fn_vSetSuperObjectTransparenceLevel(p_stTargetSO,fTransparence);
			/* NO charcter transparency*/
			if ( bPersoTransparencyActive )
			{
				/* no anim transparency for that module*/
				HIE_fn_vSetSuperObjectDrawMask(p_stTargetSO, HIE_fn_lGetSuperObjectDrawMask(p_stTargetSO) | GLI_C_lIsNotGrided );
			}
		}
		p_stChannel = p_stChannel->p_stNextActiveChannel;
	}
}

 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
void PLA_fn_vInitAllChildInHeapNewAnim(	HIE_tdxHandleToSuperObject p_stSuperObject
										 ,	struct tdstAnim3d_ *p_stCurrentAnim,
										 unsigned short _uwFrameNumber) 
{
	MS_tdxHandleTo3dData		h_Current3dData;
	struct tdstFrame3d_			*p_stCurrentFrame3d;
	struct tdstElement3d_		*p_stElt3d;
	struct tdstElement3d_		*p_stStopElt3d;
	register tdstAChannel		*p_stNewChannel;
	unsigned long				ulNextChannelNumber;
	tdstCouple					*p_stNewCouples, *p_stOldCouples;
 
	CHN_tdxHandleToChannelArray	hChannelArray;
	register tdstAChannel		*p_stLastFrameChannel;
	register tdstAChannel		*p_stLastFrameChannelForLink;
	BOOL						bHieChanged;
 
	h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	hChannelArray = fn_h3dDataGetChannelSOList(h_Current3dData);
	p_stCurrentFrame3d = fn_p_st3dDataGetCurrentFrame(h_Current3dData);
 
	/* get the old hierarchy couples*/
#ifndef U64
	p_stOldCouples = fn_p_st3dDataGetCurrentHieCouples(h_Current3dData);
#else
	p_stOldCouples = p_stCurrentFrame3d->stHierarchy.d_stCouples;
#endif
 
	fn_vUpdateFrame(p_stSuperObject,p_stCurrentFrame3d,p_stCurrentAnim,_uwFrameNumber);
 
	p_stElt3d = p_stCurrentFrame3d->p_stArrayOfElts3d;
	p_stNewCouples = p_stCurrentFrame3d->stHierarchy.d_stCouples;
 
	if (hChannelArray == NULL)
	{
		/* create array of channels !!*/
		fn_vInitCSOList(&hChannelArray,fn_ul3dDataGetNumberOfChannels(h_Current3dData));
		fn_v3dDataSetChannelSOList(h_Current3dData,hChannelArray);
		/* set the first active channel to NULL because new activation !*/
		fn_v3dDataSetFirstActiveChannel(h_Current3dData, NULL);
	}
 
	/* check if hierarhy changed for this frame...*/
	/* hie changed if couple array are different*/
	if (p_stOldCouples != p_stNewCouples)
	{
		register unsigned long	i;
#ifdef U64
		tdstCouple* p_stBackupOldCouples=p_stOldCouples;
/*		osSyncPrintf("New hierarchy for anim %d! (%x)\n",p_stCurrentAnim->uwNumOfA3dGENERAL,p_stNewCouples);*/
#endif /*U64*/

		/* hierarchy changed !!*/
		/* so apply changes on the channels !*/
 
		bHieChanged = TRUE;
		/* first, 'isolate' old channels if necessary*/
		if (p_stOldCouples)
		{
			/* ok, there was an old hierarchy*/
			i = fn_ul3dDataGetCurrentHieNbCouples(h_Current3dData);
			while (i--)
			{
				/* isolate the channel*/
				hChannelArray[p_stOldCouples->wChild].p_stFatherChannel = NULL;
				/* next one !*/
				p_stOldCouples++;
			}
		}
 
		/* then, set up the new hierarchy*/
		i = p_stCurrentFrame3d->stHierarchy.ulNbOfCouples;
		/* register the new hierarchy in the 3ddata*/
		fn_v3dDataSetCurrentHieCouples(h_Current3dData,p_stNewCouples);
		fn_v3dDataSetCurrentHieNbCouples(h_Current3dData,i);
		while (i--)
		{
			/* set up the channel link*/
			hChannelArray[p_stNewCouples->wChild].p_stFatherChannel = hChannelArray + p_stNewCouples->wFather;
			/* next one !*/
			p_stNewCouples++;
		}
#ifdef U64
		/*AR9902 Free old hierarchy*/
		if (p_stBackupOldCouples)
		{

			MMG_fn_vAddMemoryInfo( MMG_C_lTypeInterpol , MMG_C_lSubTypeHierarchies , 0 );
			TMP_M_Free(p_stBackupOldCouples);		
		}
#endif 
	}
	else
	{
		bHieChanged = FALSE;
	}
 
	/* set the stop adress for elt3d loop*/
	p_stStopElt3d = p_stElt3d + p_stCurrentAnim->ucMaxNumberOfElements;
	/* get adress of next channel for this new frame*/
	if (p_stElt3d == p_stStopElt3d)
	{
		/* strange, new frame elt3d array is empty...*/
		p_stNewChannel = NULL;
	}
	else
	{
		ulNextChannelNumber = p_stElt3d->ucChannelNumber;
		p_stNewChannel = (ulNextChannelNumber == C_ucUnknownChannel) ? NULL : hChannelArray + ulNextChannelNumber;
	}
 
	/* loop init for last frame channel array*/
	p_stLastFrameChannel = fn_h3dDataGetFirstActiveChannel(h_Current3dData);
	p_stLastFrameChannelForLink = NULL;
 
	/* paralel loop ...*/
	/* stop when both pointers reach the end...*/
	while (p_stNewChannel || p_stLastFrameChannel)
	{
		if (p_stNewChannel == p_stLastFrameChannel)
		{
			/* here, both p_stLastFrameChannel and p_stNewChannel are not NULL*/
			/* and we have p_stLastFrameChannel == p_stNewChannel*/
			/* so the channel for the next frame was already used for the last frame*/
 
			if (bHieChanged)
			{
				/* hierarchy changed, so update it !*/
				/* isolate old superobject --- not necessary because addtail will do it !*/
				/* LST2_M_DynamicIsolate(p_stLastFrameChannel->hSupObject);*/
				/* and put it back at its right place*/
				if (p_stLastFrameChannel->p_stFatherChannel)
				{
					/* this channel has another channel for father*/
					/* check if this other channel's SO already exists !*/
					if (p_stLastFrameChannel->p_stFatherChannel->hSupObject == NULL)
					{
						/*create it !*/
#if defined(ANIM_DEBUG) && defined(U64)
						if(p_stLastFrameChannel->p_stFatherChannel <= p_stLastFrameChannel)
						{
							osSyncPrintf("Error : p_stLastFrameChannel->p_stFatherChannel > p_stLastFrameChannel\n");
							osSyncPrintf("Anim : %d, Frame : %d, Channel : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,_uwFrameNumber,p_stElt3d->ucChannelNumber);
						}
#endif
#ifndef RETAIL
						ENGassert(p_stLastFrameChannel->p_stFatherChannel > p_stLastFrameChannel);
#endif
						p_stLastFrameChannel->p_stFatherChannel->hSupObject = PLA_fn_hFindNextFreeSupObj();
					}
					HIE_fn_vSuperObjectAddTail(p_stLastFrameChannel->p_stFatherChannel->hSupObject,p_stLastFrameChannel->hSupObject);
				}
				else
				{
					HIE_fn_vSuperObjectAddTail(p_stSuperObject,p_stLastFrameChannel->hSupObject);
				}
			}
			/* no need to update link...*/
			/* advance to next step, that is advance in both arrays*/
			/* link*/
			p_stLastFrameChannelForLink = p_stLastFrameChannel;
			/* first array*/
			/* check if previous frame active channel links are sorted*/
#if defined(ANIM_DEBUG) && defined(U64)
			if(!(p_stLastFrameChannel->p_stNextActiveChannel == NULL || p_stLastFrameChannel->p_stNextActiveChannel > p_stLastFrameChannel))
			{
				osSyncPrintf("Error : sort problem\n");
				osSyncPrintf("Anim : %d, Frame : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,_uwFrameNumber);
			}
#endif
#ifndef RETAIL
			ENGassert(p_stLastFrameChannel->p_stNextActiveChannel == NULL || p_stLastFrameChannel->p_stNextActiveChannel > p_stLastFrameChannel);
#endif
			p_stLastFrameChannel = p_stLastFrameChannel->p_stNextActiveChannel;
			/* second array*/
			p_stElt3d++;
			/* get adress of next channel for this new frame*/
			if (p_stElt3d == p_stStopElt3d)
			{
				/* reached the end of second array*/
				p_stNewChannel = NULL;
			}
			else
			{
				/* check if next frame channels are sorted*/
#if defined(ANIM_DEBUG) && defined(U64)
				if(!(p_stElt3d->ucChannelNumber == C_ucUnknownChannel || p_stElt3d->ucChannelNumber > ulNextChannelNumber))
				{
					osSyncPrintf("Error : sort problem\n");
					osSyncPrintf("Anim : %d, Frame : %d, Channel : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,_uwFrameNumber,p_stElt3d->ucChannelNumber);
				}
#endif
#ifndef RETAIL
				ENGassert(p_stElt3d->ucChannelNumber == C_ucUnknownChannel || p_stElt3d->ucChannelNumber > ulNextChannelNumber);
#endif
				ulNextChannelNumber = p_stElt3d->ucChannelNumber;
				p_stNewChannel = (ulNextChannelNumber == C_ucUnknownChannel) ? NULL : hChannelArray + ulNextChannelNumber;
			}
		}
		else if (p_stLastFrameChannel == NULL || (p_stNewChannel != NULL && p_stLastFrameChannel > p_stNewChannel))
		{
			/* there is a new active channel in the new frame...*/
			/* allocate a new superObject (if not already done)*/
			/* if the new SO already exists, it means that this channel is the father*/
			/* of another channel of lower number*/
			if (p_stNewChannel->hSupObject == NULL)
			{
				p_stNewChannel->hSupObject =  PLA_fn_hFindNextFreeSupObj();
			}
			/* put this new supobject at its right place !*/
			if (p_stNewChannel->p_stFatherChannel)
			{
				/* check if the father's SO already exists !*/
				if (p_stNewChannel->p_stFatherChannel->hSupObject == NULL)
				{
					/* it does not exist, so create it !*/
#ifndef RETAIL
					ENGassert(p_stNewChannel->p_stFatherChannel > p_stNewChannel);
#endif
					p_stNewChannel->p_stFatherChannel->hSupObject = PLA_fn_hFindNextFreeSupObj();
				}
				HIE_fn_vSuperObjectAddTail(p_stNewChannel->p_stFatherChannel->hSupObject,p_stNewChannel->hSupObject);
			}
			else
			{
				HIE_fn_vSuperObjectAddTail(p_stSuperObject,p_stNewChannel->hSupObject);
			}
			/* set this new SO anim matrix*/
/*			HIE_fn_vSetSuperObjectMatrix(p_stNewChannel->hSupObject,&p_stNewChannel->stAnimMatrix);*/
			/* update link of previous channel*/
			if (p_stLastFrameChannelForLink)
			{
				/* there was a previous active channel !!*/
				/* new channel has been inserted !!*/
				/* update link of new channel*/
				p_stNewChannel->p_stNextActiveChannel = p_stLastFrameChannelForLink->p_stNextActiveChannel;
				/* and update link of previous channel*/
				p_stLastFrameChannelForLink->p_stNextActiveChannel = p_stNewChannel;
			}
			else
			{
				/* there is no previous active channel, so this new channel is the first one...*/
				/* new channel's next active channel is the first active channel*/
				p_stNewChannel->p_stNextActiveChannel = fn_h3dDataGetFirstActiveChannel(h_Current3dData);
				/* set as the first active in the 3ddata*/
				fn_v3dDataSetFirstActiveChannel(h_Current3dData, p_stNewChannel);
			}
			/* and now, go to next step... that is advance one in the next frame array*/
			/* last channel for link is the new one that has been inserted*/
			p_stLastFrameChannelForLink = p_stNewChannel;
			/* advance in second array*/
			p_stElt3d++;
			/* get adress of next channel for this new frame*/
			if (p_stElt3d == p_stStopElt3d)
			{
				/* reached the end of second array*/
				p_stNewChannel = NULL;
			}
			else
			{
				/* check if next frame channels are sorted*/
#if defined(ANIM_DEBUG) && defined(U64)
				if(!(p_stElt3d->ucChannelNumber == C_ucUnknownChannel || p_stElt3d->ucChannelNumber > ulNextChannelNumber))
				{
					if(p_stElt3d->ucChannelNumber == C_ucUnknownChannel)
						osSyncPrintf("Unknown channel\n");
					else
						osSyncPrintf("Error channel bad sorted\n");
					osSyncPrintf("Anim : %d, Frame : %d, Channel : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,_uwFrameNumber,p_stElt3d->ucChannelNumber);
				}
#endif
#ifndef RETAIL
				ENGassert(p_stElt3d->ucChannelNumber == C_ucUnknownChannel || p_stElt3d->ucChannelNumber > ulNextChannelNumber);
#endif
				ulNextChannelNumber = p_stElt3d->ucChannelNumber;
				p_stNewChannel = (ulNextChannelNumber == C_ucUnknownChannel) ? NULL : hChannelArray + ulNextChannelNumber;
			}
		}
		/* the case p_stLastFrameChannel == NULL will never happen here...*/
		/* because it is treated in previous if... so I removed it !*/
		else if (p_stNewChannel == NULL || p_stLastFrameChannel < p_stNewChannel)
		{
			/* there is a channel that is active in previous frame, and that is not*/
			/* active any more in next frame...*/
			/* so let's disactive it !*/
 
			if (p_stLastFrameChannel->hZoomSupObject)
			{
				/* it was a zoomed channel, so destroy its zoom matrix*/
/*				PLA_fn_vReleaseMatrixInHeap(HIE_fn_hGetSuperObjectMatrix(p_stLastFrameChannel->hZoomSupObject));*/
				/* destroy the zoom SO*/
				LST2_M_DynamicIsolate(p_stLastFrameChannel->hZoomSupObject);
				PLA_fn_vReleaseSuperObjectInHeap(p_stLastFrameChannel->hZoomSupObject);
				p_stLastFrameChannel->hZoomSupObject = NULL;
			}
			/* Add on: kill all father-sons links*/
			/* ???*/
/*			{
				HIE_tdxHandleToSuperObject hChild;
				ACP_tdxIndex xChildIndex;
 
				HIE_M_ForEachChildOf(p_stLastFrameChannel->hSupObject,hChild,xChildIndex)
				{
					if(HIE_fn_ulGetSuperObjectType(hChild) == C_ucCharacter )
					{
						fn_vReputCharacterSuperObjectAtTheWorld(hChild);
					}
				}
			}
*/			/* then detroy the channel SO*/
			LST2_M_DynamicIsolate(p_stLastFrameChannel->hSupObject);
			PLA_fn_vReleaseSuperObjectInHeap(p_stLastFrameChannel->hSupObject);
			p_stLastFrameChannel->hSupObject = NULL;
			/* now update the links*/
			if (p_stLastFrameChannelForLink)
			{
				/* there was a previous active channel !*/
				/* so (previous active channel's next active channel) is the (destroyed channel's next active channel) (it is clear !!)*/
				p_stLastFrameChannelForLink->p_stNextActiveChannel = p_stLastFrameChannel->p_stNextActiveChannel;
			}
			else
			{
				/* there was no previous active channel, so we disactivated the first channel !*/
				fn_v3dDataSetFirstActiveChannel(h_Current3dData, p_stLastFrameChannel->p_stNextActiveChannel);
			}
			/* and now, go to next step... that is advance one in the last frame channel array*/
			/* check if previous frame active channel links are sorted*/
#if defined(ANIM_DEBUG) && defined(U64)
			if((p_stLastFrameChannel->p_stNextActiveChannel != NULL) && (p_stLastFrameChannel->p_stNextActiveChannel <= p_stLastFrameChannel))
			{
				osSyncPrintf("Error channel bad sorted\n");
				osSyncPrintf("Anim : %d, Frame : %d\n",p_stCurrentAnim->uwNumOfA3dGENERAL,_uwFrameNumber);
			}
#endif
#ifndef RETAIL
			ENGassert(p_stLastFrameChannel->p_stNextActiveChannel == NULL || p_stLastFrameChannel->p_stNextActiveChannel > p_stLastFrameChannel);
#endif
			p_stLastFrameChannel = p_stLastFrameChannel->p_stNextActiveChannel;
		}
	}
}
 
 
 
 
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
 
 
 
/* Modif : 22/04/98 Stop morphing before freeing an element - Carlos Torres*/
/* Modif : 15/05/98 Release Matrix for custom zoom channels - Carlos Torres*/
void PLA_fn_vDesInitAllChildOfCharacter(HIE_tdxHandleToSuperObject p_stSuperObject, struct tdstEngineObject_ *p_stObject)
{
	MS_tdxHandleTo3dData  h_Current3dData;
	tdstAChannel *p_stChannel;
	tdstAnim3d  *p_stCurrentAnim = NULL; 
	CHN_tdxHandleToChannelArray hArray;
#ifdef U64
	tdstCouple *p_stCouples;
	struct tdstFrame3d_* p_stCurrentFrame3d;
#endif
 
	if (p_stObject == NULL)
		return;
 
	h_Current3dData = p_stObject->h_3dData;
 
	if (fn_h3dDataGetCurrentState(h_Current3dData))
		p_stCurrentAnim = fn_h3dDataGetCurrentState(h_Current3dData)->p_stAnim;
 
	p_stChannel = fn_h3dDataGetFirstActiveChannel(h_Current3dData);
	hArray = fn_h3dDataGetChannelSOList(h_Current3dData);
	if (hArray)
	{
		while (p_stChannel)
		{
			/* For Morphing Anim and channel morphed --> stop morphing*/
			if(p_stSuperObject && p_stCurrentAnim && p_stCurrentAnim->d_stMorphDataArray)
				MOR_fn_xStopMorph(p_stSuperObject,(short)(p_stChannel - hArray));
			
			/* release matrix and hierarchy for symetric module*/
			if (p_stChannel->hZoomSupObject)
			{
				/* release zoom matrix*/
				/*			PLA_fn_vReleaseMatrixInHeap(HIE_fn_hGetSuperObjectMatrix(p_stChannel->hZoomSupObject));*/
				/* isolate zoom SO*/
				LST2_M_DynamicIsolate(p_stChannel->hZoomSupObject);
				/* release zoom SO*/
				PLA_fn_vReleaseSuperObjectInHeap(p_stChannel->hZoomSupObject);
				p_stChannel->hZoomSupObject = NULL;
			}
			/* release normal module...*/
			if(p_stChannel->hSupObject) /*AR9901*/
			{
				LST2_M_DynamicIsolate(p_stChannel->hSupObject);
				PLA_fn_vReleaseSuperObjectInHeap(p_stChannel->hSupObject);
				p_stChannel->hSupObject = NULL;
			}
			p_stChannel = p_stChannel->p_stNextActiveChannel;
		}
	}
	/* JO 09/01/98*/
	fn_v3dDataSetSkipCurrentFrame(h_Current3dData,FALSE);
	/* stop playing events and desinit*/
	if (p_stSuperObject)
		fn_vDesInitAllEvents(p_stSuperObject,NULL,TRUE);
 
	/* delete the channels array !*/
	fn_vFreeCSOList(&hArray);
	fn_v3dDataSetChannelSOList(h_Current3dData,NULL);
	fn_v3dDataSetFirstActiveChannel(h_Current3dData,NULL);
 
	fn_vFreeArrayOfElts3d (h_Current3dData);
 
	fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAnim = NULL;
#ifndef U64
	if (fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAngularSpeedMatrix)
	{
		MMG_fn_vAddMemoryInfo( MMG_C_lTypeInterpol , MMG_C_lSubTypeSpeedMatrix , 0 );
		TMP_M_Free(fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAngularSpeedMatrix);
		fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAngularSpeedMatrix = NULL;
	}
#endif /*U64*/
#ifdef U64
	p_stCouples=fn_p_st3dDataGetCurrentHieCouples(h_Current3dData);
	if(p_stCouples!=NULL)
	{
		MMG_fn_vAddMemoryInfo( MMG_C_lTypeInterpol , MMG_C_lSubTypeHierarchies , 0 );
		TMP_M_Free(p_stCouples);		
	}
	p_stCurrentFrame3d = fn_p_st3dDataGetCurrentFrame(h_Current3dData);
	p_stCurrentFrame3d->stHierarchy.d_stCouples=NULL;
#endif /*U64*/
    fn_v3dDataSetCurrentHieCouples(h_Current3dData,NULL);
	fn_v3dDataSetCurrentHieNbCouples(h_Current3dData,0);
	fn_v3dDataSetFlagModifState(h_Current3dData,TRUE);
	fn_v3dDataSetSkipCurrentFrame(h_Current3dData,FALSE);
}
 
 
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
void PLA_fn_vRefreshGlobalMatrixUnderCharacter(HIE_tdxHandleToSuperObject _hSprObj)
{
	long i;
	HIE_tdxHandleToSuperObject hChild;
 
/* ANNECY MT - 06/10/98 {*/
	if(fn_ulStandardGameGetCustomBitsSO(_hSprObj) & GAM_C_CustBitNeedModuleMatrices)
	{
		HIE_M_ForEachChildOf(_hSprObj, hChild, i)
			PLA_fn_vRefreshGlobalMatrixOfAnimsHierarchy(hChild);
	}
/* END ANNECY MT }*/
}
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
void PLA_fn_vRefreshGlobalMatrixOfAnimsHierarchy(HIE_tdxHandleToSuperObject _hSprObj)
{
	long i;
	register long lType;
	HIE_tdxHandleToSuperObject hChild;
 
	lType = HIE_fn_ulGetSuperObjectType(_hSprObj);
 
	if(lType & (HIE_C_ulSuperObject | HIE_C_ulPO | HIE_C_ulPO_Mirror ))
	{
		POS_fn_vMulMatrixMatrix(HIE_fn_hGetSuperObjectGlobalMatrix(_hSprObj),HIE_fn_hGetSuperObjectGlobalMatrix(HIE_fn_hGetSuperObjectFather(_hSprObj)),HIE_fn_hGetSuperObjectMatrix(_hSprObj));
#ifdef ACTIVE_EDITOR
		_hSprObj->llastComputeFrameForModule = HIE_gs_lCurrentFrame;
#endif
	}
	else return;
 
	HIE_M_ForEachChildOf(_hSprObj, hChild, i)
		PLA_fn_vRefreshGlobalMatrixOfAnimsHierarchy(hChild);
 
}
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
 
/*            ######################################################################## */
/*        ############################################################################ */
/*      ########################## MANAGMENT of Anim's Datas ######################### */
/*     ############################################################################### */
/*     ############################################################################### */
/*     #########                                                                       */
/* #################                                                                   */
/*   #############                                                                     */
/*     #########                                                                       */
/*       #####                                                                         */
/*         #                                                                           */
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/* Set New State*/
/*ANNECY CT 11/02/98{*/
/* Modif 26/03/98 CT Reinit flag end of anim*/
/* Modif 15/05/98 CT Stop morphing of the current anim*/
/* Modif 29/09/98 BNT can force the change if required*/
ACP_tdxBool PLA_fn_bSetNewState(HIE_tdxHandleToSuperObject p_stSuperObject,tdxHandleToState  h_WantedState, ACP_tdxBool _bForce , ACP_tdxBool _bHandleSkippedEventsIfRelevant )
{
	MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	tdxHandleToState  h_ResultState;
	tdxHandleToTransition  h_Transition;
 
	/*fn_v3dDataSetNbEngineFrameSinceLastMechEvent(h_Current3dData,LME_INVALID);*/
 
	if( (h_WantedState == fn_h3dDataGetFirstStateOfAction(h_Current3dData)) && !_bForce )
		return(TRUE);
 
	h_Transition = fn_hIfExistTransitionalWithTargetState(fn_h3dDataGetWantedState(h_Current3dData),h_WantedState);
 
#ifdef _DEBUG
	if (h_Transition && !fn_hGetStateToGoInTransition(h_Transition)->p_stAnim) {
		ENGassert(0);
		h_Transition = NULL;
	}
#endif
 
	if(h_Transition==NULL)
	{
		if(fn_hIfExistProhibitedState(fn_h3dDataGetWantedState(h_Current3dData),h_WantedState))	return(FALSE);
		if(fn_h3dDataGetWantedState(h_Current3dData)->ucTransitionStatusFlag == C_ucProhibitedState) return(FALSE);
		else h_ResultState = h_WantedState;
	}
	else h_ResultState = fn_hGetStateToGoInTransition(h_Transition);
 
	/* stop morphing before changing state and animation*/
	PLA_fn_vStopCurrentMorphAnim(p_stSuperObject);
 
	if( h_Transition && (fn_ucGetLinkingTypeInTransition(h_Transition) == C_ucProportionalLink))
	{
		unsigned long ulForcedFrame,ulNewStartTime;
 
		/* compute the proportional frame*/
		ulForcedFrame = fn_uw3dDataGetCurrentFrame(h_Current3dData);
		ulForcedFrame *= h_ResultState->p_stAnim->uwNumberOfFrames;
		ulForcedFrame /= fn_h3dDataGetCurrentState(h_Current3dData)->p_stAnim->uwNumberOfFrames;
		if(ulForcedFrame>=h_ResultState->p_stAnim->uwNumberOfFrames)
			ulForcedFrame=h_ResultState->p_stAnim->uwNumberOfFrames-1;
 
		/* set fictive anim start time*/
		ulNewStartTime = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount-fn_ul3dDataGetStartTime(h_Current3dData);
		ulNewStartTime *= h_ResultState->p_stAnim->uwNumberOfFrames;
		ulNewStartTime /= fn_h3dDataGetCurrentState(h_Current3dData)->p_stAnim->uwNumberOfFrames;
		ulNewStartTime = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount - ulNewStartTime;
		fn_v3dDataSetStartTime(h_Current3dData,ulNewStartTime);
		/* force the frame*/
		fn_v3dDataSetForcedFrame(h_Current3dData,(unsigned short)ulForcedFrame);
		fn_v3dDataSetLastFrame(h_Current3dData,(unsigned short)ulForcedFrame);
		/* set fictive time for previous frame*/
		fn_v3dDataSetTimePreviousFrame(h_Current3dData,
			fn_ul3dDataGetStartTime(h_Current3dData)+ulForcedFrame*1000/fn_scGetSpeedInState(h_ResultState));
		/* next frame must not be skipped !! */
		fn_v3dDataSetSkipCurrentFrame(h_Current3dData,FALSE);
	}
	else
	{
		fn_v3dDataSetTimeDelay(h_Current3dData,0);
		fn_v3dDataSetCurrentFrame(h_Current3dData,0);
		fn_v3dDataSetTimePreviousFrame(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount);
		/* next frame must not be skipped !! */
		fn_v3dDataSetSkipCurrentFrame(h_Current3dData,FALSE);
	}
 
	/* MR1906*/
	fn_v3dDataSetNbEngineFrameSinceLastMechEvent(h_Current3dData,LME_INVALID);
 
	fn_v3dDataSetStateInLastFrame(h_Current3dData,fn_h3dDataGetCurrentState(h_Current3dData));
	fn_v3dDataSetWantedState(h_Current3dData,h_ResultState);
	fn_v3dDataSetFirstStateOfAction(h_Current3dData,h_WantedState);
	fn_v3dDataSetFlagModifState(h_Current3dData,TRUE);
 
	/* reinit flag end of anim*/
	fn_v3dDataSetFlagEndOfAnim(h_Current3dData,(unsigned char)
		(fn_uw3dDataGetForcedFrame(h_Current3dData) == h_ResultState->p_stAnim->uwNumberOfFrames));
 
	PLA_fn_bDoAnimPlayerForCharacter(p_stSuperObject , FALSE , _bHandleSkippedEventsIfRelevant);
 
	return TRUE;
}
/*ENDANNECY CT}*/
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
ACP_tdxBool PLA_fn_bSetNewStateWithRandom(HIE_tdxHandleToSuperObject p_stSuperObject,tdxHandleToState h_WantedState)
{
	MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
  tdxHandleToState  h_ResultState = NULL;
  struct tdstAnim3d_ *p_stNextAnim;
  unsigned short uwFrameNumber;
	tdxHandleToTransition  h_Transition;
 
  if(h_WantedState==fn_h3dDataGetFirstStateOfAction(h_Current3dData))  return(TRUE);
 
  h_Transition = fn_hIfExistTransitionalWithTargetState(fn_h3dDataGetWantedState(h_Current3dData),h_WantedState);
 
  if(h_ResultState==NULL) {
		if(fn_hIfExistProhibitedState(fn_h3dDataGetWantedState(h_Current3dData),h_WantedState))	return(FALSE);
		if(fn_h3dDataGetWantedState(h_Current3dData)->ucTransitionStatusFlag == C_ucProhibitedState) return(FALSE);
		else h_ResultState = h_WantedState;
  }
  else h_ResultState = fn_hGetStateToGoInTransition(h_Transition);
 
  /* MR1906*/
  fn_v3dDataSetNbEngineFrameSinceLastMechEvent(h_Current3dData,LME_INVALID);
  /* MR1709*/
  fn_v3dDataSetStartTime(h_Current3dData,0);
 
  fn_v3dDataSetStateInLastFrame(h_Current3dData,fn_h3dDataGetCurrentState(h_Current3dData));
  fn_v3dDataSetWantedState(h_Current3dData,h_ResultState);
  fn_v3dDataSetFirstStateOfAction(h_Current3dData,h_WantedState);
  fn_v3dDataSetFlagModifState(h_Current3dData,TRUE);
 
  p_stNextAnim = fn_h3dDataGetWantedState(h_Current3dData)->p_stAnim;
  uwFrameNumber = (unsigned char)RND_fn_ulGetUnsignedLongRandomValue(g_Randomhandle,0,p_stNextAnim->uwNumberOfFrames-1);
  fn_v3dDataSetForcedFrame(h_Current3dData,uwFrameNumber);
  fn_v3dDataSetLastFrame(h_Current3dData,(short)(uwFrameNumber-1));
  fn_v3dDataSetTimeDelay(h_Current3dData,0);
  fn_v3dDataSetTimePreviousFrame(h_Current3dData,g_stEngineStructure.stEngineTimer.ulCurrentTimerCount);
 
  PLA_fn_bDoAnimPlayerForCharacter(p_stSuperObject,FALSE,FALSE);
 
  return(TRUE);
}
 
/*********************************************************************
* Function : PLA_fn_vSetCurrFrame                                    *
*	Set the frame specified in the current anim or compute a random  *
*	frame if frame specified is PLA_C_lRandomFrame                   *
* Create: 17/02/98	Author  : Carlos Torres                          µ
**********************************************************************/
void PLA_fn_vSetCurrFrame(HIE_tdxHandleToSuperObject p_stSuperObject, short _wFrame)
{
	MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	unsigned short uwMaxFrame=(unsigned short)(fn_h3dDataGetCurrentState(h_Current3dData)->p_stAnim->uwNumberOfFrames);
  unsigned char ucFrameRate = fn_uc3dDataGetFrameRate(h_Current3dData), ucFrameRate2 = ucFrameRate;
 
	/* compute random frame*/
	if (_wFrame == PLA_C_wRandomFrame)
	{
		_wFrame=(short) RND_fn_ulGetUnsignedLongRandomValue(g_Randomhandle,0,uwMaxFrame-1);
	}
	/* Frame must be < NbFrame*/
	else
	{
		if ( _wFrame < 0 )
		{
			_wFrame = 0;
		}
		else if ( _wFrame >= uwMaxFrame )
		{
			_wFrame = (short) (uwMaxFrame - 1);
		}
	}
 
	/* change forced frame*/
	fn_v3dDataSetForcedFrame(h_Current3dData, _wFrame);
	fn_v3dDataSetLastFrame(h_Current3dData, (short)(_wFrame - 1));
	/* simulate a changing of state*/
	fn_v3dDataSetFlagModifState(h_Current3dData,TRUE);
	fn_v3dDataSetWantedState(h_Current3dData,fn_h3dDataGetCurrentState(h_Current3dData));
	/* reinit flag in case we have reached the end*/
	fn_v3dDataSetFlagEndOfAnim(h_Current3dData,FALSE);
	fn_v3dDataSetFlagEndState(h_Current3dData,FALSE);
 
  if ( ! ucFrameRate )
  {
    /*set a non-null frame rate so that the anim player does something for us*/
    ucFrameRate2 = fn_scGetSpeedInState(fn_h3dDataGetCurrentState(h_Current3dData));
    fn_v3dDataSetFrameRate(h_Current3dData, ucFrameRate2);
  }
 
  /* we can set fictive start time and previous compute frame*/
	fn_v3dDataSetStartTime(h_Current3dData,
    g_stEngineStructure.stEngineTimer.ulCurrentTimerCount - (1000 * _wFrame) / ucFrameRate2
  );
	fn_v3dDataSetTimePreviousFrame(h_Current3dData,
    g_stEngineStructure.stEngineTimer.ulCurrentTimerCount - 1000 / ucFrameRate2
  );
 
  /*change the frame*/
	PLA_fn_bDoAnimPlayerForCharacter(p_stSuperObject,FALSE,FALSE);
 
  /*reset the previous frame rate*/
  fn_v3dDataSetFrameRate(h_Current3dData, ucFrameRate);
}
 
/*********************************************************************
* Function : PLA_fn_uwGetNbFrameInCurrAnim                           *
*	Return number of frame in the current anim of the charcter       *
* Author  : Carlos Torres                                            *
* Date of last modification: 17/02/98                                *
**********************************************************************/
unsigned short PLA_fn_uwGetNbFrameInCurrAnim(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
 
	return fn_h3dDataGetCurrentState(h_Current3dData)->p_stAnim->uwNumberOfFrames;
}
 
/*********************************************************************
* Function : PLA_fn_uwGetCurrFrameOfAnim                             *
*	Return the current frame of the anim                             *
* Author  : Carlos Torres                                            *
* Date of last modification: 12/03/98                                *
**********************************************************************/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 04/06/99 */
unsigned short PLA_fn_uwGetCurrFrameOfAnim(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
 
	return fn_uw3dDataGetCurrentFrame(h_Current3dData);
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 04/06/99 */

 
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/* Init New State*/
/* Modif : 22/04/98 Reset frame of current anim at init - Carlos Torres*/
BOOL PLA_fn_vInitNewState(HIE_tdxHandleToSuperObject p_stSuperObject,tdxHandleToState  h_State)
{
	MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
 
	/*if(p_stCurrent3dData->p_stFamily->d_stState == NULL ) return; // unknown object*/
	if(LST2_M_StaticGetFirstElement(&(fn_h3dDataGetFamily(h_Current3dData)->hForStateArray)) == NULL )
		return(FALSE);
 
	fn_v3dDataSetFlagEndState(h_Current3dData,FALSE);
	fn_v3dDataSetFlagModifState(h_Current3dData,TRUE);
	/*fn_v3dDataSetFlagInitState(h_Current3dData,TRUE);*/
 
	/* Reset frame*/
	fn_v3dDataSetCurrentFrame(h_Current3dData,0);
	fn_v3dDataSetLastFrame(h_Current3dData,0);
 
	fn_v3dDataSetWantedState(h_Current3dData,h_State);
	/*if(fn_h3dDataGetCurrentState(h_Current3dData)==NULL)*/
 
	/* set new state, so init frame array*/
/* ANNECY MT - 22/09/98 {*/
	/*
	if (fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d != NULL)
	{
		// normally, this should be NULL, but it may happen when the B-mode is started...
        MMG_fn_vAddMemoryInfo( MMG_C_lTypeFamily , MMG_C_lSubTypeAnimation , h_Current3dData->h_Family);
		TMP_M_Free(fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d);
	}
	// and init array
	if (h_State->p_stAnim)
	{
        MMG_fn_vAddMemoryInfo( MMG_C_lTypeFamily , MMG_C_lSubTypeAnimation , h_Current3dData->h_Family);
		fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d = (tdstElement3d*)TMP_M_p_Malloc(sizeof(tdstElement3d) * h_State->p_stAnim->ucMaxNumberOfElements);
		memset(fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d,0,sizeof(tdstElement3d) * h_State->p_stAnim->ucMaxNumberOfElements);
		fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAnim = NULL;
	}
	*/
	if (h_State->p_stAnim)
	{
		fn_vAllocArrayOfElts3d (h_Current3dData , h_State->p_stAnim->ucMaxNumberOfElements);
	}
	else
	{
		fn_vFreeArrayOfElts3d (h_Current3dData);
	}
/* END ANNECY MT }*/
 
	fn_v3dDataSetCurrentState(h_Current3dData,h_State);
	fn_vUpdateCurrentActivationForCharacter(p_stSuperObject);
	fn_v3dDataSetFirstStateOfAction(h_Current3dData,h_State);
	fn_v3dDataSetFrameRate(h_Current3dData,fn_scGetSpeedInState(h_State));
	if(h_State->p_stAnim) 	
		fn_vInitAllEvents(p_stSuperObject,0);
	return(TRUE);
}
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 04/06/99 */
BOOL PLA_fn_bInitNewStateWithRandom(HIE_tdxHandleToSuperObject p_stSuperObject,tdxHandleToState  h_WantedState)
{
	MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	struct tdstAnim3d_ *p_stCurrentAnim;
  BOOL test;
 
	test = PLA_fn_vInitNewState(p_stSuperObject,h_WantedState);
	if(test)
  {
    p_stCurrentAnim = fn_h3dDataGetCurrentState(h_Current3dData)->p_stAnim;
    fn_v3dDataSetForcedFrame(h_Current3dData,(unsigned char)RND_fn_ulGetUnsignedLongRandomValue(g_Randomhandle,0,p_stCurrentAnim->uwNumberOfFrames-1));
    return(TRUE);
  }
	return(FALSE);
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 04/06/99 */

/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 04/06/99 */
void PLA_fn_vModifyCurrentState(HIE_tdxHandleToSuperObject p_stSuperObject,tdxHandleToState  h_State)
{
  MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
 
  fn_v3dDataSetFlagEndState(h_Current3dData,FALSE);
	fn_v3dDataSetFlagEndOfAnim(h_Current3dData,FALSE);
  fn_v3dDataSetFlagModifState(h_Current3dData,TRUE);
/*  fn_v3dDataSetFlagInitState(h_Current3dData,TRUE);*/
 
  fn_v3dDataSetWantedState(h_Current3dData,h_State);
	fn_v3dDataSetFirstStateOfAction(h_Current3dData,h_State);
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 04/06/99 */

/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/* Test New State*/
BOOL PLA_fn_bTestNewState(HIE_tdxHandleToSuperObject p_stSuperObject,tdxHandleToState  h_WantedState)
{
  MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
  /*tdxHandleToState  h_ResultState;*/
  tdxHandleToTransition  h_Transition;
 
  if(h_WantedState==fn_h3dDataGetFirstStateOfAction(h_Current3dData))  return(TRUE);
 
 
  /*h_ResultState = fn_hIfExistTransitionalWithTargetState(fn_h3dDataGetWantedState(h_Current3dData),h_WantedState);*/
  h_Transition = fn_hIfExistTransitionalWithTargetState(fn_h3dDataGetWantedState(h_Current3dData),h_WantedState);
 
	/*if(h_ResultState==NULL)*/
	if(h_Transition==NULL)
	{
		if(fn_hIfExistProhibitedState(fn_h3dDataGetWantedState(h_Current3dData),h_WantedState))	return(FALSE);
		if(fn_h3dDataGetWantedState(h_Current3dData)->ucTransitionStatusFlag == C_ucProhibitedState) return(FALSE);
	}
 
  return(TRUE);
}
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/* Test New State*/
BOOL PLA_fn_bTestCurrentAction(HIE_tdxHandleToSuperObject p_stSuperObject,tdxHandleToState  h_FirstStateOfAction)
{
  MS_tdxHandleTo3dData   h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
 
  if(h_FirstStateOfAction==fn_h3dDataGetFirstStateOfAction(h_Current3dData))  return(TRUE);
 
  return(FALSE);
}
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
 
 
 
 
/*            ######################################################################## */
/*        ############################################################################ */
/*      ########################## MANAGMENT of STATES STATUS ####################### */
/*     ############################################################################### */
/*     ############################################################################### */
/*     #########                                                                       */
/* #################                                                                   */
/*   #############                                                                     */
/*     #########                                                                       */
/*       #####                                                                         */
/*         #                                                                           */
 
 
 
/* Access Functions for Speed. CGHT 12/02/97*/
/* MR0605: Add speed of skipped frames (warning: if the end of an anim is skipped, only the speeds of the new anim is taking into account*/
/* CGHT 04/06/97 : Add Empty list support.*/
/* Modif : continuous speed Carlos Torres 21/04/98*/
struct MTH3D_tdstVector_ * PLA_fn_stGetLinearSpeedVector(HIE_tdxHandleToSuperObject p_stSuperObject,short sLastFrame)
{
	MS_tdxHandleTo3dData			h_Current3dData;
	struct tdstState_				*p_stCurrentState;
	struct tdstAnim3d_				*p_stCurrentAnim;
	static struct MTH3D_tdstVector_ stSpeedVector;
/*	struct tdstFrame3d_				*p_stCurrentFrame3d;*/
	int i;
 
	h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	p_stCurrentState = fn_h3dDataGetCurrentState(h_Current3dData);
	p_stCurrentAnim = p_stCurrentState->p_stAnim;
 
	if(p_stCurrentAnim!=NULL)
	{
		MTH3D_tdstVector * p_stVector;
		int iFramePassed;
		MTH_tdxReal xInvFramePassed;
 
#ifdef DISCREET_SPEED
		MTH3D_M_vFillVector(&stSpeedVector,0);
 
		/* compute covered distance for all frame passed*/
		for (i=sLastFrame+1;i<=fn_uw3dDataGetCurrentFrame(h_Current3dData);i++)
		{
			p_stVector = fn_p_stGetLinearSpeedVector(p_stCurrentAnim,i);
			if (p_stVector)
			{
				MTH3D_M_vAddVector(&stSpeedVector,&stSpeedVector,);
			}
		}
		/* compute speed*/
		MTH3D_M_vMulScalarVector(&stSpeedVector,MTH_M_xInv(M_xGetUsefulDeltaTimeInSeconds(g_stEngineStructure.stEngineTimer)),&stSpeedVector);
#else /* DISCREET_SPEED */
		iFramePassed=1;
 
		p_stVector = fn_p_stGetLinearSpeedVector(p_stCurrentAnim,fn_uw3dDataGetCurrentFrame(h_Current3dData));
		if (p_stVector)
		{
			MTH3D_M_vCopyVector(&stSpeedVector,p_stVector);
		}
		else
		{
			MTH3D_M_vFillVector(&stSpeedVector,0);
		}
 
		/* compute covered distance for all frame passed*/
		for (i=sLastFrame+1;i<fn_uw3dDataGetCurrentFrame(h_Current3dData);i++,iFramePassed++)
		{
/*			fn_vUpdateFrame(p_stSuperObject,p_stCurrentFrame3d,p_stCurrentAnim,i);*/
			p_stVector = fn_p_stGetLinearSpeedVector(p_stCurrentAnim,(unsigned short)i);
			if (p_stVector)
			{
				MTH3D_M_vAddVector(&stSpeedVector,&stSpeedVector,p_stVector);
			}
		}
		xInvFramePassed = MTH_M_xInv((MTH_tdxReal)iFramePassed);
		/* average distance per frame for all frame skipped*/
		MTH3D_M_vMulScalarVector(&stSpeedVector,xInvFramePassed,&stSpeedVector);
		/* compute speed*/
		MTH3D_M_vMulScalarVector(&stSpeedVector,fn_uc3dDataGetFrameRate(h_Current3dData),&stSpeedVector);
#endif /* DISCREET_SPEED */
		return &stSpeedVector;
	}
	else
		return NULL;
}
 
 
 
 
struct MTH3D_tdstMatrix_ * PLA_fn_stGetAngularSpeedMatrix(HIE_tdxHandleToSuperObject p_stSuperObject,short sLastFrame)
{
	MS_tdxHandleTo3dData	h_Current3dData;
	struct tdstState_		*p_stCurrentState;
	tdstAnim3d				*p_stCurrentAnim;
	static struct MTH3D_tdstMatrix_ stSpeedMatrix;
/*	struct tdstFrame3d_				*p_stCurrentFrame3d;*/
	int i;
	ACP_tdxBool bSpeedMatrix = FALSE;
 
	h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
	p_stCurrentAnim   = p_stCurrentState->p_stAnim;
 
	if(p_stCurrentAnim!=NULL)
	{
		MTH3D_tdstMatrix	stMatrix;
 
		MTH3D_M_vSetIdentityMatrix(&stSpeedMatrix);
		for (i=sLastFrame+1 ; i<=fn_uw3dDataGetCurrentFrame(h_Current3dData) ; i++)
		{
			if (fn_p_stGetAngularSpeedMatrix(p_stCurrentAnim,(unsigned short)i,&stMatrix))
			{
				MTH3D_M_vMulMatrixMatrix(&stSpeedMatrix,&stSpeedMatrix,&stMatrix);
				bSpeedMatrix=TRUE;
			}
		}
/*		return &stSpeedMatrix;*/
	}
/*	else*/
/*	{*/
/*		return NULL;*/
/*	}*/
	return bSpeedMatrix ? &stSpeedMatrix : NULL;
}
 
BOOL PLA_fn_bTestIfEndOfAction(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
 
	if(    fn_uc3dDataGetFlagEndState(h_Current3dData)
		&& fn_h3dDataGetCurrentState(h_Current3dData)==fn_h3dDataGetWantedState(h_Current3dData) )
	{
		return(TRUE);
	}
	return(FALSE);
}
 
BOOL PLA_fn_bTestIfEndOfAnim(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	if( fn_uc3dDataGetFlagEndOfAnim(M_GetMSHandle(p_stSuperObject,3dData)) ) return(TRUE);
	return(FALSE);
}
 
/*********** TMP *******************/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 04/06/99 */
void PLA_fn_vInitNewAction(HIE_tdxHandleToSuperObject p_stSuperObject,unsigned short wAction)
{
	struct tdstState_  *p_stTmpState;
	long i;
 
	LST2_M_StaticGetElementNumber(&(fn_h3dDataGetFamily(M_GetMSHandle(p_stSuperObject,3dData))->hForStateArray)
		,p_stTmpState,wAction,i);
	PLA_fn_vInitNewState(p_stSuperObject,p_stTmpState);
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 04/06/99 */

 
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/* **************************************************************************************/
/* *  Description :   Change frame of current anim, and change anim if we have reached **/
/* *									end, Make sure that fn_vDoAnim is not called for objects without **/
/* *									Anim or State                                                    **/
/* *===================================================================================**/
/* *-----------------------------------------------------------------------------------**/
/* *  Creation date : 27/07/97            Author : DVD (Gizmo)                         **/
/* **************************************************************************************/
 
#ifdef ACTIVE_EDITOR
BOOL PLA_fn_bDoFirstInitOfAnimPlayerForCharacter(HIE_tdxHandleToSuperObject p_stSuperObject, tdstAnim3d *p_stNewAnim)
{
	MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	struct tdstState_  *p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
	struct tdstAnim3d_ *p_stCurrentAnim;
	/*unsigned char         FlagModifyState;*/
	/*  tdstSubAnim3d         stTmpSubAnim;*/
	BOOL bDidChangeState = FALSE;
	/* MR2204*/
	unsigned long ulAddFrames=0;
 
	/* MR0407*/
	/*unsigned short uwAddFrame;*/
	/*unsigned char ucStateSpeed;		// MR2407*/
 
	if (p_stCurrentState==NULL)
		return FALSE; /* not a good object !!! mettre un message d'erreur !!! ...*/
 
	p_stCurrentAnim   = p_stCurrentState->p_stAnim;
 
	/* for instance : a camera ...*/
	if (p_stNewAnim==NULL)  return TRUE;
	
	fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAnim = NULL;
 
	/*	update the stCurrent3dData structure*/
	if(fn_uc3dDataGetFlagModifState(h_Current3dData) == TRUE || p_stCurrentAnim != p_stNewAnim)
	{
		if (p_stCurrentAnim->ucMaxNumberOfElements != p_stNewAnim->ucMaxNumberOfElements || fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d == NULL)
		{
/* ANNECY MT - 22/09/98 {*/
			/*
			if (fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d)
			{
                MMG_fn_vAddMemoryInfo( MMG_C_lTypeFamily , MMG_C_lSubTypeAnimation , h_Current3dData->h_Family);
				TMP_M_Free(fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d);
			}
            MMG_fn_vAddMemoryInfo( MMG_C_lTypeFamily , MMG_C_lSubTypeAnimation , h_Current3dData->h_Family);
			fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d = (tdstElement3d*)TMP_M_p_Malloc(sizeof(tdstElement3d) * p_stNewAnim->ucMaxNumberOfElements);
			memset(fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stArrayOfElts3d,0,sizeof(tdstElement3d) * p_stNewAnim->ucMaxNumberOfElements);
			*/
			fn_vAllocArrayOfElts3d (h_Current3dData , p_stNewAnim->ucMaxNumberOfElements);
/* END ANNECY MT }*/
			fn_p_st3dDataGetCurrentFrame(h_Current3dData)->p_stAnim = NULL;
		}
		fn_v3dDataSetFlagModifState(h_Current3dData,FALSE);
/*		fn_v3dDataSetCurrentHieCouples(h_Current3dData,NULL);*/
/*		fn_v3dDataSetCurrentHieNbCouples(h_Current3dData,0);*/
/*		fn_v3dDataSetFirstActiveChannel(h_Current3dData,NULL);*/
	}
 
	p_stCurrentState->p_stAnim = p_stNewAnim;
 
	PLA_fn_vInitAllChildInHeapNewAnim(p_stSuperObject,p_stNewAnim,fn_uw3dDataGetCurrentFrame(h_Current3dData));
 
	PLA_fn_vDoFrame(p_stNewAnim,fn_uw3dDataGetCurrentFrame(h_Current3dData),p_stSuperObject);
	/* last event played is set correctly by*/
	/* - previous call to this function*/
	/* - init of all events*/
	/* - call to fn_vPlayLastEventsBeforeRestart() for previous loop of the same anim*/
/*	fn_vPlayEventsSinceLastOneNoLoop( p_stSuperObject );*/
	
	
	/* Takes the speed in the anim and transfers it to the mechanics*/
	/*fn_vTransferSpeedInformationPLA_DNM(p_stSuperObject,ucLastFrame);*/
/*	fn_vTransferSpeedInformationPLA_DNM(p_stSuperObject,fn_s3dDataGetLastFrame(h_Current3dData));*/
	
	/*fn_v3dDataSetLastFrame(h_Current3dData,fn_uc3dDataGetCurrentFrame(h_Current3dData));*/
 
	return TRUE;
}
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
void PLA_fn_bDoOffsetFirstInitForCharacter(HIE_tdxHandleToSuperObject p_stSuperObject)
{
	MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
	struct tdstState_  *p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
	MTH3D_tdstVector stCharTransVect/*,stOffsetAnim*/;
	POS_tdstCompletePosition *p_stCharMatrix;
 
 
	/* Calcul Offset ici (MR1504)*/
	p_stCharMatrix=HIE_fn_hGetSuperObjectMatrix(p_stSuperObject);
	/*POS_fn_vGetTranslationVector(&p_stTmpState->p_stAnim->stOffsetMatrix,&stOffsetAnim);*/
	POS_fn_vGetTranslationVector(p_stCharMatrix,&stCharTransVect);
	/*MTH3D_M_vSubVector(&stCharTransVect,&stCharTransVect,&stOffsetAnim);*/
/*	POS_fn_vGetTranslationVector(&p_stCurrentState->p_stAnim->stOffsetMatrix,&stOffsetAnim);
	MTH3D_M_vAddVector(&stCharTransVect,&stCharTransVect,&stOffsetAnim); */
	MTH3D_M_vAddVector(&stCharTransVect,&stCharTransVect,&p_stCurrentState->p_stAnim->stOffsetMatrix); /*AR9811*/
	POS_fn_vSetTranslationVector(p_stCharMatrix,&stCharTransVect);
	POS_fn_vMulMatrixMatrix(HIE_fn_hGetSuperObjectGlobalMatrix(p_stSuperObject),HIE_fn_hGetSuperObjectGlobalMatrix(HIE_fn_hGetSuperObjectFather(p_stSuperObject)),p_stCharMatrix);
 
 
}
 
#endif
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
 
 
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/*POS_tdxHandleToPosition PLA_fn_hFindNextFreeMatrix(void)
{
	PLA_g_ulMaxInMatrixHeap ++;
	if ( PLA_g_ulMaxInMatrixHeap >= __PLA_NB_MAX_MATRIX__ )
		M_GameFatalError(E_uwGameNoMorePLAObj);
					  if(PLA_g_ulMaxInMatrixHeap > PLA_g_ulMaxOccupationOfMatrixHeap) PLA_g_ulMaxOccupationOfMatrixHeap++;
	while ( PLA_g_a_wStateOfMatrixHeap[PLA_g_ulCurrentPosInMatrixHeap] )
	{ // stop when PLA_g_a_wStateOfMatrixHeap[CurrentPos]
		// attention !!! __PLA_NB_MAX_MATRIX__ est une puissance de 2 !!!
		PLA_g_ulCurrentPosInMatrixHeap ++;
    if(PLA_g_ulCurrentPosInMatrixHeap == __PLA_NB_MAX_MATRIX__) PLA_g_ulCurrentPosInMatrixHeap = 0L;
	}
	PLA_g_a_wStateOfMatrixHeap[PLA_g_ulCurrentPosInMatrixHeap] = 1;
 
	return &PLA_g_d_stMatrixHeap[PLA_g_ulCurrentPosInMatrixHeap];
}
*/
 
 
 
 
 
 
 
 
 
/*void PLA_fn_vReleaseMatrixInHeap(POS_tdxHandleToPosition _hMatrix)
{
	long lPos = _hMatrix - PLA_g_d_stMatrixHeap;
	if ( (lPos < 0) || (lPos > __PLA_NB_MAX_MATRIX__) || (PLA_g_a_wStateOfMatrixHeap[lPos] == 0) )
		M_GameFatalError(E_uwGameNoMorePLAObj);
 
	PLA_g_a_wStateOfMatrixHeap[lPos] = 0;
	PLA_g_ulMaxInMatrixHeap --;
}
*/
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
 
/*.............############################################################.............*/
/*.....############################################################################.....*/
/*.####################################################################################.*/
/*void PLA_fn_vForceRegenerationWhenBlockInNoState_EndOfAction(HIE_tdxHandleToSuperObject p_stSuperObject)
{
 
  MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
  struct tdstState_  *p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
 
  if(p_stCurrentState == NULL) return;
  if(p_stCurrentState->p_stAnim == NULL) return;
 
  /* Write the last frame until animation is changed*/
  /*PLA_fn_vInitAllChildInHeapNewAnim(p_stSuperObject,p_stCurrentState->p_stAnim,(unsigned char)(p_stCurrentState->p_stAnim->uwNumberOfFrames-1));
  PLA_fn_vDoFrame(p_stCurrentState->p_stAnim,(unsigned char)(p_stCurrentState->p_stAnim->uwNumberOfFrames-1),p_stSuperObject);
}
 
void PLA_fn_vForceRegenerationWhenSkip(HIE_tdxHandleToSuperObject p_stSuperObject)
{
  MS_tdxHandleTo3dData h_Current3dData = M_GetMSHandle(p_stSuperObject,3dData);
  struct tdstState_  *p_stCurrentState  = fn_h3dDataGetCurrentState(h_Current3dData);
  unsigned short uwCurrentFrame;
 
  if(p_stCurrentState == NULL) return;
  if(p_stCurrentState->p_stAnim == NULL) return;
 
  uwCurrentFrame=fn_uw3dDataGetCurrentFrame(h_Current3dData);
  if(uwCurrentFrame == p_stCurrentState->p_stAnim->uwNumberOfFrames) uwCurrentFrame--;
 
  PLA_fn_vInitAllChildInHeapNewAnim(p_stSuperObject,p_stCurrentState->p_stAnim,uwCurrentFrame);
  PLA_fn_vDoFrame(p_stCurrentState->p_stAnim,uwCurrentFrame,p_stSuperObject);
}*/
/*.####################################################################################.*/
/*.....############################################################################.....*/
/*.............############################################################.............*/
 
#ifdef ACTIVE_EDITOR
 
extern unsigned char g_ucIsEdInGhostMode;
 
void fn_vCheckModuleAccessGam(HIE_tdxHandleToSuperObject hPerso, unsigned char cChannel)
{
	HIE_tdxHandleToSuperObject hModule;
 
	hModule = fn_hGetSuperObjectInChannel(fn_h3dDataGetChannelSOList(M_GetMSHandle(hPerso, 3dData)),(short) cChannel);
 
	/* if B mode, no check is done*/
	if (g_ucIsEdInGhostMode)
	{
		if (hModule)
			hModule->llastComputeFrameForModule = HIE_gs_lCurrentFrame;
		return;
	}
 
	/* if hModule is NULL, then there is an error : access to a valid channel number, but nothing in the channel !*/
	if (hModule == NULL)
	{
		/* error !*/
		char cText[512];
		
		if (M_GetMSHandle(hPerso,Brain) && M_pstGetMindOfBrain(M_GetMSHandle(hPerso,Brain)))
		{
			sprintf(cText,"You try to access a module that does not exist at this moment !!!\n"
				"this module belongs to : %s\nThe number of the channel you try to access is : %i\n",(M_pstGetMindOfBrain(M_GetMSHandle(hPerso,Brain)))->szPersoName,cChannel);
		}
		else
		{
			sprintf(cText,"You try to access a module that does not exist at this moment !!!\n"
				"this module belongs to <actor with no brain (current state is %s)>\nThe number of the channel you try to access is : %i\n",cChannel, fn_p_szGetStateName(fn_h3dDataGetCurrentState(M_GetMSHandle(hPerso,3dData))));
		}
		MessageBox(NULL,cText,"Module Access error",MB_OK|MB_ICONWARNING);
		fn_vForceEditor();
	}
 
	else if (hModule->llastComputeFrameForModule < HIE_gs_lCurrentFrame-1)
	{
		/* error !*/
		char cText[512];
 
		if (M_GetMSHandle(hPerso,Brain) && M_pstGetMindOfBrain(M_GetMSHandle(hPerso,Brain)))
		{
			sprintf(cText,"You try to get a module position that is not up to date !!!\n"
					  "this module belongs to : %s\n",(M_pstGetMindOfBrain(M_GetMSHandle(hPerso,Brain)))->szPersoName);
		}
		else
		{
			sprintf(cText,"You try to get a module position that is not up to date !!!\n"
					  "this module belongs to <actor with no brain (current state is %s>\n", fn_p_szGetStateName(fn_h3dDataGetCurrentState(M_GetMSHandle(hPerso,3dData))));
		}
		if (fn_ulStandardGameGetCustomBitsSO(hPerso) & GAM_C_CustBitNeedModuleMatrices)
		{
			strcat(cText,"This Perso already has the custombit 2 set, but it seems that the anim player has not\n"
						 "been played this time..., so check anim player related flags\n");
		}
		else
		{
			strcat(cText,"This perso does not have the custom bit 2 set, correct this and try again\n");
		}
		sprintf (cText + strlen(cText),"There is a difference of %i frames\n",HIE_gs_lCurrentFrame-hModule->llastComputeFrameForModule);
 
		MessageBox(NULL,cText,"Module Access error",MB_OK|MB_ICONWARNING);
		fn_vForceEditor();
	}
}
 
 
 
 
 
#endif
 
 
