////////////////////////////////////////////////////////////////////// // // Crytek Source code // Copyright (c) Crytek 2001-2004 // // XPuppetProxy.cpp: implementation of the CXPuppetProxy class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "XPuppetProxy.h" #include #include "Game.h" #include "XPlayer.h" #include "XVehicle.h" #include "WeaponClass.h" #include "ScriptObjectVector.h" #include "XEntityProcessingCmd.h" #include #include #include ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CXPuppetProxy::CXPuppetProxy(IEntity *pEntity,IScriptSystem *pScriptSystem, CXGame *pGame):pSignalTable(pScriptSystem),pJumpTable(pScriptSystem) { m_fMovementRestrictionDuration = -1; m_bAllowedToMove = false; m_nWeaponBoneID = -1; m_bWasSwimming = false; m_bFireOverride = false; m_bInJump = false; m_pScriptSystem = pScriptSystem; m_pEntity = pEntity; m_nLastBodyPos = 0; m_vPreviousTargetPos = pEntity->GetPos(); if (m_pEntity->GetContainer()) { if (!m_pEntity->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &m_pPlayer)) m_pPlayer = 0; } else m_pPlayer = 0; // m_pPlayer->SetEntity(pEntity); m_bDead = false; m_fBackwardSpeed = 0; m_fForwardSpeed = 0; m_vHeadDir = pEntity->GetAngles(); m_vHeadDir=ConvertToRadAngles(m_vHeadDir); m_vTorsoDir = m_vHeadDir; m_vBodyDir = m_vHeadDir; m_pGame = pGame; m_AIHandler.Init( m_pGame, m_pEntity, m_pGame->GetSystem()->GetILog() ); m_pEntity->GetScriptObject()->GetValue("JumpSelectionTable",pJumpTable); bool bFish = false; m_pEntity->GetScriptObject()->GetValue("IsFish",bFish); m_pPlayer->m_bIsFish = bFish; m_pCharacterPhysics = 0; ICryCharInstance *pInstance = m_pEntity->GetCharInterface()->GetCharacter(0); if (pInstance) { if (pInstance->GetModel()) { m_nWeaponBoneID = pInstance->GetModel()->GetBoneByName("Bip01 R Forearm"); } } m_pAISystem = NULL; } CXPuppetProxy::~CXPuppetProxy() { //delete m_pPlayer; ICryCharInstance *pInstance = m_pEntity->GetCharInterface()->GetCharacter(0); if (pInstance) pInstance->RemoveAnimationEventSink(this); } int CXPuppetProxy::Update(SOBJECTSTATE *state) { FUNCTION_PROFILER( m_pGame->GetSystem(),PROFILE_AI ); if (m_pPlayer) { if (!m_pPlayer->IsAlive()) return 0; } m_pScriptSystem->BeginCall("BasicAI","DoChatter"); m_pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject()); m_pScriptSystem->EndCall(); // new piece that deals with stopping firing when the enemy is shot /*if (m_nWeaponBoneID>=0) { FRAME_PROFILER( "AIShotReaction",m_pGame->GetSystem(),PROFILE_AI ); pe_status_joint pjs; pjs.idChildBody = m_nWeaponBoneID; ICryCharInstance *pInstance = m_pEntity->GetCharInterface()->GetCharacter(0); if (pInstance) { m_pCharacterPhysics = pInstance->GetCharacterPhysics(); if (m_pCharacterPhysics) { m_pCharacterPhysics->GetStatus(&pjs); if (pjs.q.Length() > 0.001f) { SAIEVENT event; event.fInterest = 0.2f; m_pEntity->GetAI()->Event(AIEVENT_ONBODYSENSOR,&event); } } } } */ Vec3d angles = m_pEntity->GetAngles(1); if(!m_pEntity->IsBound() || m_pPlayer->GetRedirected()) // move only if not bound // if(1) { if ((-1e+9 < state->fValue && state->fValue < 1e+9)) { // handle turning if (state->turnleft || state->turnright) { angles.z+=state->fValue; } } else state->fValue = 0; if ((-1e+9 < state->fValueAux && state->fValueAux < 1e+9)) { angles.x+=state->fValueAux; } else state->fValueAux = 0; CXEntityProcessingCmd tempCommand; tempCommand.SetDeltaAngles(angles); //-------------------- if (m_pPlayer) m_pPlayer->ProcessAngles(tempCommand); else m_pEntity->SetAngles(angles,true,false); if (state->left || state->right)// && state->bHaveTarget) { Vec3d ang = m_pEntity->GetAngles(); ang=ConvertToRadAngles(ang); //Vec3d leftdir = state->vTargetPos - m_pEntity->GetPos(); Vec3d leftdir = ang; Matrix44 mat; mat.SetIdentity(); if (state->left) { //mat.RotateMatrix(Vec3d(0,0,90)); mat=Matrix44::CreateRotationZYX(-Vec3d(0,0,+90)*gf_DEGTORAD)*mat; //NOTE: angles in radians and negated } else { //mat.RotateMatrix(Vec3d(0,0,-90)); mat=Matrix44::CreateRotationZYX(-Vec3d(0,0,-90)*gf_DEGTORAD)*mat; //NOTE: angles in radians and negated } leftdir = mat.TransformPointOLD(leftdir); state->vMoveDir+=leftdir; } pe_action_move motion; // motion.dir.set(0,0,0); if (state->vMoveDir.Length() > 0) { motion.dir = GetNormalized(state->vMoveDir); //motion.dir.z = 0; //motion.dir.normalize(); } else motion.dir.Set(0,0,0); if (state->jump) { FRAME_PROFILER( "AIJumpProcessing",m_pGame->GetSystem(),PROFILE_AI ); if (m_pPlayer) m_pPlayer->m_stats.jumping = true; m_vJumpVector = state->vJumpDirection; m_fLastJumpDuration = state->fJumpDuration; m_nJumpDirection = (int)(state->nJumpDirection); _SmartScriptObject pDesiredJumpType(m_pScriptSystem,true); if (pJumpTable->GetAt(m_nJumpDirection,pDesiredJumpType)) { _SmartScriptObject pDesiredJump(m_pScriptSystem,true); int cnt = pDesiredJumpType->Count(); if (cnt>1) cnt = (rand() % (cnt)) + 1; m_nLastSelectedJumpAnim = cnt; if (pDesiredJumpType->GetAt(cnt,pDesiredJump)) { const char *pAnimName; int nTakeoffFrame, nLandFrame; pDesiredJump->GetAt(1,pAnimName); pDesiredJump->GetAt(2,nTakeoffFrame); pDesiredJump->GetAt(3,nLandFrame); ICryCharInstance *pCharacter = m_pEntity->GetCharInterface()->GetCharacter(0); if (pCharacter) { // set up callbacks to jump and land correctly m_pGame->GetSystem()->GetILog()->Log("\001 [AIWARNING] Entity %s set a callback for animation %s (char %p)",m_pEntity->GetName(), pAnimName, pCharacter); pCharacter->AddAnimationEventSink(pAnimName,this); pCharacter->AddAnimationEvent(pAnimName,nTakeoffFrame,(void*)JUMP_TAKEOFF); pCharacter->AddAnimationEvent(pAnimName,nLandFrame,(void*)JUMP_LAND); m_pEntity->StartAnimation(0,pAnimName,3,0.1f); SAIEVENT sae; sae.fInterest = m_fLastJumpDuration; sae.fInterest += m_pEntity->GetAnimationLength(pAnimName) - ((nLandFrame-nTakeoffFrame)*0.03f); m_pEntity->GetAI()->Event(AIEVENT_ONBODYSENSOR,&sae); MovementControl(false, sae.fInterest); } else m_pGame->GetSystem()->GetILog()->Log("\003 [AIWARNING] Entity %s tried to jump but has no animated character!!",m_pEntity->GetName()); } } else m_pGame->GetSystem()->GetILog()->Log("\003 [AIWARNING] No jumps specified for a certain direction for entity %s",m_pEntity->GetName()); state->jump = false; } else { m_AIHandler.SetCurrentBehaviourVariable("fLastJumpDuration",state->fJumpDuration); if (m_pPlayer) m_pPlayer->m_stats.jumping = false; motion.dir *= m_fForwardSpeed; if( m_pPlayer->m_stats.bIsLimping ) { motion.dir*=.73f; } else switch (state->bodystate) { case BODYPOS_STAND: if (state->run) motion.dir*=m_pPlayer->m_RunSpeedScale; // motion.dir*=m_pGame->p_ai_runspeedmult->GetFVal(); // motion.dir*=1.5f; break; case BODYPOS_CROUCH: // motion.dir*=0.75f; // motion.dir*=m_pGame->p_ai_crouchspeedmult->GetFVal(); motion.dir*=m_pPlayer->m_CrouchSpeedScale; break; case BODYPOS_PRONE: // motion.dir*=0.5f; // motion.dir*=m_pGame->p_ai_pronespeedmult->GetFVal(); motion.dir*=m_pPlayer->m_ProneSpeedScale; break; case BODYPOS_STEALTH: if (state->run) // motion.dir*=1.5f; // motion.dir*=m_pGame->p_ai_xrunspeedmult->GetFVal(); motion.dir*=m_pPlayer->m_XRunSpeedScale; else // motion.dir*=0.4f; // motion.dir*=m_pGame->p_ai_xwalkspeedmult->GetFVal(); motion.dir*=m_pPlayer->m_XWalkSpeedScale; break; case BODYPOS_RELAX: if (state->run) // motion.dir*=1.5f; // motion.dir*=m_pGame->p_ai_rrunspeedmult->GetFVal(); motion.dir*=m_pPlayer->m_RRunSpeedScale; else // motion.dir*=0.4f; // motion.dir*=m_pGame->p_ai_rwalkspeedmult->GetFVal(); motion.dir*=m_pPlayer->m_RWalkSpeedScale; break; } } pe_player_dynamics pdyn; m_pEntity->GetPhysics()->GetParams(&pdyn); if (m_pPlayer) { // handle inertia // actual intertia change is done in CPlayer::UpdatePhysics // same for AirControl/bSwimming if (((state->bCloseContact || m_bInJump) && !m_pPlayer->IsSwimming()) || m_pPlayer->m_bIsFish ) m_pPlayer->m_bInertiaOverride = true; else m_pPlayer->m_bInertiaOverride = false; /* // handle inertia if ((state->bCloseContact || m_bInJump) && !m_pPlayer->IsSwimming() ) pdyn.kInertia = 0; else { if (m_bIsFish) pdyn.kInertia = 0; else pdyn.kInertia = 4; } // if (m_pPlayer->m_fGravityOverride!=1E10 || m_pPlayer->IsSwimming()) if (m_pPlayer->m_stats.onLadder || m_pPlayer->IsSwimming()) { pdyn.kAirControl = 1; pdyn.bSwimming = 1; } else { pdyn.kAirControl = 0; pdyn.bSwimming =0 ; } */ // if (m_pPlayer->m_fGravityOverride!=1E10 || m_pPlayer->IsSwimming()) if (m_pPlayer->IsSwimming()) { // keep puppet on surface if( m_pPlayer->m_stats.fInWater>.4f) motion.dir.z = 4.0f; // motion.dir.z = .20f; // when swimming underwater and goung up by press JUMP // if too close to surface - don't aplpy much UP impulse // to prevent jumping out of water if( m_pPlayer->m_stats.fInWater < m_pPlayer->m_PlayerDimSwim.heightEye) motion.dir.z *= m_pPlayer->m_stats.fKWater*.02f; // if close to surface - don't go up too fast - not to jump out of water if (!m_bWasSwimming ) { if (!m_pPlayer->m_bIsFish) { // player entered water m_pEntity->GetAI()->SetSignal(1,"START_SWIMMING"); m_bWasSwimming = true; } } } else if (m_bWasSwimming) { if (!m_pPlayer->m_bIsFish) { // player left water m_pEntity->GetAI()->SetSignal(-1,"STOP_SWIMMING"); m_bWasSwimming = false; } } } //smooth AI movement, if AI is indoor is possible to use different acceleration values (if m_pPlayer->m_input_accel_indoor>0.0f). if (m_pPlayer) { bool indoor = false; float accel = m_pPlayer->m_input_accel; float decel = m_pPlayer->m_input_stop_accel; //if is the first time, get AISystem pointer. if (!m_pAISystem) m_pAISystem = m_pGame->GetSystem()->GetAISystem(); int building; IVisArea *pArea; if (m_pAISystem && ((IAISystem *)m_pAISystem)->CheckInside(m_pEntity->GetPos(),building,pArea)) { indoor = true; if (m_pPlayer->m_input_accel_indoor>0.0f) { accel = m_pPlayer->m_input_accel_indoor; decel = m_pPlayer->m_input_stop_accel_indoor; //m_pGame->GetSystem()->GetILog()->Log("%s indoor(%.1f,%.1f)",m_pEntity->GetName(),accel,decel); } } //force AI to use smaller acceleraion near target only when outdoor, //indoors have fDistanceFromTarget pretty small all the times and this cause AI to smooth to much, missing doors. if (state->fDistanceFromTarget>0 && !indoor) accel = min(state->fDistanceFromTarget,accel); m_pPlayer->DampInputVector(motion.dir,accel,decel,true,false); } // move entity ApplyMovement(&motion,state); // this is done in CPlayer::UpdatePhysics now // m_pEntity->GetPhysics()->SetParams(&pdyn); m_pPlayer->m_vDEBUGAIFIREANGLES = m_pEntity->GetAngles(); // handle fire of weapon int temp; if (m_pPlayer && !m_pEntity->GetScriptObject()->GetValue("NEVER_FIRE",temp)) { FRAME_PROFILER( "AIWeaponsFire",m_pGame->GetSystem(),PROFILE_AI ); m_pPlayer->m_aimLook = state->aimLook; Vec3d fireangles = state->vFireDir; Vec3d mvmtDir = state->vTargetPos - m_vPreviousTargetPos; if (mvmtDir.len2() > 20.f) { fireangles = state->vTargetPos + GetNormalized(mvmtDir)*4.5f; fireangles -= m_pEntity->GetPos(); } fireangles = ConvertVectorToCameraAngles(fireangles); m_pPlayer->m_vDEBUGAIFIREANGLES = fireangles; if (m_bFireOverride) { m_pPlayer->m_stats.firing=true; m_pPlayer->m_aimLook = true; m_bFireOverride = false; } else { m_pPlayer->m_aimLook = state->aimLook; if (state->fire) { m_pPlayer->m_stats.firing=true; //m_pPlayer->m_aimLook = true; m_pPlayer->HoldWeapon(); } else m_pPlayer->m_stats.firing=false; } } else m_pPlayer->m_stats.firing = false; //comment it //m_pPlayer->m_aimLook = true; //Account for body position----------------------------- if (m_nLastBodyPos != state->bodystate) { FRAME_PROFILER( "AISwitchingStances",m_pGame->GetSystem(),PROFILE_AI ); switch (state->bodystate) { case 1: m_dimCurrentDimensions = m_dimCrouchingPuppet; if (m_pPlayer) m_pPlayer->GoCrouch(); break; case 2: m_dimCurrentDimensions = m_dimProningPuppet; if (m_pPlayer) m_pPlayer->GoProne(); break; case 0: m_dimCurrentDimensions = m_dimStandingPuppet; if (m_pPlayer) m_pPlayer->GoStand(); break; case 5: m_dimCurrentDimensions = m_dimStandingPuppet; if (m_pPlayer) m_pPlayer->GoStealth(); break; case 4: m_dimCurrentDimensions = m_dimProningPuppet; break; case 3: m_dimCurrentDimensions = m_dimStandingPuppet; if (m_pPlayer) m_pPlayer->GoRelaxed(); break; } //<> PUppets that will not be players???? //m_pEntity->GetPhysics()->SetParams(&m_dimCurrentDimensions); m_nLastBodyPos = state->bodystate; } } else { if (m_pPlayer) { angles = m_pEntity->GetAngles( 1 ); // handle turning if (state->turnleft || state->turnright) angles.z+=state->fValue; angles.x+=state->fValueAux; CXEntityProcessingCmd tempCommand; tempCommand.SetDeltaAngles(angles); //-------------------- m_pPlayer->ProcessAngles(tempCommand); // m_pPlayer->m_aimLook = state->aimLook; if (state->fire) { Vec3d fireangles = state->vFireDir; fireangles=ConvertVectorToCameraAngles(fireangles); m_pPlayer->m_vDEBUGAIFIREANGLES =fireangles; //m_pPlayer->SetFiring(true); m_pPlayer->m_stats.firing=true; m_pPlayer->m_aimLook = true; // bAiming = true; // m_pPlayer->GoAim( ); // m_pPlayer->m_stats.firing=true; } else { m_pPlayer->m_stats.firing=false; } } } //------------------------------------------- if (!(m_LastObjectState == *state)) { m_LastObjectState = *state; UpdateMotor(state); } bool bSkipNextUpdate = false; { FRAME_PROFILER( "AISignalProcessing",m_pGame->GetSystem(),PROFILE_AI ); while (!state->vSignals.empty()) { AISIGNAL sstruct = state->vSignals.back(); state->vSignals.pop_back(); int signal = sstruct.nSignal; const char *szText = &sstruct.strText[0]; IEntity* pSender= (IEntity*) sstruct.pSender; switch (signal) { case -10: // throw a grenate if (m_pPlayer) { Vec3d firepos,fireangles; firepos = m_pPlayer->GetEntity()->GetPos(); firepos.z+=2.f; fireangles = m_pPlayer->GetEntity()->GetAngles(); m_pPlayer->m_fGrenadeTimer=3; m_pPlayer->FireGrenade(firepos,fireangles,m_pPlayer->GetEntity()); } //state->pSignalSender=0; break; case -20: bSkipNextUpdate = true; break; } SendSignal(signal,szText,pSender); //state->nSignal = 0; //state->szSignalText = 0; } } if (state->nAuxSignal) { FRAME_PROFILER( "AIReadibilityProcessing",m_pGame->GetSystem(),PROFILE_AI ); SendAuxSignal(state->nAuxSignal,state->szAuxSignalText.c_str()); state->nAuxSignal = 0; } // send SYSTEM GAME EVENTS LAST!!! They are most important. if (state->bReevaluate && !bSkipNextUpdate) UpdateMind(state); if (state->bHaveTarget) m_vPreviousTargetPos = state->vTargetPos; return 0; } bool CXPuppetProxy::QueryProxy(unsigned char type, void **pProxy) { if (type == AIPROXY_PUPPET) { *pProxy = (void *) this; return true; } else return false; } void CXPuppetProxy::SetRootBone(const char *pRootBone) { m_strRootBone = pRootBone; } void CXPuppetProxy::SetSpeeds(float fwd, float bkw) { m_fForwardSpeed = fwd; m_fBackwardSpeed = bkw; if(m_pPlayer) m_pPlayer->SetWalkSpeed( m_fForwardSpeed ); } void CXPuppetProxy::SetPuppetDimensions(float height, float eye_height, float sphere_height, float radius) { m_dimStandingPuppet.heightEye = eye_height; m_dimStandingPuppet.heightCollider = sphere_height; m_dimStandingPuppet.sizeCollider.Set(0.6f,0.6f,radius); m_dimCrouchingPuppet.heightEye = eye_height * 0.5f; m_dimCrouchingPuppet.heightCollider = sphere_height * 0.5f; m_dimCrouchingPuppet.sizeCollider.Set(0.6f, 0.6f, radius*0.5f); m_dimProningPuppet.heightEye = eye_height *0.2f; m_dimProningPuppet.heightCollider = sphere_height * 0.2f; m_dimProningPuppet.sizeCollider.Set(0.7f, 0.6f, radius*0.2f); } void CXPuppetProxy::GetDimensions(int bodypos, float &eye_height, float &height) { if (bodypos) { if (bodypos == 1) { eye_height = m_dimCrouchingPuppet.heightEye; height = m_dimCrouchingPuppet.heightEye+0.05f; } else { eye_height = m_dimProningPuppet.heightEye; height = m_dimProningPuppet.heightEye+0.05f; } } else { eye_height = m_dimStandingPuppet.heightEye; height = m_dimStandingPuppet.heightEye+0.05f; } } int CXPuppetProxy::UpdateMotor(SOBJECTSTATE *state) { // create table to pass to motor script /* _SmartScriptObject pTable(m_pScriptSystem); pTable->SetValue("turning",(state->turnleft || state->turnright)); pTable->SetValue("forward",state->forward); pTable->SetValue("back",state->back); pTable->SetValue("left",state->left); pTable->SetValue("right",state->right); pTable->SetValue("bodypos",state->bodystate); pTable->SetValue("run",state->run); pTable->SetValue("signal",state->nSignal); pTable->SetValue("health",state->fHealth); pTable->SetValue("moving",(state->back || state->forward || state->left || state->right)); // call script for cool animations m_pScriptSystem->BeginCall(m_pEntity->GetEntityClassName(),m_strMotorFuncName.c_str()); m_pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject()); m_pScriptSystem->PushFuncParam(*pTable); m_pScriptSystem->EndCall();*/ return 0; } void CXPuppetProxy::UpdateMind(SOBJECTSTATE *state) { m_AIHandler.AIMind( state ); state->bReevaluate = false; return; bool bScriptControl = false; if (!state->bHaveTarget) int a=5; _SmartScriptObject pTable(m_pScriptSystem); pTable->SetValue("haveTarget",state->bHaveTarget); pTable->SetValue("fInterest",state->fInterest); pTable->SetValue("fThreat",state->fThreat); pTable->SetValue("fDistance",state->fDistanceFromTarget); pTable->SetValue("nType",state->nTargetType); // pTable->SetValue("nSignal",state->nSignal); pTable->SetValue("bMemory",state->bMemory); pTable->SetValue("bSound",state->bSound); pTable->SetValue("bTakingDamage",state->bTakingDamage); pTable->SetValue("bTargetEnabled",state->bTargetEnabled); m_pScriptSystem->BeginCall( m_hBehaviourFunc ); // m_pScriptSystem->BeginCall(m_pEntity->GetEntityClassName(),m_strBehaviourFuncName.c_str()); m_pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject()); m_pScriptSystem->PushFuncParam(*pTable); m_pScriptSystem->EndCall(bScriptControl); state->bReevaluate = false; } void CXPuppetProxy::Reset(void) { if (m_pPlayer) m_pPlayer->m_stats.FiringType = eNotFiring; } void CXPuppetProxy::SendSignal(int signalID, const char * szText, IEntity *pSender) { m_pEntity->SetNeedUpdate( true ); m_AIHandler.AISignal( signalID, szText, pSender ); } void CXPuppetProxy::SendAuxSignal(int signalID, const char * szText) { m_AIHandler.DoReadibilityPack(szText); } void CXPuppetProxy::SetSignalFunc(HSCRIPTFUNCTION pFunc) { m_hSignalFunc.Init(m_pScriptSystem,pFunc); } void CXPuppetProxy::SetBehaviourFunc(HSCRIPTFUNCTION pFunc) { m_hBehaviourFunc.Init(m_pScriptSystem,pFunc); } void CXPuppetProxy::SetMotorFunc(HSCRIPTFUNCTION pFunc) { m_hMotorFunc.Init(m_pScriptSystem,pFunc); } //-------------------------------------------------------------------------------------------- bool CXPuppetProxy::CustomUpdate(Vec3d & vPos, Vec3d & vAngles) { if (m_pPlayer) { if (_isnan(m_pPlayer->m_vCharacterAngles.x) || _isnan(m_pPlayer->m_vCharacterAngles.y) || _isnan(m_pPlayer->m_vCharacterAngles.z)) GameWarning("m_vCharacterAngles for entity %s are NaN",m_pEntity->GetName()); else vAngles = m_pPlayer->m_vCharacterAngles; } return false; } void CXPuppetProxy::DebugDraw(struct IRenderer * pRenderer) { pRenderer->TextToScreenColor(50,66,0.3f,0.3f,0.3f,1.f,"- Proxy Information --"); const char *szCurrentBehaviour=0; const char *szPreviousBehaviour=0; const char *szFirstBehaviour=0; if (m_AIHandler.m_pBehavior) m_AIHandler.m_pBehavior->GetValue("Name",szCurrentBehaviour); if (m_AIHandler.m_pPreviousBehavior) m_AIHandler.m_pPreviousBehavior->GetValue("Name",szPreviousBehaviour); if (!m_AIHandler.m_FirstBehaviorName.empty()) szFirstBehaviour = m_AIHandler.m_FirstBehaviorName.c_str(); pe_player_dynamics pdyn; m_pEntity->GetPhysics()->GetParams(&pdyn); pRenderer->TextToScreen(50,70,"GRAVITY IN PHYSICS :%.3f AirControl: %.3f",pdyn.gravity,pdyn.kAirControl); if (m_pPlayer) { if (m_pPlayer->m_weaponPositionState == 1) pRenderer->TextToScreen(50,72,"WEAPON HOLSTERED"); else if (m_pPlayer->m_weaponPositionState == 2) pRenderer->TextToScreen(50,72,"HOLDING WEAPON"); else pRenderer->TextToScreen(50,72,"WEAPON POS UNDEFINED"); } pe_status_living pliv; m_pEntity->GetPhysics()->GetStatus(&pliv); if (IsEquivalent(pliv.vel,pliv.velRequested,0.1f)) pRenderer->SetMaterialColor(1,1,1,1); else pRenderer->SetMaterialColor(1,0,0,1); pRenderer->TextToScreen(40,66,"VEL_REQUESTED:(%.2f,%.2f,%.2f) ACTUAL_VEL:(%.2f,%.2f,%.2f)", pliv.velRequested.x,pliv.velRequested.y,pliv.velRequested.z,pliv.vel.x,pliv.vel.y,pliv.vel.z); pRenderer->TextToScreen(50,74,"BEHAVIOUR: %s",szCurrentBehaviour); pRenderer->TextToScreen(50,76," PREVIOUS BEHAVIOUR: %s",szPreviousBehaviour); pRenderer->TextToScreen(50,78," DESIGNER ASSIGNED BEHAVIOUR: %s",szFirstBehaviour); ICryCharInstance *pInstance = m_pEntity->GetCharInterface()->GetCharacter(0); if (pInstance) { for (int i=0;i<5;i++) { int nId=-1; if ((nId = pInstance->GetCurrentAnimation(i))>=0) { pRenderer->TextToScreen(50.f,80.f+2*i," LAYER %d: ANIM: %s",i,pInstance->GetModel()->GetAnimationSet()->GetName(nId)); } } pRenderer->TextToScreen(50,68,"Current animation scale %.3f",pInstance->GetAnimationSpeed()); } } void CXPuppetProxy::OnAnimationEvent(const char *sAnimation,AnimSinkEventData UserData) { // only used for synchronizing animation jumps if (UserData.p == (void*)JUMP_TAKEOFF) { m_bInJump = true; pe_action_move motion; motion.dir = m_vJumpVector; motion.iJump = 1; m_pEntity->GetPhysics()->Action(&motion); m_pGame->GetSystem()->GetILog()->Log("\003 [AIWARNING] -------%s--------------- NOW APPLYING JUMP ACTION!! --------------------------------",sAnimation); _SmartScriptObject pDesiredJumpType(m_pScriptSystem,true); if (pJumpTable->GetAt(m_nJumpDirection,pDesiredJumpType)) { _SmartScriptObject pDesiredJump(m_pScriptSystem,true); if (pDesiredJumpType->GetAt(m_nLastSelectedJumpAnim,pDesiredJump)) { int nTakeoffFrame, nLandFrame; pDesiredJump->GetAt(2,nTakeoffFrame); pDesiredJump->GetAt(3,nLandFrame); float in_air_duration = (float)(nLandFrame-nTakeoffFrame) * (1.f/30.f); m_pPlayer->m_AnimationSystemEnabled = 0; m_pEntity->SetAnimationSpeed(in_air_duration/m_fLastJumpDuration); } } //0 means takeoff m_pEntity->SendScriptEvent( ScriptEvent_Jump,0 ); } else if (UserData.p == (void*)JUMP_LAND) { m_pGame->GetSystem()->GetILog()->Log("\003 [AIWARNING] -------%s--------------- LANDED!! --------------------------------",sAnimation); m_pEntity->SetAnimationSpeed(1.f); m_pPlayer->m_AnimationSystemEnabled = 1; pe_action_move motion; motion.dir.Set(0,0,0); motion.iJump = 0; m_pEntity->GetPhysics()->Action(&motion); //1 means landing m_pEntity->SendScriptEvent( ScriptEvent_Jump,1 ); } else m_pEntity->OnAnimationEvent(sAnimation,UserData); } void CXPuppetProxy::OnEndAnimation(const char *sAnimation) { { ICryCharInstance *pCharacter = m_pEntity->GetCharInterface()->GetCharacter(0); if (pCharacter) { m_pGame->GetSystem()->GetILog()->Log("\003 [AIWARNING] ---------------------- %s animation ended ------------------------------",sAnimation); m_bInJump = false; //m_pGame->GetSystem()->GetILog()->Log("\001 [AIWARNING] Entity %s removed a callback for animation %s (char %p)",m_pEntity->GetName(), sAnimation, pCharacter); pCharacter->RemoveAnimationEvent(sAnimation,13,(void*)JUMP_TAKEOFF); pCharacter->RemoveAnimationEvent(sAnimation,29,(void*)JUMP_LAND); pCharacter->RemoveAnimationEventSink(sAnimation,this); m_pEntity->SetAnimationSpeed(1.f); m_pPlayer->m_AnimationSystemEnabled = 1; } } } bool CXPuppetProxy::CheckStatus(unsigned char status) { switch( status ){ case AIPROXYSTATUS_INVEHICLE: if( m_pPlayer->GetVehicle() ) return true; return false; } return false; } void CXPuppetProxy::ApplyHealth(float fHealth) { if (m_pPlayer) { if (fHealth > 1.f) m_pPlayer->m_stats.health = (int)fHealth; } } void CXPuppetProxy::ApplyMovement(pe_action_move * move_params, SOBJECTSTATE *state) { FUNCTION_PROFILER(m_pGame->GetSystem(),PROFILE_AI ); if (!m_pGame->cv_game_AllowAIMovement->GetIVal()) m_fMovementRestrictionDuration = 1.f; // AI is not allowed to move if (m_fMovementRestrictionDuration>0) { m_fMovementRestrictionDuration-=m_pGame->GetSystem()->GetITimer()->GetFrameTime(); SAIEVENT event; event.nDeltaHealth=0; m_pEntity->GetAI()->Event(AIEVENT_MOVEMENT_CONTROL,&event); move_params->dir.Set(0,0,0); move_params->iJump = 0; m_pEntity->GetPhysics()->Action(move_params); return; } if (!m_pGame->ai_num_of_bots->GetIVal()) { m_pEntity->GetPhysics()->Action(move_params); return; } if (m_SAF.bMoving) { // puppet is already moving m_pEntity->GetPhysics()->Action(move_params); } else { // puppet is still stationary if (!m_SAF.bMovePending) { if (state->vMoveDir.Length() > 0) { m_SAF.bMovePending = true; Vec3d lookdir; if (state->bHaveTarget) lookdir = state->vTargetPos - m_pEntity->GetAI()->GetPos(); else lookdir = state->vMoveDir; ICryCharInstance *pInstance = m_pEntity->GetCharInterface()->GetCharacter(0); if (pInstance) { CryCharAnimationParams ccap; ccap.nLayerID = 0; ccap.fBlendInTime=0.1f; ccap.fBlendOutTime=0.1f; ccap.nFlags = ccap.FLAGS_ALIGNED; char animName[64] = "s"; if (state->bodystate!=BODYPOS_RELAX) animName[0] = (state->bodystate==BODYPOS_STAND)?'a':'x'; strcat(animName, (state->run)?"run":"walk"); Vec3d angles = ConvertToRadAngles(m_pEntity->GetAI()->GetAngles()); //if (lookdir.Length()>4.f) { float fDot = GetNormalized(lookdir).Dot(angles); if (fDot>0.5f) { strcat(animName,"fwd_start"); } else if (fDot<-0.5f) { // moving generally back, use back start anim if (state->bHaveTarget) strcat(animName,"_turnaround_start"); // pInstance->StartAnimation("srun_turnaround_start",ccap); else strcat(animName,"back_start"); //pInstance->StartAnimation("srunback_start",ccap); } else { float zcross = lookdir.x*angles.y - lookdir.y*angles.x; if (zcross<0.f) strcat(animName,"left_start"); //pInstance->StartAnimation("srunleft_start",ccap); else strcat(animName,"right_start"); //pInstance->StartAnimation("srunright_start",ccap); } pInstance->StartAnimation(animName,ccap); } } } } SAIEVENT event; event.nDeltaHealth=m_bAllowedToMove?1:0; m_pEntity->GetAI()->Event(AIEVENT_MOVEMENT_CONTROL,&event); if (m_bAllowedToMove) m_pEntity->GetPhysics()->Action(move_params); } pe_status_living pdyn; m_pEntity->GetPhysics()->GetStatus(&pdyn); Vec3d velocity = pdyn.vel; velocity.z = 0; if (velocity.Length()>0.0001f) m_SAF.bMoving = true; else { // don't allow puppet to move m_SAF.bMoving = false; SAIEVENT event; event.nDeltaHealth=0; m_pEntity->GetAI()->Event(AIEVENT_MOVEMENT_CONTROL,&event); } if (state->vMoveDir.Length()<0.0001f) m_SAF.bMovePending = false; } void CXPuppetProxy::Load(CStream &stm) { int nPresent=0; //check curr behaviour stm.Read(nPresent); if (nPresent) { char str[255]; stm.Read(str,255); m_AIHandler.SetBehaviour(str); } // check prev stm.Read(nPresent); if (nPresent) { char str[255]; stm.Read(str,255); } int vehicleId; stm.Read(vehicleId); if(vehicleId) { IEntity *pVehicleEnt = m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(vehicleId); if(pVehicleEnt) { m_pEntity->GetScriptObject()->SetValue("theVehicle", pVehicleEnt->GetScriptObject()); m_pGame->GetSystem()->GetILog()->Log(" the vehicle is %s",pVehicleEnt->GetName()); } } } // // void CXPuppetProxy::Load_PATCH_1(CStream &stm) { int nPresent=0; //check curr behaviour stm.Read(nPresent); if (nPresent) { char str[255]; stm.Read(str,255); m_AIHandler.SetBehaviour(str); } // check prev stm.Read(nPresent); if (nPresent) { char str[255]; stm.Read(str,255); } } void CXPuppetProxy::Save(CStream &stm) { // save the current & previous behaviours const char *szString; if (m_AIHandler.m_pBehavior) { stm.Write((int)1); // we have a current behaviour m_AIHandler.m_pBehavior->GetValue("Name",szString); stm.Write(szString); } else stm.Write((int)0); if (m_AIHandler.m_pPreviousBehavior) { stm.Write((int)1); m_AIHandler.m_pPreviousBehavior->GetValue("Name",szString); stm.Write(szString); } else stm.Write((int)0); _SmartScriptObject pVehicle(m_pScriptSystem,true); if( m_pEntity->GetScriptObject()->GetValue("theVehicle", pVehicle)) { int id; pVehicle->GetValue("id", id); stm.Write(id); m_pGame->GetSystem()->GetILog()->Log(" Writing vehicle id %d",id); } else stm.Write((int)0); }