/***************************/
/* DNMDynam.Cpp            */
/***************************/
/* Date 6-11-96            */
/* Modification 1996-12-11 */
/***************************/
#include "cpa_std.h"
 
#include "MEC/MecInc.h"
#include "MEC/DNMSurSt.h"
#include "MEC/DNMDynam.h"
#include "MEC/MECBase.h"
#include "MEC/MECTools.h"
#include "MEC/mBase.h"
#include "extheade.h"
 
#include "GAM/InitEnum.h"
#include "GAM/Actions/Dynam.h"
 
#if defined(ACTIVE_EDITOR)
extern void fn_vForceEditor (void);
/*extern ACP_tdxBool fn_bTestIfEditorRunning (void);*/
#endif /* ACTIVE_EDITOR */
extern HIE_tdxHandleToSuperObject gp_stInactiveDynamicWorld;
 
 
/*FB030898 for C optimisation*/
extern POS_tdstCompletePosition *POS_g_p_stIdentityMatrix;
/*END FB*/
 
extern HIE_tdxHandleToSuperObject gp_stDynamicWorld;
 
 
 
/*--- Global data ----*/
#ifdef MEC_CHECK_ACCESS
 
/* char g_a_TmpBuffer [1000];	/* > size of largest structure that can be return   */
HIE_tdxHandleToSuperObject g_hLastActorErrorInAdvancedCheck = NULL;
HIE_tdxHandleToSuperObject g_hLastActorErrorInComplexCheck = NULL;
HIE_tdxHandleToSuperObject g_hLastActorErrorInCollisionCheck = NULL;
 
/* Oliv' - remove wNumRom - 22/06/1999
#ifdef U64
	short fn_wGet3dDataNumRom(struct tdstEngineObject_ * p_stEngineObject);
	#define M_GetEngineObject(p_stSuperObject) ((HIE_fn_ulGetSuperObjectType(p_stSuperObject) != HIE_C_ulActor)?NULL:((struct tdstEngineObject_ *)(HIE_fn_hGetSuperObjectObject(p_stSuperObject))))
#endif
*/
 
/*--------------------------------------- Check functions --------------------------------*/
void DNM_fn_vDisplayErrorMessage ( char* szMessage, HIE_tdxHandleToSuperObject hSupObj )
{
	char szBuffer [500];
 
#ifndef U64
	if (hSupObj)
	{
	char szFamilyName [500];
	char szTypeName [10];
	char szTypeNames [10];
	char* pszActorName;
	char* pszFamilyName;
 
 
		pszActorName = AI_fn_pszGetActorName (hSupObj);
		pszFamilyName = AI_fn_pszGetFamilyName (hSupObj,szFamilyName);
 
		if (fn_ucIsAnAlwaysObject(HIE_fn_hGetSuperObjectObject(hSupObj)))
		{
			strcpy ( szTypeName, "always" );
			strcpy ( szTypeNames, "always" );
		}
		else
		{
			strcpy ( szTypeName, "actor" );
			strcpy ( szTypeNames, "actors" );
		}
 
		if (pszActorName && pszFamilyName)
			sprintf ( szBuffer, "%s\nto %s : %s\nof family : %s", szMessage, szTypeName, pszActorName, pszFamilyName );
		else if (pszActorName)
			sprintf ( szBuffer, "%s\nto %s : %s", szMessage, szTypeName, pszActorName );
		else if (pszFamilyName)
			sprintf ( szBuffer, "%s\nto %s of the family : %s .", szMessage, szTypeNames, pszFamilyName );
		else 
			sprintf ( szBuffer, "%s\nto an unknown %s.", szMessage, szTypeName );
	}
	else 
		sprintf ( szBuffer, "%s\nto someone.", szMessage );
 
 
	Erm_fn_iMessageBox (szBuffer,"Mechanic Allocation Error",MB_OK|MB_ICONERROR);
#else
	if (hSupObj)
	{
/* Oliv' - remove wNumRom - 22/06/1999 */
/*		short wNumRom = fn_wGet3dDataNumRom(M_GetEngineObject(hSupObj)); */
		short wNumRom = fn_otStandardGameGetPersonalType( M_GetMSHandle(hSupObj,StandardGame) );
		sprintf(szBuffer, "%s for Perso : %ld\n", szMessage, wNumRom);
/* EndOfOliv' */
	}
	else
		sprintf(szBuffer, "%s\n", szMessage);
	M_PrintfStopErrorN64((szBuffer));
#endif
 
#if defined(ACTIVE_EDITOR)
	fn_vForceEditor ();
#else
	/* Can't continue. You must allocate good mechanic to actor.*/
	*(long *)0x00000000 = 5;
#endif
}
 
 
 
 
DNM_tdstDynamicsBaseBlock* DNM_fn_pstGetBaseBlockWithAdvancedCheckAccess (DNM_tdstDynamics *p_stDynamic)
{
	HIE_tdxHandleToSuperObject hSupObj;
 
	if (!DNM_M_bDynamicsIsAdvancedSize(p_stDynamic))
	{
		hSupObj = DNM_fn_pstGetActorWithDynamic (p_stDynamic);
		if (hSupObj!=g_hLastActorErrorInAdvancedCheck)
		{
			g_hLastActorErrorInAdvancedCheck = hSupObj;
			DNM_fn_vDisplayErrorMessage ( "You must allocate an advanced mechanic", hSupObj );
		}
/*		return (DNM_tdstDynamicsBaseBlock*)g_a_TmpBuffer;*/
	}
	return &(p_stDynamic->m_tdstDynamicsBaseBlock);	
}
 
 
DNM_tdstDynamicsBaseBlock* DNM_fn_pstGetBaseBlockWithComplexCheckAccess (DNM_tdstDynamics *p_stDynamic)
{
	HIE_tdxHandleToSuperObject hSupObj;
 
	if (!DNM_M_bDynamicsIsComplexSize(p_stDynamic))
	{
		hSupObj = DNM_fn_pstGetActorWithDynamic (p_stDynamic);
		if (hSupObj!=g_hLastActorErrorInComplexCheck)
		{
			g_hLastActorErrorInComplexCheck = hSupObj;
			DNM_fn_vDisplayErrorMessage ( "You must allocate complex mechanic", hSupObj );
		}
/*		return (DNM_tdstDynamicsBaseBlock*)g_a_TmpBuffer;*/
	}
	return &(p_stDynamic->m_tdstDynamicsBaseBlock);	
}
 
 
DNM_tdstDynamicsAdvancedBlock* DNM_fn_pstGetAdvancedBlockWithCheckAccess (DNM_tdstDynamics *p_stDynamic)
{
	HIE_tdxHandleToSuperObject hSupObj;
 
	if (!DNM_M_bDynamicsIsAdvancedSize(p_stDynamic))
	{
		hSupObj = DNM_fn_pstGetActorWithDynamic (p_stDynamic);
		if (hSupObj!=g_hLastActorErrorInAdvancedCheck)
		{
			g_hLastActorErrorInAdvancedCheck = hSupObj;
			DNM_fn_vDisplayErrorMessage ( "You must allocate an advanced mechanic", hSupObj );
		}
/*		return (DNM_tdstDynamicsAdvancedBlock*)g_a_TmpBuffer;*/
	}
	return &(p_stDynamic->m_tdstDynamicsAdvancedBlock);			
}
 
DNM_tdstDynamicsComplexBlock* DNM_fn_pstGetComplexBlockWithCheckAccess (DNM_tdstDynamics *p_stDynamic)
{
	HIE_tdxHandleToSuperObject hSupObj;
 
	if (!DNM_M_bDynamicsIsComplexSize(p_stDynamic))
	{
		hSupObj = DNM_fn_pstGetActorWithDynamic (p_stDynamic);
		if (hSupObj!=g_hLastActorErrorInComplexCheck)
		{
			g_hLastActorErrorInComplexCheck = hSupObj;
			DNM_fn_vDisplayErrorMessage ( "You must allocate a complex mechanic", hSupObj );
		}
/*		return (DNM_tdstDynamicsComplexBlock*)g_a_TmpBuffer;*/
	}
	return &(p_stDynamic->m_tdstDynamicsComplexBlock);			
}
 
DNM_tdstReport*	DNM_fn_pstGetReportWithCheckAccess (DNM_tdstDynamics *p_stDynamic)
{
	HIE_tdxHandleToSuperObject hSupObj;
 
	if (!DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
	{
		hSupObj = DNM_fn_pstGetActorWithDynamic (p_stDynamic);
		if (hSupObj!=g_hLastActorErrorInCollisionCheck)
		{
			g_hLastActorErrorInCollisionCheck = hSupObj;
			DNM_fn_vDisplayErrorMessage ( "You must allocate collision", hSupObj );
		}
/*		return (DNM_tdstReport*)g_a_TmpBuffer;*/
	}
	return DNM_M_pstGetBaseBlock(p_stDynamic)->m_pstReport;
}
 
 
 
HIE_tdxHandleToSuperObject DNM_fn_pstGetActorWithDynamic (DNM_tdstDynamics *p_stDynamic)
{
	HIE_tdxHandleToSuperObject hCharacter,hNextCharacter;
	DNM_tdstDynamics *p_stCharacterDynamic;
	long i;
 
	HIE_M_ForEachMovingChildOf(gp_stDynamicWorld,hCharacter,hNextCharacter,i)
	{
		/* actor or platform */
		if ( HIE_fn_ulGetSuperObjectType(hCharacter)==HIE_C_ulActor )
		{
			p_stCharacterDynamic = fn_p_stDynamGetDynamicsSO (hCharacter);
			if (p_stCharacterDynamic==p_stDynamic) return hCharacter;
		}	
	}
 
	HIE_M_ForEachChildOf(gp_stInactiveDynamicWorld,hCharacter,i)
	/* actor or platform */
	if ( HIE_fn_ulGetSuperObjectType(hCharacter)==HIE_C_ulActor )
	{
		p_stCharacterDynamic = fn_p_stDynamGetDynamicsSO (hCharacter);
		if (p_stCharacterDynamic==p_stDynamic) return hCharacter;
	}	
 
 
	return NULL;
}
 
 
#endif /* MEC_CHECK_ACCESS*/
 
 
 
void DNM_fn_vDynamicsInitDefault(DNM_tdstDynamics *p_stDynamic)
{
#ifdef DNM_DEBUG
  if(p_stDynamics == NULL)
		return;
#endif
 
	DNM_tdstReport* p_stReport = NULL;
	unsigned long ulEndFlags = 0;
  
/*XB981020*/
#ifdef MEC_CHECK_ACCESS
    g_hLastActorErrorInAdvancedCheck = NULL;
	g_hLastActorErrorInComplexCheck = NULL;
	g_hLastActorErrorInCollisionCheck = NULL;
#endif /* MEC_CHECK_ACCESS */
/*End XB*/
 
	/* Init global report */	
	memset ( &g_stReport, 0, sizeof(DNM_tdstMecReport) );

	/* Init BitFields */
	p_stDynamic->m_tdstDynamicsBaseBlock.ulFlags = 0;
	p_stDynamic->m_tdstDynamicsBaseBlock.ulEndFlags &= (DNM_C_CollisionReport|DNM_C_Always|0xF);
	ulEndFlags = p_stDynamic->m_tdstDynamicsBaseBlock.ulEndFlags;
 
 
	/* Initialisation of the report */
#ifdef ACTIVE_EDITOR
	p_stReport = DNM_M_p_stDynamicsGetReportWithoutCheckAccess (p_stDynamic);
	DNM_p_stReportDefaultInit (p_stReport);
#else 
	if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
	{
		p_stReport = DNM_M_p_stDynamicsGetReport (p_stDynamic);
		DNM_p_stReportDefaultInit (p_stReport);
	}
#endif /* ACTIVE_EDITOR*/
 
 
 
	/* clean all */
#ifndef ACTIVE_EDITOR
	if (DNM_M_bDynamicsIsComplexSize(p_stDynamic)) memset ( p_stDynamic, 0, sizeof(DNM_tdstComplexDynamics) );
	else if (DNM_M_bDynamicsIsAdvancedSize(p_stDynamic)) memset ( p_stDynamic, 0, sizeof(DNM_tdstAdvancedDynamics) );
	else memset ( p_stDynamic, 0, sizeof(DNM_tdstBaseDynamics) );
#else /* ACTIVE_EDITOR*/
	memset ( p_stDynamic, 0, sizeof(DNM_tdstComplexDynamics) );
#endif /* ACTIVE_EDITOR*/
 
 
	/* restore values */
	p_stDynamic->m_tdstDynamicsBaseBlock.ulEndFlags = ulEndFlags;
	if (p_stReport)
		DNM_M_DynamicsSetReport(p_stDynamic,p_stReport);
 
 
	/* Init no null fields */
	DNM_M_vDynamicsSetInit (p_stDynamic,TRUE);
 
	/*--- Base init ---*/
	DNM_M_vDynamicsSetNbFrame(p_stDynamic,1);
 
	/*--- Advanced init ---*/
	if (DNM_M_bDynamicsIsAdvancedSize(p_stDynamic))
	{
		DNM_M_vDynamicsSetStreamFactor (p_stDynamic,MTH_C_ONE);
	}
  
	/*--- Complex init ---*/
	if (DNM_M_bDynamicsIsComplexSize(p_stDynamic))
	{
		HIE_fn_vInvalidateSuperObject (&DNM_M_hDynamicsGetPlatformSO(p_stDynamic));
	}

	memset(&g_stReport,0,sizeof(DNM_tdstMecReport)); //AR9906 Init of global report (See with Jacques)
}
 
 
 
/* Init function*/
void DNM_fn_vInitBaseMechanic (DNM_tdstDynamics *p_stDynamic)
{
	DNM_fn_vDynamicsInitDefault (p_stDynamic);
}
 
void DNM_fn_vInitDynamic (DNM_tdstDynamics *p_stDynamic, DNM_tdxHandleToMecIdentityCard hIdCard)
{
	DNM_tdstMecBaseIdCard* p_IdCard = (DNM_tdstMecBaseIdCard*)hIdCard; 
 
	/*--- Base ---*/
	DNM_M_vDynamicsSetAnimation(p_stDynamic,DNM_M_bBaseIdCardIsAnimation(p_IdCard));
	DNM_M_vDynamicsSetCollide(p_stDynamic,DNM_M_bBaseIdCardIsCollide(p_IdCard));
	DNM_M_vDynamicsSetGravity(p_stDynamic,DNM_M_bBaseIdCardIsGravity(p_IdCard)); 
	DNM_M_vDynamicsSetTilt(p_stDynamic,DNM_M_bBaseIdCardIsTilt(p_IdCard));
	DNM_M_vDynamicsSetGi(p_stDynamic,DNM_M_bBaseIdCardIsGi(p_IdCard));
	DNM_M_vDynamicsSetOnGround(p_stDynamic,DNM_M_bBaseIdCardIsOnGround(p_IdCard));
	DNM_M_vDynamicsSetClimb(p_stDynamic,DNM_M_bBaseIdCardIsClimb(p_IdCard));
	DNM_M_vDynamicsSetSpider(p_stDynamic,DNM_M_bBaseIdCardIsSpider(p_IdCard));
	DNM_M_vDynamicsSetShoot(p_stDynamic,DNM_M_bBaseIdCardIsShoot(p_IdCard));
	DNM_M_vDynamicsSetSwim(p_stDynamic,DNM_M_bBaseIdCardIsSwim(p_IdCard));
	DNM_M_vDynamicsSetCollisionControl(p_stDynamic,DNM_M_bBaseIdCardIsCollisionControl(p_IdCard));
	DNM_M_vDynamicsSetKeepWallSpeedZ(p_stDynamic,DNM_M_bBaseIdCardIsKeepWallSpeedZ(p_IdCard));
	DNM_M_vDynamicsSetSpeedLimit(p_stDynamic,DNM_M_bBaseIdCardIsSpeedLimit(p_IdCard));
	DNM_M_vDynamicsSetInertia(p_stDynamic,DNM_M_bBaseIdCardIsInertia(p_IdCard));
	DNM_M_vDynamicsSetStream(p_stDynamic,DNM_M_bBaseIdCardIsStream(p_IdCard));
	DNM_M_vDynamicsSetStickOnPlatform(p_stDynamic,DNM_M_bBaseIdCardIsStickOnPlatform(p_IdCard));
	DNM_M_vDynamicsSetScaleOption(p_stDynamic,DNM_M_bBaseIdCardIsScale(p_IdCard));
	DNM_M_vDynamicsSetGravityFactor(p_stDynamic,DNM_M_xBaseIdCardGetGravityFactor(p_IdCard)); 
	DNM_M_vDynamicsSetSlopeLimit(p_stDynamic,DNM_M_xBaseIdCardGetSlopeLimit(p_IdCard));
	DNM_M_bDynamicsSetMechanicChange(p_stDynamic,TRUE);
	DNM_M_vDynamicsSetNeverFall(p_stDynamic,FALSE);
	DNM_M_vDynamicsSetForceSafeWalk ( p_stDynamic, FALSE );

	/* Optimization */
	MEC_fn_vComputeSlopeLimit (p_stDynamic);
 
	/*--- Advanced ---*/
	if (DNM_M_bDynamicsIsAdvancedSize(p_stDynamic))
	{
		DNM_M_vDynamicsSetSlide(p_stDynamic,DNM_M_xBaseIdCardGetSlide(p_IdCard));
		DNM_M_vDynamicsSetRebound(p_stDynamic,DNM_M_xBaseIdCardGetRebound(p_IdCard));
		DNM_M_vDynamicsSetInertiaFactorX(p_stDynamic,DNM_M_xBaseIdCardGetInertiaFactorX(p_IdCard));
		DNM_M_vDynamicsSetInertiaFactorY(p_stDynamic,DNM_M_xBaseIdCardGetInertiaFactorY(p_IdCard));
		DNM_M_vDynamicsSetInertiaFactorZ(p_stDynamic,DNM_M_xBaseIdCardGetInertiaFactorZ(p_IdCard));
		DNM_M_vDynamicsSetMaxSpeed(p_stDynamic,DNM_M_pBaseIdCardGetMaxSpeed(p_IdCard));
		
		/* collision matrix */
		MEC_fn_vRegisterCollisionTranslation (p_stDynamic,DNM_M_p_stDynamicsGetCurrentMatrix(p_stDynamic));
 
	}
 
	/*--- Complex ---*/
	else if (DNM_M_bDynamicsIsComplexSize(p_stDynamic))
	{
		DNM_M_vDynamicsSetTiltIntensity(p_stDynamic,DNM_M_xBaseIdCardGetTiltIntensity(p_IdCard));
		DNM_M_vDynamicsSetTiltInertia(p_stDynamic,DNM_M_xBaseIdCardGetTiltInertia(p_IdCard));
		DNM_M_vDynamicsSetTiltOrigin(p_stDynamic,DNM_M_xBaseIdCardGetTiltOrigin(p_IdCard));
	}
}
 
 
/* Inform that Id Card has changed             */
/* Author : j Thénoz                           */
/* Date : 1997-12-15                           */
/* Version : 1.01                              */
void DNM_fn_vChangeIdCard (DNM_tdstDynamics *_p_stDynamics,DNM_tdxHandleToMecIdentityCard _hNewIdCard)
{
	#if defined(MEC_DEBUG)
#ifndef U64
	HIE_tdxHandleToSuperObject hSupObj;
	char szMessage [500];
	char* pszName;
 
	if (!_hNewIdCard)
	{
		hSupObj = DNM_fn_pstGetActorWithDynamic (_p_stDynamics);
		pszName = AI_fn_pszGetActorName (hSupObj);
		sprintf ( szMessage, "You must select a mechanic in action editor\nto actor : %s .", pszName );
		Erm_fn_iMessageBox (szMessage,"Mechanic error",MB_OK|MB_ICONERROR);
#else
	if (!_hNewIdCard)
	{
/* Oliv' - remove wNumRom - 22/06/1999 */
/*		short wNumRom = fn_wGet3dDataNumRom(M_GetEngineObject(hSupObj)); */
		short wNumRom = fn_otStandardGameGetPersonalType( M_GetMSHandle(hSupObj,StandardGame) );
		M_PrintfStopErrorN64(("You must select a mechanic for Perso : %ld\n", wNumRom));
/* EndOfOliv' */
#endif /* U64*/
 
 
#if defined(ACTIVE_EDITOR)
		fn_vForceEditor ();
#endif /* ACTIVE_EDITOR*/
 
    	Erm_M_ClearLastError(C_ucErmDefaultChannel);
 
		return;
	}
	
	#endif
 
#ifdef DNM_DEBUG
	if (DNM_fn_eIdentityCardGetType(_hNewIdCard)==DNM_eBase)
#else
	if (DNM_M_eBaseIdCardGetIdentity((DNM_tdstMecBaseIdCard*)(_hNewIdCard)) == DNM_eBase)
#endif
	DNM_fn_vInitDynamic (_p_stDynamics, _hNewIdCard);
	DNM_M_vDynamicsSetCurrentIdCard(_p_stDynamics,_hNewIdCard);
}
 
 
/* clone dynamic structure */
void DNM_fn_vDynamicsCopyClone ( DNM_tdstDynamics *_p_stDst, DNM_tdstDynamics *_p_stSrc )
{
	DNM_tdstReport* p_stReport=NULL;
 
	if (DNM_M_bDynamicsIsCollisionReport(_p_stDst))
	{
		/* store destination report */
		p_stReport = DNM_M_p_stDynamicsGetReport (_p_stDst);
	}
 
	/* copy */
	if (DNM_M_bDynamicsIsComplexSize(_p_stSrc)) memcpy ( _p_stDst, _p_stSrc, sizeof(DNM_tdstComplexDynamics) );
	else if (DNM_M_bDynamicsIsAdvancedSize(_p_stSrc)) memcpy ( _p_stDst, _p_stSrc, sizeof(DNM_tdstAdvancedDynamics) );
	else memcpy ( _p_stDst, _p_stSrc, sizeof(DNM_tdstBaseDynamics) );
		
	if (p_stReport)
	{
		DNM_M_DynamicsSetReport ( _p_stDst, p_stReport );
		if (DNM_M_bDynamicsIsCollisionReport(_p_stSrc))
			memcpy ( p_stReport, DNM_M_p_stDynamicsGetReport(_p_stSrc), sizeof(DNM_tdstReport) );
	}
}
 
