bool CDialogActorContext::ExecuteAI(int& goalPipeID, const char* signalText, IAISignalExtraData* pExtraData, bool bRegisterAsListener) { IEntitySystem* pSystem = gEnv->pEntitySystem; IEntity* pEntity = pSystem->GetEntity(m_entityID); if (pEntity == 0) return false; IAIObject* pAI = pEntity->GetAI(); if (pAI == 0) return false; unsigned short nType=pAI->GetAIType(); if ( nType != AIOBJECT_ACTOR ) { if ( nType == AIOBJECT_PLAYER ) { goalPipeID = -1; // not needed for player // pAI->SetSignal( 10, signalText, pEntity, NULL ); // 10 means this signal must be sent (but sent[!], not set) // even if the same signal is already present in the queue return true; } // invalid AIObject type return false; } IPipeUser* pPipeUser = pAI->CastToIPipeUser(); if (pPipeUser) { if (goalPipeID > 0) { pPipeUser->RemoveSubPipe(goalPipeID, true); pPipeUser->UnRegisterGoalPipeListener( this, goalPipeID ); goalPipeID = 0; } } goalPipeID = gEnv->pAISystem->AllocGoalPipeId(); if (pExtraData == 0) pExtraData = gEnv->pAISystem->CreateSignalExtraData(); pExtraData->iValue = goalPipeID; if (pPipeUser && bRegisterAsListener) { pPipeUser->RegisterGoalPipeListener( this, goalPipeID, "CDialogActorContext::ExecuteAI"); } IAIActor* pAIActor = CastToIAIActorSafe(pAI); if(pAIActor) pAIActor->SetSignal( 10, signalText, pEntity, pExtraData ); // 10 means this signal must be sent (but sent[!], not set) // even if the same signal is already present in the queue return true; }
////////////////////////////////////////////////////////////////////////// // IsMountedWeaponUsableWithTarget // A piece of game-code moved from CryAction when scriptbind_AI moved to the AI system ////////////////////////////////////////////////////////////////////////// int CScriptBind_Game::IsMountedWeaponUsableWithTarget(IFunctionHandler *pH) { int paramCount = pH->GetParamCount(); if(paramCount<2) { GameWarning("%s: too few parameters.", __FUNCTION__); return pH->EndFunction(); } GET_ENTITY(1); if(!pEntity) { GameWarning("%s: wrong entity id in parameter 1.", __FUNCTION__); return pH->EndFunction(); } IAIObject* pAI = pEntity->GetAI(); if (!pAI) { GameWarning("%s: Entity '%s' does not have AI.",__FUNCTION__, pEntity->GetName()); return pH->EndFunction(); } EntityId itemEntityId; ScriptHandle hdl2; if(!pH->GetParam(2,hdl2)) { GameWarning("%s: wrong parameter 2 format.", __FUNCTION__); return pH->EndFunction(); } itemEntityId = (EntityId)hdl2.n; if (!itemEntityId) { GameWarning("%s: wrong entity id in parameter 2.", __FUNCTION__); return pH->EndFunction(); } IGameFramework *pGameFramework = gEnv->pGame->GetIGameFramework(); IItem* pItem = pGameFramework->GetIItemSystem()->GetItem(itemEntityId); if (!pItem) { //gEnv->pAISystem->Warning("<CScriptBind> ", "entity in parameter 2 is not an item/weapon"); GameWarning("%s: entity in parameter 2 is not an item/weapon.", __FUNCTION__); return pH->EndFunction(); } float minDist = 7; bool bSkipTargetCheck = false; Vec3 targetPos(ZERO); if(paramCount > 2) { for(int i=3;i <= paramCount ; i++) { if(pH->GetParamType(i) == svtBool) pH->GetParam(i,bSkipTargetCheck); else if(pH->GetParamType(i) == svtNumber) pH->GetParam(i,minDist); else if(pH->GetParamType(i) == svtObject) pH->GetParam(i,targetPos); } } IAIActor* pAIActor = CastToIAIActorSafe(pAI); if (!pAIActor) { GameWarning("%s: entity '%s' in parameter 1 is not an AI actor.", __FUNCTION__, pEntity->GetName()); return pH->EndFunction(); } IEntity* pItemEntity = pItem->GetEntity(); if(!pItemEntity) return pH->EndFunction(); if(!pItem->GetOwnerId()) { // weapon is not used, check if it is on a vehicle IEntity* pParentEntity = pItemEntity->GetParent(); if(pParentEntity) { IAIObject* pParentAI = pParentEntity->GetAI(); if(pParentAI && pParentAI->GetAIType()==AIOBJECT_VEHICLE) { // (MATT) Feature was cut and code was tricky, hence ignore weapons in vehicles {2008/02/15:11:08:51} return pH->EndFunction(); } } } else if( pItem->GetOwnerId()!= pEntity->GetId()) // item is used by someone else? return pH->EndFunction(false); // check target if(bSkipTargetCheck) return pH->EndFunction(true); IAIObject* pTarget = pAIActor->GetAttentionTarget(); if(targetPos.IsZero()) { if(!pTarget) return pH->EndFunction(); targetPos = pTarget->GetPos(); } Vec3 targetDir(targetPos - pItemEntity->GetWorldPos()); Vec3 targetDirXY(targetDir.x, targetDir.y, 0); float length2D = targetDirXY.GetLength(); if(length2D < minDist || length2D<=0) return pH->EndFunction(); targetDirXY /= length2D;//normalize IWeapon* pWeapon = pItem->GetIWeapon(); bool vehicleGun = pWeapon && pWeapon->GetHostId(); if (!vehicleGun) { Vec3 mountedAngleLimits(pItem->GetMountedAngleLimits()); float yawRange = DEG2RAD(mountedAngleLimits.z); if(yawRange > 0 && yawRange < gf_PI) { float deltaYaw = pItem->GetMountedDir().Dot(targetDirXY); if(deltaYaw < cosf(yawRange)) return pH->EndFunction(false); } float minPitch = DEG2RAD(mountedAngleLimits.x); float maxPitch = DEG2RAD(mountedAngleLimits.y); //maxPitch = (maxPitch - minPitch)/2; //minPitch = -maxPitch; float pitch = atanf(targetDir.z / length2D); if ( pitch < minPitch || pitch > maxPitch ) return pH->EndFunction(false); } if(pTarget) { IEntity* pTargetEntity = pTarget->GetEntity(); if(pTargetEntity) { // check target distance and where he's going IPhysicalEntity *phys = pTargetEntity->GetPhysics(); if(phys) { pe_status_dynamics dyn; phys->GetStatus(&dyn); Vec3 velocity ( dyn.v); velocity.z = 0; float speed = velocity.GetLength2D(); if(speed>0) { //velocity /= speed; if(length2D< minDist * 0.75f && velocity.Dot(targetDirXY)<=0) return pH->EndFunction(false); } } } } return pH->EndFunction(true); }
//------------------------------------------------------------------------ void CProjectile::Launch(const Vec3 &pos, const Vec3 &dir, const Vec3 &velocity, float speedScale) { Matrix34 worldTM=Matrix34(Matrix33::CreateRotationVDir(dir.GetNormalizedSafe())); worldTM.SetTranslation(pos); GetEntity()->SetWorldTM(worldTM); //Must set velocity after position, if not velocity could be reseted for PE_RIGID SetVelocity(pos, dir, velocity, speedScale); m_initial_pos = pos; m_initial_dir = dir; m_initial_vel = velocity; m_last = pos; // Attach effect when fired (not first update) if (m_trailEffectId<0) TrailEffect(true); IAIObject* pAI = 0; if ((pAI = GetEntity()->GetAI()) != NULL && pAI->GetAIType() == AIOBJECT_GRENADE) { IEntity *pOwnerEntity = gEnv->pEntitySystem->GetEntity(m_ownerId); if (pOwnerEntity && pOwnerEntity->GetAI()) { pe_status_dynamics dyn; pe_status_dynamics dynProj; if (pOwnerEntity->GetAI()->GetProxy() && pOwnerEntity->GetPhysics() && pOwnerEntity->GetPhysics()->GetStatus(&dyn) && GetEntity()->GetPhysics()->GetStatus(&dynProj)) { Vec3 ownerVel( dyn.v); Vec3 grenadeDir(dynProj.v.GetNormalizedSafe()); // Trigger the signal at the predicted landing position. Vec3 predictedPos = pos; float dummySpeed; if (GetWeapon()) GetWeapon()->PredictProjectileHit(pOwnerEntity->GetPhysics(), pos, dir, velocity, speedScale * m_pAmmoParams->speed, predictedPos, dummySpeed); /* bool res = pOwnerEntity->GetAI()->GetProxy()->GetSecWeapon()->PredictProjectileHit( pOwnerEntity->GetPhysics(), GetEntity()->GetPos(), grenadeDir, ownerVel, 1, predictedPos, speed);*/ gEnv->pAISystem->GrenadeEvent(predictedPos, 0.0f, AIGE_GRENADE_THROWN, GetEntity(), pOwnerEntity); // Inform the AI that sees the throw /* IAIObject* pOwnerAI = pOwnerEntity->GetAI(); AutoAIObjectIter it(gEnv->pAISystem->GetFirstAIObjectInRange(IAISystem::OBJFILTER_TYPE, AIOBJECT_PUPPET, predictedPos, 20.0f, false)); for(; it->GetObject(); it->Next()) { IAIObject* pAI = it->GetObject(); if (!pAI->IsEnabled()) continue; if (pOwnerAI && !pOwnerAI->IsHostile(pAI,false)) continue; // Only sense grenades that are on front of the AI and visible when thrown. // Another signal is sent when the grenade hits the ground. Vec3 delta = GetEntity()->GetPos() - pAI->GetPos(); // grenade to AI float dist = delta.NormalizeSafe(); const float thr = cosf(DEG2RAD(160.0f)); if (delta.Dot(pAI->GetViewDir()) > thr) { ray_hit hit; static const int objTypes = ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid; static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; int res = gEnv->pPhysicalWorld->RayWorldIntersection(pAI->GetPos(), delta*dist, objTypes, flags, &hit, 1); if (!res || hit.dist > dist*0.9f) { IAISignalExtraData* pEData = gEnv->pAISystem->CreateSignalExtraData(); // no leak - this will be deleted inside SendAnonymousSignal pEData->point = predictedPos; pEData->nID = pOwnerEntity->GetId(); pEData->iValue = 1; gEnv->pAISystem->SendSignal(SIGNALFILTER_SENDER, 1, "OnGrenadeDanger", pAI, pEData); } } } */ } } } }
//------------------------------------------------------------------------ void CProjectile::Launch(const Vec3 &pos, const Vec3 &dir, const Vec3 &velocity, float speedScale) { m_destroying = false; GetGameObject()->EnablePhysicsEvent(true, eEPE_OnCollisionLogged); // Only for bullets m_hitPoints = m_pAmmoParams->hitPoints; m_hitListener = false; if(m_hitPoints>0) { //Only projectiles with hit points are hit listeners g_pGame->GetGameRules()->AddHitListener(this); m_hitListener = true; m_noBulletHits = m_pAmmoParams->noBulletHits; } Matrix34 worldTM=Matrix34(Matrix33::CreateRotationVDir(dir.GetNormalizedSafe())); worldTM.SetTranslation(pos); GetEntity()->SetWorldTM(worldTM); //Must set velocity after position, if not velocity could be reseted for PE_RIGID SetVelocity(pos, dir, velocity, speedScale); m_initial_pos = pos; m_initial_dir = dir; m_initial_vel = velocity; m_last = pos; // Attach effect when fired (not first update) if(m_trailEffectId<0) TrailEffect(true); IAIObject *pAI = 0; if((pAI = GetEntity()->GetAI()) != NULL && pAI->GetAIType() == AIOBJECT_GRENADE) { IEntity *pOwnerEntity = gEnv->pEntitySystem->GetEntity(m_ownerId); pe_status_dynamics dyn; pe_status_dynamics dynProj; if(pOwnerEntity->GetPhysics() && pOwnerEntity->GetPhysics()->GetStatus(&dyn) && GetEntity()->GetPhysics()->GetStatus(&dynProj)) { // Vec3 ownerVel(dyn.v); Vec3 grenadeDir(dynProj.v.GetNormalizedSafe()); // Trigger the signal at the predicted landing position. Vec3 predictedPos = pos; float dummySpeed; if(GetWeapon()) GetWeapon()->PredictProjectileHit(pOwnerEntity->GetPhysics(), pos, dir, velocity, speedScale * m_pAmmoParams->speed, predictedPos, dummySpeed); // Associate event with vehicle if the shooter is in a vehicle (tank cannon shot, etc) EntityId ownerId = pOwnerEntity->GetId(); IActor *pActor = g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(ownerId); if(pActor && pActor->GetLinkedVehicle() && pActor->GetLinkedVehicle()->GetEntityId()) ownerId = pActor->GetLinkedVehicle()->GetEntityId(); SAIStimulus stim(AISTIM_GRENADE, AIGRENADE_THROWN, ownerId, GetEntityId(), predictedPos, ZERO, 20.0f); gEnv->pAISystem->RegisterStimulus(stim); } } }
//------------------------------------------------------------------------ void CProjectile::HandleEvent(const SGameObjectEvent &event) { if(m_destroying) return; FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); if(event.event == eGFE_OnCollision) { EventPhysCollision *pCollision = (EventPhysCollision *)event.ptr; if(pCollision == NULL) return; const SCollisionParams *pCollisionParams = m_pAmmoParams->pCollision; if(pCollisionParams) { if(pCollisionParams->pParticleEffect) pCollisionParams->pParticleEffect->Spawn(true, IParticleEffect::ParticleLoc(pCollision->pt, pCollision->n, pCollisionParams->scale)); if(pCollisionParams->sound) { _smart_ptr<ISound> pSound = gEnv->pSoundSystem->CreateSound(pCollisionParams->sound, FLAG_SOUND_DEFAULT_3D); if(pSound) { pSound->SetSemantic(eSoundSemantic_Projectile); pSound->SetPosition(pCollision->pt); pSound->Play(); } } } // add battledust for bulletimpact if(gEnv->bServer && g_pGame->GetGameRules()) { if(CBattleDust *pBD = g_pGame->GetGameRules()->GetBattleDust()) { pBD->RecordEvent(eBDET_ShotImpact, pCollision->pt, GetEntity()->GetClass()); } } Ricochet(pCollision); //Update damage if((m_damageDropPerMeter>0.0001f)&& (((pCollision->pt-m_initial_pos).len2()>m_damageDropMinDisSqr)||m_firstDropApplied)) { if(!m_firstDropApplied) { m_firstDropApplied = true; m_initial_pos = m_initial_pos + (m_initial_dir*(sqrt_fast_tpl(m_damageDropMinDisSqr))); } Vec3 vDiff = pCollision->pt - m_initial_pos; float dis = vDiff.len(); m_damage -= (int)(floor_tpl(m_damageDropPerMeter * dis)); //Check m_damage is positive if(m_damage<MIN_DAMAGE) m_damage=MIN_DAMAGE; //Also modify initial position (the projectile could not be destroyed, cause of pirceability) m_initial_pos = pCollision->pt; } // Notify AI system about grenades. if(gEnv->pAISystem) { IAIObject *pAI = 0; if((pAI = GetEntity()->GetAI()) != NULL && pAI->GetAIType() == AIOBJECT_GRENADE) { // Associate event with vehicle if the shooter is in a vehicle (tank cannon shot, etc) EntityId ownerId = m_ownerId; IActor *pActor = g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(ownerId); if(pActor && pActor->GetLinkedVehicle() && pActor->GetLinkedVehicle()->GetEntityId()) ownerId = pActor->GetLinkedVehicle()->GetEntityId(); SAIStimulus stim(AISTIM_GRENADE, AIGRENADE_COLLISION, ownerId, GetEntityId(), GetEntity()->GetWorldPos(), ZERO, 12.0f); gEnv->pAISystem->RegisterStimulus(stim); } } } }