1181 lines
30 KiB
C++
1181 lines
30 KiB
C++
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Source code
|
|
// Copyright (c) Crytek 2001-2004
|
|
//
|
|
// XPuppetProxy.cpp: implementation of the CXPuppetProxy class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "XPuppetProxy.h"
|
|
#include <IScriptSystem.h>
|
|
#include "Game.h"
|
|
#include "XPlayer.h"
|
|
#include "XVehicle.h"
|
|
#include "WeaponClass.h"
|
|
#include "ScriptObjectVector.h"
|
|
#include "XEntityProcessingCmd.h"
|
|
#include <CryCharAnimationParams.h>
|
|
#include <float.h>
|
|
|
|
#include <IAISystem.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// 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;
|
|
}
|
|
|
|
//<<FIXME>> 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);
|
|
|
|
} |