void Level::SetTargetPos( Enemies enemies ) { for( Enemies::iterator it = enemies.begin(); it != enemies.end(); ++it ) { (*it)->SetTargetPos( GetTargetPos() ); } }
//------------------------------------------------------------------------ bool CGunTurret::IsTargetShootable(IEntity *pTarget) { // raycast shootability check Vec3 pos = m_fireHelper.empty() ? GetWeaponPos() : GetSlotHelperPos(eIGS_ThirdPerson, m_fireHelper.c_str(), true); Vec3 tpos = GetTargetPos(pTarget); Vec3 dir = tpos - pos; bool shootable = RayCheck(pTarget, pos, dir); if(!shootable) { // fallback for actors // todo: also use this for shooting pos! CActor *pActor = GetActor(pTarget->GetId()); if(pActor && pActor->GetMovementController()) { SMovementState state; pActor->GetMovementController()->GetMovementState(state); dir = state.eyePosition - pos; shootable = RayCheck(pTarget, pos, dir); } } return shootable; }
//------------------------------------------------------------------------ IEntity *CGunTurret::GetClosestTACShell() { if(g_pGame->GetCVars()->i_auto_turret_target_tacshells == 0) return NULL; float r = m_turretparams.tac_range; if(r == 0.f) return NULL; Vec3 pos = GetWeaponPos(); SProjectileQuery pquery; pquery.box = AABB(Vec3(pos.x-r,pos.y-r,pos.z-r),Vec3(pos.x+r,pos.y+r,pos.z+r)); int count = g_pGame->GetWeaponSystem()->QueryProjectiles(pquery); ETargetClass closest = eTC_NotATarget; float closestDistSq = r*r; IEntity *pClosest = 0; for(int i=0; i<pquery.nCount; ++i) { IEntity *pEntity = pquery.pResults[i]; if(!pEntity || pEntity == GetEntity()) continue; ETargetClass t_class = GetTargetClass(pEntity); if(t_class == eTC_NotATarget) continue; pos = GetTargetPos(pEntity); float distSq=(pos-GetWeaponPos()).len2(); if(closest>=t_class && distSq>closestDistSq) continue; float yaw, pitch; GetTargetAngles(pos,yaw,pitch); if(!IsTargetAimable(yaw,pitch)) continue; bool canShoot = IsTargetShootable(pEntity); if(!canShoot) t_class = eTC_NotATarget; if(distSq < closestDistSq || (t_class>=closest)) { closestDistSq = distSq; closest = t_class; pClosest = pEntity; } } return pClosest; }
void CalcFiringPosition(SActivationInfo* pActInfo, IWeapon* pWeapon) { Vec3 realTargetPos = GetTargetPos( pActInfo ); m_firingPos = realTargetPos; float acc = GetPortFloat( pActInfo, IN_ACCURACY ); if (acc<1) { bool itHits = cry_frand() < acc; if (!itHits) { // what this code does is: // - in the plane perpendicular to the shooting vector, and located at the target, it builds a vector, centered in the target, and rotates it to point in a random direction, but always in the plane // - then it moves along that vector, a random distance (error distance) // - and that is the final to-fire position const float MAX_ERROR_LENGTH = 6.f; // meters const float MIN_ERROR_ANGLE = 2.f; // degrees const float MAX_ERROR_ANGLE = 5.f; // degrees // error angle from weapon to target float errorAngle = MIN_ERROR_ANGLE + (MAX_ERROR_ANGLE-MIN_ERROR_ANGLE) * cry_frand(); // 2d angle, in the plane normal to the vector from weapon to target. float dirErrorAngle = cry_frand() * 360; // could be done with just 1 sqrt instead 2, but is not really worth it here. Vec3 vecToTarget = pActInfo->pEntity->GetPos() - realTargetPos; Vec3 vecToTargetNorm = vecToTarget.GetNormalizedSafe(); Vec3 dirError2D = vecToTargetNorm.GetOrthogonal(); dirError2D = dirError2D.GetRotated( vecToTargetNorm, DEG2RAD(dirErrorAngle) ); float dist = vecToTarget.len(); float errorLen = std::min( dist * tanf( DEG2RAD(errorAngle) ), MAX_ERROR_LENGTH ); m_firingPos = realTargetPos + ( dirError2D * errorLen ); #ifdef DEBUG_NODEFIREWEAPON posTarget = realTargetPos; posOrig = pActInfo->pEntity->GetPos(); posShot = m_firingPos; #endif } } if (GetPortBool( pActInfo, IN_ALIGNTOTARGET )) { UpdateWeaponTM( pActInfo, m_firingPos ); m_lastPos = pActInfo->pEntity->GetWorldPos(); m_lastRotation = pActInfo->pEntity->GetWorldRotation(); } pWeapon->SetDestination( m_firingPos ); }
//------------------------------------------------------------------------ //chr safe to remove? bool CGunTurret::IsTargetCloaked(IActor *pActor) const { // cloak check if(m_turretparams.find_cloaked) return false; bool cloaked = false; // if destinationId assigned, target can always be found if(m_destinationId && pActor->GetEntityId() == m_destinationId) return false; if(cloaked && m_turretparams.light_fov != 0.f) { // if cloaked, target can only be found with searchlight // check if target inside light cone const Matrix34 &weaponTM = GetEntity()->GetSlotWorldTM(eIGS_ThirdPerson); Vec3 wpos(weaponTM.GetTranslation()); Vec3 wdir(weaponTM.GetColumn1()); Vec3 tpos(GetTargetPos(pActor->GetEntity())); float epsilon = 0.8f; Quat rot = Quat::CreateRotationAA(epsilon*0.5f*DEG2RAD(m_turretparams.light_fov), weaponTM.GetColumn2()); Vec3 a = wpos + m_turretparams.mg_range*(wdir*rot); Vec3 b = wpos + m_turretparams.mg_range*(wdir*rot.GetInverted()); bool inside = Overlap::PointInTriangle(tpos, wpos, a, b, weaponTM.GetColumn2()); if(inside) { rot = Quat::CreateRotationAA(0.5f*DEG2RAD(m_turretparams.light_fov), weaponTM.GetColumn0()); a = wpos + m_turretparams.mg_range*(wdir*rot); b = wpos + m_turretparams.mg_range*(wdir*rot.GetInverted()); inside = Overlap::PointInTriangle(tpos, wpos, a, b, weaponTM.GetColumn0()); } cloaked = !inside; if(g_pGameCVars->i_debug_turrets == eGTD_Search) { IRenderAuxGeom *pGeom = gEnv->pRenderer->GetIRenderAuxGeom(); pGeom->SetRenderFlags(e_Def3DPublicRenderflags); float color[] = {1,1,1,1}; Vec3 points[] = {wpos, a, b}; pGeom->DrawPolyline(points, 3, true, ColorB(0,255,0,255)); if(inside) gEnv->pRenderer->Draw2dLabel(200,200,1.4f,color,false,"target inside cone"); } } return cloaked; }
// プレイヤーを対象に向ける static void LookAtRef(TESObjectREFR* akRef, float wait) { if (akRef == NULL) return; // akRef->Is3DLoaded() if (akRef->GetNiNode() == NULL) return; NiPoint3 targetPos; if (!GetTargetPos(akRef, &targetPos)) return; LookAt(targetPos.x, targetPos.y, targetPos.z, wait); }
int CMob::StandingByProcessor(void) { int rt = FALSE; if (RouteType == 5 || Affect[0].Type == 24) { int Face = MOB.Equip[0].sIndex; if (Leader == 0 && (Affect[0].Type == 24 || Face >= 315 && Face <= 345)) { rt |= 0x100; return rt; } if (Leader <= 0 || Leader >= MAX_USER) { rt |= 1; return rt; } if (Affect[0].Type == 24 || Face >= 315 && Face <= 345) { int summoner = Summoner; if (summoner <= 0 || summoner >= MAX_USER) { rt |= 1; return rt; } int _leader = 0; if (Leader == summoner) _leader = 1; for (int i = 0; i < MAX_PARTY; ++i) { if (pMob[Leader].PartyList[i] == summoner) _leader = 1; } if (_leader == 0) { rt |= 1; return rt; } if (pUser[summoner].Mode != USER_PLAY) { rt |= 1; return rt; } int Distance = BASE_GetDistance(TargetX, TargetY, pMob[summoner].TargetX, pMob[summoner].TargetY); if (Distance >= 13) { NextX = pMob[summoner].TargetX; NextY = pMob[summoner].TargetY; rt = rt | 0x02; return rt; } if (Distance <= 4 || Distance >= 13) return rt; SegmentX = pMob[summoner].TargetX; SegmentY = pMob[summoner].TargetY; GetTargetPos(summoner); rt = rt | 0x01; return rt; } rt = rt |= 1; return rt; } else { if (Leader == 0) { int enemy = GetEnemyFromView(); if (enemy && TargetX <= SegmentX + HALFGRIDX && TargetX >= SegmentX - HALFGRIDX && TargetY >= SegmentY - HALFGRIDY && TargetY <= SegmentY + HALFGRIDY) return enemy | 0x10000000; } if (RouteType == 6 && TargetX == SegmentX && TargetY == SegmentY) return 0; if (SegmentX == TargetX && SegmentY == TargetY) { if(SegmentProgress == 4 && RouteType == 3) { if(WaitSec <= 0) return 0x10000; else WaitSec -= 6; return 0; } if (WaitSec <= 0 || RouteType == 6) { int Seg = SegmentWait[SegmentProgress]; if (Seg > 0) { WaitSec = Seg; return 0; } } else { WaitSec -= 6; if (WaitSec > 0) { if (RouteType && TargetX != SegmentListX[0] || TargetY != SegmentListY[0]) { if (MOB.BaseScore.AttackRun & 0xF) return rt | 0x10; return 0; } else return 0; } WaitSec = 0; } int SetSeg = SetSegment(); if (SetSeg == 1) return 0; if (SetSeg == 2) return rt | 1; if (SetSeg == 0x10) return rt | 1; } GetNextPos(0); if (NextX != TargetX || NextY != TargetY) return rt | 1; else { SetSegment(); return rt; } } return rt; }
void plCameraModifier1::Update() { // update the brain // this freeze thing is a useful debugging tool... if (plVirtualCam1::Instance()->freeze) return; if (GetBrain()) { if (fUpdateBrainTarget && fTarget->GetCoordinateInterface()) // if we need to update the brain and the target is loaded { fUpdateBrainTarget = false; GetBrain()->AddTarget(); // update the brain's target } bool moveInSub = !(GetBrain()->HasFlag(plCameraBrain1::kIgnoreSubworldMovement)); if (moveInSub && GetBrain()->GetSubject()) { plKey worldKey = nil; // First check if this is a physical. If so, grab the subworld from that if (GetBrain()->GetSubject()->GetSimulationInterface()) { plPhysical* phys = GetBrain()->GetSubject()->GetSimulationInterface()->GetPhysical(); if (phys) worldKey = phys->GetWorldKey(); } // Also, check if this is an avatar. They don't have physicals, you // have to ask the avatar controller for the subworld key. if (!worldKey) { plKey subject = plKey(GetBrain()->GetSubject()->GetKey()); plArmatureMod* armMod = plAvatarMgr::FindAvatar(subject); if (armMod && armMod->GetController() ) worldKey = armMod->GetController()->GetSubworld(); } if (worldKey) { // this picks up and moves the camera to it's previous subworld coordinate (so the subworld isn't moving out from underneath us) hsMatrix44 l2w, w2l; plSceneObject* so = plSceneObject::ConvertNoRef(worldKey->ObjectIsLoaded()); if (so) { l2w = so->GetLocalToWorld(); w2l = so->GetWorldToLocal(); if (fInSubLastUpdate) { if (!(fLastSubPos == fFrom && fLastSubPOA == fAt)) { SetTargetPos(l2w * fLastSubPos); SetTargetPOA(l2w * fLastSubPOA); } } else { fInSubLastUpdate = true; } GetBrain()->Update(); fLastSubPos = w2l * GetTargetPos(); fLastSubPOA = w2l * GetTargetPOA(); } return; } else { fInSubLastUpdate = false; } } GetBrain()->Update(); fLastSubPos = GetTargetPos(); fLastSubPOA = GetTargetPOA(); } }
void Level::GoalReached( boost::shared_ptr<Enemy> e ) { FreeTargetPos( e->GetTargetPos() ); e->SetTargetPos( GetTargetPos() ); }
// 一定距離内に居るアクターをすべて返す VMArray<Actor*> FindCloseActor(float distance, UInt32 sortOrder) { enum Order { kSortOrder_distance = 0, // 距離が近い順 kSortOrder_crosshair = 1, // クロスヘアに近い順 kSortOrder_zaxis_clock = 2, // Z軸時計回り kSortOrder_zaxis_rclock = 3, // Z軸逆時計回り kSortOrder_invalid = 4 }; double fovThreshold = (double)PlayerCamera::GetSingleton()->worldFOV / 180.0 * M_PI /2; VMArray<Actor*> result; result.arr = NULL; tArray<UInt32>* actorHandles = &(*s_cellInfo)->actorHandles; if (actorHandles->count == 0) return result; std::vector<std::pair<double, Actor*>> vec; vec.reserve(actorHandles->count); PlayerCharacter* player = *g_thePlayer; NiPoint3 camPos; GetCameraPos(&camPos); UInt32 handle; size_t i = 0; while (actorHandles->GetNthItem(i++, handle)) { TESObjectREFR* ref = NULL; if (handle != *g_invalidRefHandle) LookupREFRByHandle(&handle, &ref); if (ref && ref->formType == kFormType_Character) { Actor* actor = (Actor*)ref; NiPoint3 pos; GetTargetPos(actor, &pos); double dx = pos.x - camPos.x; double dy = pos.y - camPos.y; double dz = pos.z - camPos.z; double dd = sqrt(dx*dx + dy*dy + dz*dz); if (distance <= 0 || dd <= distance) { double point; NiPoint3 cameraAngle; GetCameraAngle(&cameraAngle); double angleZ = NormalRelativeAngle(atan2(dx, dy) - cameraAngle.z); double angleX = NormalRelativeAngle(atan2(-dz, sqrt(dx*dx + dy*dy)) - cameraAngle.x); if (abs(angleZ) < fovThreshold) { switch (sortOrder) { case kSortOrder_distance: point = dd; break; case kSortOrder_crosshair: point = sqrt(angleZ*angleZ + angleX*angleX); break; case kSortOrder_zaxis_clock: point = NormalAbsoluteAngle(atan2(dx, dy) - cameraAngle.z); break; case kSortOrder_zaxis_rclock: point = 2*M_PI - NormalAbsoluteAngle(atan2(dx, dy) - cameraAngle.z); break; default: point = 0; break; } if (point >= 0) { vec.push_back(std::make_pair(point, actor)); } } } } } if (vec.size() == 0) return result; if (sortOrder < kSortOrder_invalid) std::sort(vec.begin(), vec.end()); // Papyrusに返す配列を確保 if (result.Allocate(vec.size())) { for (i = 0; i < vec.size(); i++) { result.Set(&vec[i].second, i); } } return result; }
//------------------------------------------------------------------------ IEntity *CGunTurret::GetClosestTarget() { float r = MAX(m_turretparams.mg_range, m_turretparams.rocket_range); Vec3 pos = GetWeaponPos(); IEntity *pClosest = 0; float closestDistSq=sqr(r); ETargetClass closest = eTC_NotATarget; SEntityProximityQuery query; query.box = AABB(Vec3(pos.x-r,pos.y-r,pos.z-r),Vec3(pos.x+r,pos.y+r,pos.z+r)); int count=gEnv->pEntitySystem->QueryProximity(query); for(int i=0; i<query.nCount; i++) { IEntity *pEntity = query.pEntities[i]; if(!pEntity || pEntity == GetEntity()) continue; // check parent (and siblings) the turret might be linked to, to not attack them if(IEntity *pParent = GetEntity()->GetParent()) { if(pEntity == pParent) continue; int nChildren = pParent->GetChildCount(); for(int j=0; j<nChildren; ++j) { if(pParent->GetChild(j) == pEntity) continue; } } ETargetClass t_class = GetTargetClass(pEntity); if(t_class == eTC_NotATarget) continue; Vec3 tpos = GetTargetPos(pEntity); if(!IsInRange(tpos,t_class)) continue; float distSq=(tpos-pos).len2(); if(closest>=t_class && distSq>closestDistSq) continue; bool canShoot = IsTargetShootable(pEntity); if(!canShoot) t_class = eTC_NotATarget; else if(distSq < closestDistSq || (t_class>=closest)) { closestDistSq = distSq; closest = t_class; pClosest = pEntity; } } if(closest==eTC_NotATarget && !m_turretparams.surveillance) return 0; return pClosest; }
//------------------------------------------------------------------------ Vec3 CGunTurret::PredictTargetPos(IEntity *pTarget, bool sec)//sec - weapon to use { pTarget = ResolveTarget(pTarget); Vec3 tpos = GetTargetPos(pTarget); if(m_turretparams.search_only || m_turretparams.prediction == 0.f) return tpos; IPhysicalEntity *pe = pTarget->GetPhysics(); pe_status_dynamics dyn; if(!pe || !pe->GetStatus(&dyn)) return tpos; Vec3 vel = dyn.v; Vec3 acc = dyn.a; float a = acc.len(); if(a < 0.01f) a = 0.f; else acc /= a; Vec3 vpos = GetWeaponPos(); Vec3 dist = tpos-vpos; float d = dist.len(); if(d < 0.01f) return tpos; dist /= d; float d_speed = vel*dist; float speed = 800.0f; const SAmmoParams *ammo = g_pGame->GetWeaponSystem()->GetAmmoParams(GetFireMode(0)->GetAmmoType()); if(!ammo) return tpos; if(ammo->physicalizationType == ePT_None) return tpos; speed = ammo->speed; float time_to = d/max(1.f, speed-d_speed); // MR: clamped acc prediction to reduce jerkyness when targetting objects that are able // to do near-instant velocity changes (like players) a = min(a, 25.f); Vec3 delta = vel*(time_to) + 0.5f*a*acc*time_to*time_to; delta *= m_turretparams.prediction; if(g_pGameCVars->i_debug_turrets == eGTD_Prediction) { IPersistantDebug *pDebug = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug(); pDebug->Begin("CGunTurret::PredictTargetPos", false); pDebug->AddSphere(tpos+delta, 0.2f, ColorF(1,0,0,1), 1.f); gEnv->pRenderer->DrawLabel(vpos, 1.4f, "Predict %s: speed %.1f (dspeed %.1f), acc %.1f, time %.1f", pTarget->GetName(), vel.len(), d_speed, a, time_to); } return tpos+delta; }