/// Use guided matching to find corresponding 2-view correspondences void match( const SfM_Data & sfm_data, const Pair_Set & pairs, const std::shared_ptr<Regions_Provider> & regions_provider) { C_Progress_display my_progress_bar( pairs.size(), std::cout, "Compute pairwise fundamental guided matching:\n" ); #ifdef OPENMVG_USE_OPENMP #pragma omp parallel #endif // OPENMVG_USE_OPENMP for (Pair_Set::const_iterator it = pairs.begin(); it != pairs.end(); ++it) { #ifdef OPENMVG_USE_OPENMP #pragma omp single nowait #endif // OPENMVG_USE_OPENMP { // -- // Perform GUIDED MATCHING // -- // Use the computed model to check valid correspondences // - by considering geometric error and descriptor distance ratio. std::vector<IndMatch> vec_corresponding_indexes; const View * viewL = sfm_data.getViews().at(it->first).get(); const Poses::const_iterator iterPoseL = sfm_data.getPoses().find(viewL->id_pose); const Intrinsics::const_iterator iterIntrinsicL = sfm_data.getIntrinsics().find(viewL->id_intrinsic); const View * viewR = sfm_data.getViews().at(it->second).get(); const Poses::const_iterator iterPoseR = sfm_data.getPoses().find(viewR->id_pose); const Intrinsics::const_iterator iterIntrinsicR = sfm_data.getIntrinsics().find(viewR->id_intrinsic); Mat xL, xR; PointsToMat(iterIntrinsicL->second.get(), regions_provider->regions_per_view.at(it->first)->GetRegionsPositions(), xL); PointsToMat(iterIntrinsicR->second.get(), regions_provider->regions_per_view.at(it->second)->GetRegionsPositions(), xR); const Mat34 P_L = iterIntrinsicL->second.get()->get_projective_equivalent(iterPoseL->second); const Mat34 P_R = iterIntrinsicR->second.get()->get_projective_equivalent(iterPoseR->second); const Mat3 F_lr = F_from_P(P_L, P_R); const double thresholdF = 4.0; #if defined(EXHAUSTIVE_MATCHING) // Guided matching considering geometric error and descriptor distance ratio geometry_aware::GuidedMatching <Mat3, openMVG::fundamental::kernel::EpipolarDistanceError, DescriptorT, L2_Vectorized<DescriptorT::bin_type> >( F_lr, xL, desc_provider.at(it->first), xR, desc_provider.at(it->second), Square(thresholdF), Square(0.8), vec_corresponding_indexes); #else const Vec3 epipole2 = epipole_from_P(P_R, iterPoseL->second); const features::Regions * regions = regions_provider->regions_per_view.at(it->first).get(); if (regions->IsScalar()) { // L2 Metric (Handle descriptor internal type) if(regions->Type_id() == typeid(unsigned char).name()) { geometry_aware::GuidedMatching_Fundamental_Fast< openMVG::fundamental::kernel::EpipolarDistanceError, L2_Vectorized<unsigned char> > ( F_lr, epipole2, regions_provider->regions_per_view.at(it->first).get(), iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(), regions_provider->regions_per_view.at(it->second).get(), Square(thresholdF), Square(0.8), vec_corresponding_indexes); } else if(regions->Type_id() == typeid(float).name()) { geometry_aware::GuidedMatching_Fundamental_Fast< openMVG::fundamental::kernel::EpipolarDistanceError, L2_Vectorized<float> > ( F_lr, epipole2, regions_provider->regions_per_view.at(it->first).get(), iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(), regions_provider->regions_per_view.at(it->second).get(), Square(thresholdF), Square(0.8), vec_corresponding_indexes); } else if(regions->Type_id() == typeid(double).name()) { geometry_aware::GuidedMatching_Fundamental_Fast< openMVG::fundamental::kernel::EpipolarDistanceError, L2_Vectorized<double> > ( F_lr, epipole2, regions_provider->regions_per_view.at(it->first).get(), iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(), regions_provider->regions_per_view.at(it->second).get(), Square(thresholdF), Square(0.8), vec_corresponding_indexes); } } else if (regions->IsBinary() && regions->Type_id() == typeid(unsigned char).name()) { // Hamming metric geometry_aware::GuidedMatching_Fundamental_Fast< openMVG::fundamental::kernel::EpipolarDistanceError, Hamming<unsigned char> > ( F_lr, epipole2, regions_provider->regions_per_view.at(it->first).get(), iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(), regions_provider->regions_per_view.at(it->second).get(), Square(thresholdF), 0.8, vec_corresponding_indexes); } #endif #ifdef OPENMVG_USE_OPENMP #pragma omp critical #endif // OPENMVG_USE_OPENMP { ++my_progress_bar; for (size_t i = 0; i < vec_corresponding_indexes.size(); ++i) putatives_matches[*it].push_back(vec_corresponding_indexes[i]); } } } }
double Error(size_t sample, const Model &model) const { return Square(ErrorT::Error(model, x1_.col(sample), x2_.col(sample))); }
void CTorpedoProjectile::Update() { // tracking only works when we are underwater if (!weaponDef->submissile && pos.y > 0.0f) { if (!luaMoveCtrl) { // must update dir and speed.w here SetVelocityAndSpeed(speed + (UpVector * mygravity)); } } else { if (--ttl > 0) { if (!luaMoveCtrl) { float3 targetVel; if (speed.w < maxSpeed) speed.w += std::max(0.2f, tracking); if (target != NULL) { const CSolidObject* so = dynamic_cast<const CSolidObject*>(target); const CWeaponProjectile* po = dynamic_cast<const CWeaponProjectile*>(target); targetPos = target->pos; if (so != NULL) { targetPos = so->aimPos; targetVel = so->speed; if (allyteamID != -1 && pos.SqDistance(so->aimPos) > Square(150.0f)) { const CUnit* u = dynamic_cast<const CUnit*>(so); if (u != NULL) { targetPos = u->GetErrorPos(allyteamID, true); } } } if (po != NULL) { targetVel = po->speed; } } if (!weaponDef->submissile && targetPos.y > 0.0f) { targetPos.y = 0.0f; } const float3 targetLeadVec = targetVel * (pos.distance(targetPos) / maxSpeed) * 0.7f; const float3 targetLeadDir = (targetPos + targetLeadVec - pos).Normalize(); float3 targetDirDif = targetLeadDir - dir; if (targetDirDif.Length() < tracking) { dir = targetLeadDir; } else { // <tracking> is the projectile's turn-rate targetDirDif = (targetDirDif - (dir * targetDirDif.dot(dir))).SafeNormalize(); dir = (dir + (targetDirDif * tracking)).SafeNormalize(); } // do not need to update dir or speed.w here CWorldObject::SetVelocity(dir * speed.w); } explGenHandler->GenExplosion(cegID, pos, speed, ttl, areaOfEffect, 0.0f, NULL, NULL); } else { if (!luaMoveCtrl) { // must update dir and speed.w here SetVelocityAndSpeed((speed * 0.98f) + (UpVector * mygravity)); } } } if (!luaMoveCtrl) { SetPosition(pos + speed); } if (pos.y < -2.0f) { --nextBubble; if (nextBubble == 0) { nextBubble = 1 + (int) (gs->randFloat() * 1.5f); const float3 pspeed = (gs->randVector() * 0.1f) + float3(0.0f, 0.2f, 0.0f); new CBubbleProjectile( owner(), pos + gs->randVector(), pspeed, 40 + gs->randFloat() * GAME_SPEED, 1 + gs->randFloat() * 2, 0.01f, 0.3f + gs->randFloat() * 0.3f ); } } UpdateGroundBounce(); UpdateInterception(); }
/* ================== idBotAI::Bot_PickBestVehicleWeapon See what the best weapon is that we have at our disposal - we'll change our position in this vehicle if need be to get access to a ( better ) weapon. ================== */ void idBotAI::Bot_PickBestVehicleWeapon() { bool enemyInAirborneVehicle = false; bool enemyInGroundVehicle = false; bool needMovementUpdate = false; bool enemyOnFoot = false; bool hasGunnerSeatOpen; bool enemyReachable = false; if ( weapSwitchTime > botWorld->gameLocalInfo.time ) { return; } if ( botVehicleInfo->type == ICARUS ) { return; } proxyInfo_t enemyVehicleInfo; idVec3 vec = botWorld->clientInfo[ enemy ].origin - botInfo->origin; float dist = vec.LengthSqr(); hasGunnerSeatOpen = VehicleHasGunnerSeatOpen( botInfo->proxyInfo.entNum ); if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.isAirborneVehicle ) { enemyInAirborneVehicle = true; } else { enemyInGroundVehicle = true; } } else { enemyOnFoot = true; } Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( botAAS.hasPath && botAAS.path.travelTime < Bot_ApproxTravelTimeToLocation( botInfo->origin, botWorld->clientInfo[ enemy ].origin, true ) * TRAVEL_TIME_MULTIPLY ) { enemyReachable = true; } switch( botVehicleInfo->type ) { case TITAN: if ( botVehicleInfo->driverEntNum == botNum ) { if ( enemyInAirborneVehicle && enemyInfo.enemyDist <= TANK_MINIGUN_RANGE && hasGunnerSeatOpen ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; break; } } else { if ( ( enemyInAirborneVehicle && enemyInfo.enemyDist > TANK_MINIGUN_RANGE && botVehicleInfo->driverEntNum == -1 ) || !enemyInAirborneVehicle ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } break; case TROJAN: if ( botInfo->proxyInfo.weapon == LAW ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( ( !enemyInAirborneVehicle && !enemyInGroundVehicle ) || enemyInfo.enemyDist < 700.0f || enemyInfo.enemyDist > WEAPON_LOCK_DIST ) { botUcmd->botCmds.becomeDriver = true; //mal: using the LAW to lock onto our vehicle enemy makes sense ( the drivers MG is a joke in this case ). needMovementUpdate = true; break; } } } if ( botVehicleInfo->driverEntNum == botNum ) { if ( ( enemyInAirborneVehicle || enemyInGroundVehicle ) && hasGunnerSeatOpen && dist < Square( WEAPON_LOCK_DIST ) ) { botUcmd->botCmds.becomeGunner = true; //mal: using the LAW to lock onto our airborne enemy makes sense ( the drivers MG is a joke in this case ). needMovementUpdate = true; break; } } if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON ) { if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } else if ( VehicleHasGunnerSeatOpen( botVehicleInfo->entNum ) ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; } break; }//mal: if we're the driver, stay as the driver! break; case BADGER: if ( botVehicleInfo->driverEntNum == botNum ) { //mal: we're the driver, if the turret is available, we may jump into it to fight enemies. if ( hasGunnerSeatOpen && vehicleDriverTime < botWorld->gameLocalInfo.time && enemyReachable && enemyInfo.enemyDist > 700.0f && enemyVehicleInfo.type != HOG ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { vehicleDriverTime = botWorld->gameLocalInfo.time + 15000; break; } if ( ( enemyInAirborneVehicle || ( enemyInfo.enemyDist < 3000.0f && enemyInfo.enemyDist > 700.0f ) ) && vehicleGunnerTime + 30000 < botWorld->gameLocalInfo.time && enemyInfo.enemyVisible ) { //mal: dont do this if enemy too far away, or its been too soon since we last did this. botUcmd->botCmds.becomeGunner = true; vehicleGunnerTime = botWorld->gameLocalInfo.time + 15000; needMovementUpdate = true; break; } } } if ( botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) { if ( hasGunnerSeatOpen && botVehicleInfo->driverEntNum != -1 ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; break; } //mal: our gunner may have been killed, or maybe he jumped out some time ago - take his place. if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( vehicleGunnerTime < botWorld->gameLocalInfo.time || !enemyInfo.enemyVisible ) { //mal: even if we had a driver and he bailed, become the driver for a better shot, then can go back to the gun. botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } } if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && botVehicleInfo->driverEntNum != botNum ) { if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } else if ( VehicleHasGunnerSeatOpen( botVehicleInfo->entNum ) ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; } else if ( botVehicleInfo->hasFreeSeat ) { needMovementUpdate = true; botUcmd->botCmds.activate = true; //mal: rotate to one of the back seats. } }//mal: if we're the driver, stay as the driver! break; case PLATYPUS: if ( botVehicleInfo->driverEntNum == botNum ) { //mal: we're the driver, if the turret is available, we may jump into it to fight enemies. if ( hasGunnerSeatOpen ) { if ( enemyInfo.enemyDist < 1500.0f && vehicleGunnerTime + 30000 < botWorld->gameLocalInfo.time && enemyInfo.enemyVisible ) { //mal: dont do this if enemy too far away, or its been too soon since we last did this. botUcmd->botCmds.becomeGunner = true; vehicleGunnerTime = botWorld->gameLocalInfo.time + 10000; needMovementUpdate = true; } } //mal: if we have a gunner, we'll try to get a better shot for him, so that he can cut down our enemies. } if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( vehicleGunnerTime < botWorld->gameLocalInfo.time || !enemyInfo.enemyVisible ) { //mal: even if we had a driver and he bailed, become the driver for a better shot, then can go back to the gun. botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } } } break; case DESECRATOR: if ( botVehicleInfo->driverEntNum == botNum ) { if ( enemyInAirborneVehicle && enemyInfo.enemyDist <= TANK_MINIGUN_RANGE && hasGunnerSeatOpen ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; break; } } else { if ( ( enemyInAirborneVehicle && enemyInfo.enemyDist > TANK_MINIGUN_RANGE && botVehicleInfo->driverEntNum == -1 ) || !enemyInAirborneVehicle ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } break; case HOG: if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( vehicleGunnerTime < botWorld->gameLocalInfo.time || !enemyInfo.enemyVisible || botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE && !enemyInAirborneVehicle ) { //mal: even if we had a driver and he bailed, become the driver for a better shot, then can go back to the gun. botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } //mal: we'll prefer to ram our enemies who are in vehicles } } if ( botVehicleInfo->driverEntNum == botNum && ( !Bot_VehicleCanRamClient( enemy ) || VEHICLE_COMBAT_MOVEMENT_STATE == NULL || combatMoveType != VEHICLE_RAM_ATTACK_MOVEMENT ) ) { if ( ( enemyInAirborneVehicle || ( enemyInfo.enemyDist < 3000.0f && enemyInfo.enemyDist > 700.0f ) ) && vehicleGunnerTime + 30000 < botWorld->gameLocalInfo.time && enemyInfo.enemyVisible ) { botUcmd->botCmds.becomeGunner = true; vehicleGunnerTime = botWorld->gameLocalInfo.time + 10000; needMovementUpdate = true; } } break; case ANANSI: case HORNET: if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; //mal: our coward of a pilot bailed on us... take the controls! needMovementUpdate = true; } } if ( botVehicleInfo->driverEntNum == botNum ) { if ( botInfo->proxyInfo.weapon == LAW ) { //mal: law is better against other vehicles if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { botUcmd->botCmds.switchVehicleWeap = true; } else { if ( botInfo->proxyInfo.weaponIsReady == false && rocketTime < botWorld->gameLocalInfo.time && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: use rockets if LAW outta charge rocketTime = botWorld->gameLocalInfo.time + 2000; botUcmd->botCmds.switchVehicleWeap = true; } } } if ( botInfo->proxyInfo.weapon == ROCKETS ) { //mal: rockets are nice against slow moving ground targets. if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE && rocketTime < botWorld->gameLocalInfo.time ) { botUcmd->botCmds.switchVehicleWeap = true; } } } break; } if ( needMovementUpdate ) { COMBAT_MOVEMENT_STATE = NULL; VEHICLE_COMBAT_MOVEMENT_STATE = NULL; vehicleUpdateTime = botWorld->gameLocalInfo.time + 500; } weapSwitchTime = botWorld->gameLocalInfo.time + 1500; }
void GameObject::setSquare(const Square& s) { _square = Square(s); }
/* ================ idBotAI::ClientIsAudibleToVehicle Cheaply tells us if the client is question is making enough noise for this vehicle to "notice" them and possibly consider them an enemy. ================ */ bool idBotAI::ClientIsAudibleToVehicle( int clientNum ) { heardClient = -1; // reset this every frame. if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_EASY ) { // stupid bot - you can't hear anyone! return false; } if ( botWorld->botGoalInfo.teamRetreatInfo[ botInfo->team ].retreatTime > botWorld->gameLocalInfo.time ) { return false; } const clientInfo_t& client = botWorld->clientInfo[ clientNum ]; if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && !botWorld->botGoalInfo.gameIsOnFinalObjective && !client.isBot ) { //mal: dont worry about hearing human targets in training mode, unless its the final obj... return false; } float hearingRange = ( client.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) ? PLAYER_HEARING_DIST : VEHICLE_HEARING_DIST; idVec3 vec = client.origin - botInfo->origin; float dist = vec.LengthSqr(); float distTemp = vec.LengthFast(); if ( client.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && client.weapInfo.weapon == SNIPERRIFLE && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { hearingRange = SNIPER_HEARING_DIST; } if ( client.weapInfo.isFiringWeap && dist < Square( hearingRange ) ) { heardClient = clientNum; return true; } if ( dist < Square( FOOTSTEP_DIST ) ) { heardClient = clientNum; return true; } if ( ClientHasObj( clientNum ) && ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY || client.isInRadar ) ) { return true; } if ( client.isInRadar && dist < Square( 1500.0f ) && ( client.abilities.gdfStealthToRadar == false || client.classType != COVERTOPS ) ) { //mal_TODO: test me!!! return true; } if ( ClientIsMarkedForDeath( clientNum, false ) ) { return true; } if ( ClientIsDangerous( clientNum ) ) { //mal: we're "aware" of campers, and will kill them if they're vis to us. heardClient = clientNum; return true; } if ( botInfo->lastAttacker == clientNum && botInfo->lastAttackerTime + 3000 > botWorld->gameLocalInfo.time ) { return true; } if ( ( client.targetLockEntNum == botNum || client.targetLockEntNum == botInfo->proxyInfo.entNum ) && client.targetLockTime + 3000 < botWorld->gameLocalInfo.time ) { return true; } return false; }
/* ================ idBotAI::Bot_VehicleFindBetterEnemy ================ */ bool idBotAI::Bot_VehicleFindBetterEnemy() { int i; int entClientNum = enemy; float dist; float entDist; proxyInfo_t vehicleInfo; proxyInfo_t enemyVehicleInfo; idVec3 vec; if ( enemy == -1 ) { //mal: we lost our enemy for some reason, so just skip finding a new one til next frame. return false; } if ( ignoreNewEnemiesWhileInVehicleTime > botWorld->gameLocalInfo.time ) { return false; } if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { //mal: if we're attacking the MCP, its the priority. if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == botWorld->botGoalInfo.botGoal_MCP_VehicleNum ) { return false; } } GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.entNum > 0 && ( enemyVehicleInfo.type == ANANSI || enemyVehicleInfo.type == HORNET ) ) { //mal: stay in dogfights! return false; } const clientInfo_t& enemyPlayerInfo = botWorld->clientInfo[ enemy ]; vec = enemyPlayerInfo.origin - botInfo->origin; entDist = vec.LengthSqr(); if ( !enemyInfo.enemyVisible ) { //mal: if we can't see our current enemy, more likely to attack a visible enemy. entDist = idMath::INFINITY; } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && !botWorld->botGoalInfo.gameIsOnFinalObjective && ( !enemyPlayerInfo.isBot || enemyPlayerInfo.isActor ) ) { //mal: dont worry about keeping our human target in training mode, unless its the final obj... entDist += Square( TRAINING_MODE_RANGE_ADDITION ); } bool curEnemyNotInVehicle = false; if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !ClientIsDefusingOurTeamCharge( enemy ) && !vehicleEnemyWasInheritedFromFootCombat ) { //mal: if our current enemy is on foot, more likely to pick a better target. Unless they're defusing our charge, or an enemy we jumped in this vehicle for, then we artificially raise their importance. curEnemyNotInVehicle = true; } numVisEnemies = 1; //mal: our current enemy is always visible to us for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !ClientIsValid( i, -1 ) ) { continue; //mal: no valid client in this client slot! } if ( i == botNum ) { continue; //mal: dont try to fight ourselves! } if ( i == enemy ) { //mal: ignore an enemy we already have continue; } if ( EnemyIsIgnored( i ) ) { continue; //mal: dont try to fight someone we've flagged to ignore for whatever reason! } //mal: if we're in the middle of a critical obj, dont go looking for trouble, unless they're shooting us! if ( Client_IsCriticalForCurrentObj( botNum, -1.0f ) && ( botInfo->lastAttacker != i || botInfo->lastAttackerTime + 3000 < botWorld->gameLocalInfo.time ) && !ClientIsDefusingOurTeamCharge( i ) ) { continue; } const clientInfo_t& playerInfo = botWorld->clientInfo[ i ]; if ( playerInfo.isNoTarget ) { continue; } //mal: dont target clients that have notarget set - this is useful for debugging, etc. if ( playerInfo.isDisguised && playerInfo.disguisedClient != botNum ) { continue; //mal: won't "see" disguised clients, unless they look like us! } if ( playerInfo.inLimbo ) { continue; } if ( playerInfo.isActor ) { continue; } if ( playerInfo.invulnerableEndTime > botWorld->gameLocalInfo.time ) { continue; //mal: ignore revived/just spawned in clients - get the ppl around them! } if ( playerInfo.health <= 0 ) { continue; } if ( playerInfo.team == botInfo->team ) { continue; } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && !botWorld->botGoalInfo.gameIsOnFinalObjective && !playerInfo.isBot && enemyPlayerInfo.isBot ) { //mal: dont worry about human targets in training mode if we have a bot one, unless its the final obj... continue; } if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: st00pid bot - your not smart enough to pick your targets wisely if ( enemyVehicleInfo.entNum > 0 && enemyInfo.enemyVisible ) { if ( !( enemyVehicleInfo.flags & PERSONAL ) && !( enemyVehicleInfo.flags & WATER ) && ( enemyVehicleInfo.isAirborneVehicle && enemyVehicleInfo.xyspeed > 900.0f && entDist > Square( 2000.0f ) ) ) { if ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !Client_IsCriticalForCurrentObj( i, 1500.0f ) && !ClientHasObj( i ) ) { continue; } //mal: dont worry about an enemy in a vehicle if the vehicle is far away, moving too fast, is not a real threat } } } //mal: if our current enemy is in a vehicle, and this guy isn't, and this guy doesn't have an obj, or isn't important, hes not worth fighting. bool enemyIsInAirAttackVehicle = false; if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { //mal: pick the driver of a vehicle as the target, NOT passengers, unless there is no driver - then kill whoever. GetVehicleInfo( playerInfo.proxyInfo.entNum, vehicleInfo ); if ( vehicleInfo.driverEntNum != i && vehicleInfo.driverEntNum != -1 ) { continue; } if ( vehicleInfo.type == ANANSI || vehicleInfo.type == HORNET ) { enemyIsInAirAttackVehicle = true; } else { vec = vehicleInfo.origin - botInfo->origin; if ( vehicleInfo.xyspeed > 600.0f && vec.LengthSqr() > Square( 1900.0f ) && !InFrontOfVehicle( vehicleInfo.entNum, botInfo->origin ) ) { //mal: if they're in a mad dash away from us, forget about them! continue; } } } vec = playerInfo.origin - botInfo->origin; dist = vec.LengthSqr(); if ( !enemyIsInAirAttackVehicle ) { if ( dist > Square( ENEMY_SIGHT_BUSY_DIST * 2.0f ) ) { continue; } } float tempDist = entDist; if ( curEnemyNotInVehicle && playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { tempDist += Square( 3000.0f ); } if ( !enemyIsInAirAttackVehicle ) { if ( dist > tempDist ) { continue; } } else { if ( dist > Square( AIRCRAFT_ATTACK_DIST ) ) { continue; } } if ( !ClientIsVisibleToBot ( i, true, false ) ) { continue; } if ( Client_IsCriticalForCurrentObj( i, 1500.0f ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: if a critical class, get high priority dist = Square( 600.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } if ( ClientHasObj( i ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: if have docs, get HIGHER priority. dist = Square( 500.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } if ( ClientIsDefusingOurTeamCharge( i ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: if defusing our charge, get HIGHER priority. dist = Square( 100.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } if ( botWorld->botGoalInfo.mapHasMCPGoal && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { if ( playerInfo.proxyInfo.entNum == botWorld->botGoalInfo.botGoal_MCP_VehicleNum ) { dist = Square( 400.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } } if ( enemyIsInAirAttackVehicle && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: dont ignore a chance to dogfight! dist = Square( 100.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } numVisEnemies++; entClientNum = i; entDist = dist; } if ( entClientNum != enemy ) { enemy = entClientNum; enemySpawnID = botWorld->clientInfo[ entClientNum ].spawnID; enemyInfo.enemy_FS_Pos = botWorld->clientInfo[ entClientNum ].origin; enemyInfo.enemy_LS_Pos = enemyInfo.enemy_FS_Pos; enemyInfo.enemyLastVisTime = botWorld->gameLocalInfo.time; enemyAcquireTime = botWorld->gameLocalInfo.time; bot_FS_Enemy_Pos = botInfo->origin; bot_LS_Enemy_Pos = bot_FS_Enemy_Pos; VEHICLE_COMBAT_AI_SUB_NODE = NULL; //mal: reset the bot's combat AI node and movement state. COMBAT_MOVEMENT_STATE = NULL; return true; } return false; }
const float Magnitude(const TVector2f& _krV) { return(SquareRoot( Square(_krV.m_fX) + Square(_krV.m_fY))); }
void CMobileCAI::IdleCheck(void) { if(owner->unitDef->canAttack && owner->fireState && !owner->weapons.empty() && owner->haveTarget) { if(!owner->userTarget) { owner->haveTarget = false; } else if(owner->pos.SqDistance2D(owner->userTarget->pos) < Square(owner->maxRange + 200*owner->moveState*owner->moveState)) { Command c; c.id = CMD_ATTACK; c.options=INTERNAL_ORDER; c.params.push_back(owner->userTarget->id); c.timeOut = gs->frameNum + 140; commandQue.push_front(c); tempOrder = true; commandPos1 = owner->pos; commandPos2 = owner->pos; return; } } if(owner->unitDef->canAttack && owner->fireState && !owner->weapons.empty() && !owner->haveTarget) { if(owner->lastAttacker && owner->lastAttack + 200 > gs->frameNum && !(owner->unitDef->noChaseCategory & owner->lastAttacker->category)){ float3 apos=owner->lastAttacker->pos; float dist=apos.SqDistance2D(owner->pos); if(dist<Square(owner->maxRange+200*owner->moveState*owner->moveState)){ Command c; c.id=CMD_ATTACK; c.options=INTERNAL_ORDER; c.params.push_back(owner->lastAttacker->id); c.timeOut=gs->frameNum+140; commandQue.push_front(c); tempOrder = true; commandPos1 = owner->pos; commandPos2 = owner->pos; return; } } } if (owner->unitDef->canAttack && (gs->frameNum >= lastIdleCheck + 10) && owner->fireState >= 2 && !owner->weapons.empty() && !owner->haveTarget) { const float searchRadius = owner->maxRange + 150 * owner->moveState * owner->moveState; CUnit* enemy = helper->GetClosestValidTarget(owner->pos, searchRadius, owner->allyteam, this); if (enemy != NULL) { Command c; c.id=CMD_ATTACK; c.options=INTERNAL_ORDER; c.params.push_back(enemy->id); c.timeOut=gs->frameNum+140; commandQue.push_front(c); tempOrder = true; commandPos1 = owner->pos; commandPos2 = owner->pos; return; } } if (owner->usingScriptMoveType) { return; } lastIdleCheck = gs->frameNum; if (((owner->pos - lastUserGoal).SqLength2D() > 10000.0f) && !owner->haveTarget && !dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //note that this is not internal order so that we dont keep generating //new orders if we cant get to that pos Command c; c.id=CMD_MOVE; c.options=0; c.params.push_back(lastUserGoal.x); c.params.push_back(lastUserGoal.y); c.params.push_back(lastUserGoal.z); commandQue.push_front(c); unimportantMove=true; } else { NonMoving(); } }
void CStarburstProjectile::Update(void) { ttl--; uptime--; missileAge++; if (target && weaponDef->tracks && owner()) { targetPos = helper->GetUnitErrorPos(target, owner()->allyteam); } if (interceptTarget) { targetPos = interceptTarget->pos; if (targetPos.SqDistance(pos) < Square(areaOfEffect * 2)) { interceptTarget->Collision(); Collision(); } } if (uptime > 0) { if (curSpeed < maxSpeed) curSpeed += weaponDef->weaponacceleration; speed = dir * curSpeed; } else if (doturn && ttl > 0 && distanceToTravel > 0) { float3 dif(targetPos-pos); dif.Normalize(); dif += aimError; dif.Normalize(); if (dif.dot(dir) > 0.99f) { dir = dif; doturn = false; } else { dif = dif - dir; dif -= dir * (dif.dot(dir)); dif.Normalize(); if (weaponDef->turnrate != 0) { dir += dif * weaponDef->turnrate; } else { dir += dif * 0.06; } dir.Normalize(); } speed = dir * curSpeed; if (distanceToTravel != MAX_WORLD_SIZE) distanceToTravel -= speed.Length2D(); } else if (ttl > 0 && distanceToTravel > 0) { if (curSpeed < maxSpeed) curSpeed += weaponDef->weaponacceleration; float3 dif(targetPos - pos); dif.Normalize(); if (dif.dot(dir) > maxGoodDif) { dir = dif; } else { dif = dif - dir; dif -= dir * (dif.dot(dir)); dif.SafeNormalize(); dir += dif * tracking; dir.SafeNormalize(); } speed = dir * curSpeed; if (distanceToTravel != MAX_WORLD_SIZE) distanceToTravel -= speed.Length2D(); } else { dir.y += gravity; dir.Normalize(); curSpeed -= gravity; speed = dir * curSpeed; } pos += speed; if (ttl > 0) { if (cegTag.size() > 0) { ceg.Explosion(pos, ttl, areaOfEffect, 0x0, 0.0f, 0x0, dir); } } OldInfo* tempOldInfo = oldInfos[4]; for (int a = 3; a >= 0; --a) { oldInfos[a + 1] = oldInfos[a]; } oldInfos[0] = tempOldInfo; oldInfos[0]->pos = pos; oldInfos[0]->dir = dir; oldInfos[0]->speedf = curSpeed; int newsize = 0; for(float aa = 0; aa < curSpeed + 0.6f; aa += 0.15f, ++newsize) { float ageMod = (missileAge < 20) ? 1 : 0.6f + rand() * 0.8f / RAND_MAX; if(oldInfos[0]->ageMods.size()<=newsize) oldInfos[0]->ageMods.push_back(ageMod); else oldInfos[0]->ageMods[newsize] = ageMod; } if(oldInfos[0]->ageMods.size() != newsize) oldInfos[0]->ageMods.resize(newsize); age++; numParts++; if (weaponDef->visuals.smokeTrail && !(age & 7)) { if (curCallback) curCallback->drawCallbacker = 0; curCallback = new CSmokeTrailProjectile(pos, oldSmoke, dir, oldSmokeDir, owner(), age == 8, false, 7, Smoke_Time, 0.7f, drawTrail, this, weaponDef->visuals.texture2); oldSmoke = pos; oldSmokeDir = dir; numParts = 0; useAirLos = curCallback->useAirLos; if (!drawTrail) { float3 camDir = (pos - camera->pos).Normalize(); if (camera->pos.distance(pos) * 0.2f + (1 - fabs(camDir.dot(dir))) * 3000 > 300) drawTrail = true; } } }
const double Magnitude(const TVector2d& _krV) { return(SquareRoot( Square(_krV.m_dX) + Square(_krV.m_dY))); }
TEST(ShapePtr, DrawSquare) { // change this to make the test pass std::shared_ptr<Shape> s = Square(1); EXPECT_EQ("drew a square", s->draw()); }
void Level::Update() { for(int i = 0;i < m_nElements;i++) { m_ppElements[i]->Update(); if(m_ppElements[i]->GetState() == Ready) { bool bAlreadyExploded = false; bool bReasonToExplode = m_pGame->GetPlayer()->GetState() == Explode || m_pGame->GetPlayer()->GetState() == Dying; if(bReasonToExplode) { float x1 = m_ppElements[i]->GetPosX(); float y1 = m_ppElements[i]->GetPosY(); float x2 = m_pGame->GetPlayer()->GetPosX(); float y2 = m_pGame->GetPlayer()->GetPosY(); float fDistance = sqrt(Square(x2 - x1) + Square(y2 - y1)); if(fDistance <= m_pGame->GetPlayer()->GetRadius() + m_ppElements[i]->GetRadius()) { if(m_pGame->GetPlayer()->GetTypeClick() == 1) { m_ppElements[i]->SetExploded(); m_nScore++; } else { for(int cpt = 0;cpt < m_nElements;cpt++) { if(m_ppElements[cpt]->GetState() == Dead && !m_ppElements[i]->GetAlreadyMultiply()) { m_ppElements[i]->SetAlreadyMultiply(true); m_ppElements[cpt] = new Element(m_pGame, (int)m_ppElements[i]->GetPosX(), (int)m_ppElements[i]->GetPosY(),m_pGame->nRadius, m_pGame->fSpeed); for(int cpt2 = cpt+1;cpt2 < cpt+12;cpt2++) { if(cpt2 < m_nElements) { if(m_ppElements[cpt2]->GetState() == Dead) { m_ppElements[cpt2] = new Element(m_pGame, (int)m_ppElements[i]->GetPosX(), (int)m_ppElements[i]->GetPosY(),m_pGame->nRadius, m_pGame->fSpeed); } } } m_ppElements[cpt]->SetAlreadyMultiply(true); cpt = m_nElements; } } } bAlreadyExploded = true; } } if(bReasonToExplode || m_pGame->GetPlayer()->GetState() == Dead || m_pGame->GetPlayer()->GetType() == 2 && !bAlreadyExploded) { float x1 = m_ppElements[i]->GetPosX(); float y1 = m_ppElements[i]->GetPosY(); for(int j = 0;j < m_nElements;j++) { if(i != j && (m_ppElements[j]->GetState() == Explode || m_ppElements[j]->GetState() == Dying) && !bAlreadyExploded) { float x2 = m_ppElements[j]->GetPosX(); float y2 = m_ppElements[j]->GetPosY(); float fDistance = sqrt(Square(x2 - x1) + Square(y2 - y1)); if(fDistance <= m_ppElements[i]->GetRadius() + m_ppElements[j]->GetRadius()) { m_ppElements[i]->SetExploded(); m_nScore++; bAlreadyExploded = true; } } } } } } if(m_eState == Running) { if(m_nScore >= m_nGoal) m_eState = Won; else { float dt = m_pGame->GetHGE()->Timer_GetDelta(); m_fTimeCheckLoose += dt; if(m_fTimeCheckLoose > 1) { m_fTimeCheckLoose = 0.0; int nCptExploded = 0; for(int i = 0;i < m_nElements;i++) { if(m_ppElements[i]->GetState() == Explode || m_ppElements[i]->GetState() == Dying) nCptExploded++; } if(nCptExploded == 0 && (m_pGame->GetPlayer()->GetState() == Dead || m_pGame->GetPlayer()->GetType() == 2)) m_eState = Lost; } } } }
static MagickPassFail GetImageStatisticsVariance(void *mutable_data, const void *immutable_data, const Image *image, const PixelPacket *pixel, const IndexPacket *indexes, const long npixels, ExceptionInfo *exception) { ImageStatistics lstatistics, *statistics=(ImageStatistics *) mutable_data; const StatisticsContext *context=(const StatisticsContext *) immutable_data; double normalized; register long i; ARG_NOT_USED(indexes); ARG_NOT_USED(exception); (void) memset(&lstatistics, 0, sizeof(ImageStatistics)); #if defined(HAVE_OPENMP) # pragma omp critical (GM_GetImageStatisticsVariance) #endif { lstatistics.red.mean=statistics->red.mean; lstatistics.green.mean=statistics->green.mean; lstatistics.blue.mean=statistics->blue.mean; lstatistics.opacity.mean=statistics->opacity.mean; } for (i=0; i < npixels; i++) { normalized=(double) pixel[i].red/MaxRGB; lstatistics.red.variance += Square(normalized-lstatistics.red.mean)/context->variance_divisor; normalized=(double) pixel[i].green/MaxRGB; lstatistics.green.variance += Square(normalized-lstatistics.green.mean)/context->variance_divisor; normalized=(double) pixel[i].blue/MaxRGB; lstatistics.blue.variance += Square(normalized-lstatistics.blue.mean)/context->variance_divisor; if (image->matte) { normalized=(double) pixel[i].opacity/MaxRGB; lstatistics.opacity.variance += Square(normalized-lstatistics.opacity.mean)/context->variance_divisor; } } #if defined(HAVE_OPENMP) # pragma omp critical (GM_GetImageStatisticsVariance) #endif { statistics->red.variance += lstatistics.red.variance; statistics->green.variance += lstatistics.green.variance; statistics->blue.variance += lstatistics.blue.variance; statistics->opacity.variance += lstatistics.opacity.variance; } return MagickPass; }
CirclingWind::Result CirclingWind::CalcWind() { assert(circle_count > 0); assert(!samples.empty()); // reject if average time step greater than 2.0 seconds if ((samples.back().time - samples[0].time) / (samples.size() - 1) > 2) return Result(0); // find average double av = 0; for (unsigned i = 0; i < samples.size(); i++) av += samples[i].vector.norm; av /= samples.size(); // find zero time for times above average double rthismax = 0; double rthismin = 0; int jmax = -1; int jmin = -1; for (unsigned j = 0; j < samples.size(); j++) { double rthisp = 0; for (unsigned i = 1; i < samples.size(); i++) { const unsigned ithis = (i + j) % samples.size(); unsigned idiff = i; if (idiff > samples.size() / 2) idiff = samples.size() - idiff; rthisp += samples[ithis].vector.norm * idiff; } if ((rthisp < rthismax) || (jmax == -1)) { rthismax = rthisp; jmax = j; } if ((rthisp > rthismin) || (jmin == -1)) { rthismin = rthisp; jmin = j; } } // attempt to fit cycloid const auto mag = (samples[jmax].vector.norm - samples[jmin].vector.norm) / 2; if (mag >= 30) // limit to reasonable values (60 knots), reject otherwise return Result(0); double rthis = 0; for (const Sample &sample : samples) { const auto sc = sample.vector.bearing.SinCos(); auto wx = sc.second, wy = sc.first; wx = wx * av + mag; wy *= av; auto cmag = hypot(wx, wy) - sample.vector.norm; rthis += Square(cmag); } rthis /= samples.size(); rthis = sqrt(rthis); int quality; if (mag > 1) quality = 5 - iround(rthis / mag * 3); else quality = 5 - iround(rthis); if (circle_count < 3) quality--; if (circle_count < 2) quality--; if (quality < 1) //measurment quality too low return Result(0); /* 5 is maximum quality, make sure we honour that */ quality = std::min(quality, 5); // jmax is the point where most wind samples are below SpeedVector wind(samples[jmax].vector.bearing.Reciprocal(), mag); return Result(quality, wind); }
/** * @brief Causes this CMobileCAI to execute the attack order c */ void CMobileCAI::ExecuteAttack(Command &c) { assert(owner->unitDef->canAttack); // limit how far away we fly if (tempOrder && (owner->moveState < 2) && orderTarget && LinePointDist(ClosestPointOnLine(commandPos1, commandPos2, owner->pos), commandPos2, orderTarget->pos) > (500 * owner->moveState + owner->maxRange)) { StopMove(); FinishCommand(); return; } // check if we are in direct command of attacker if (!inCommand) { // don't start counting until the owner->AttackGround() order is given owner->commandShotCount = -1; if (c.params.size() == 1) { CUnit* targetUnit = uh->GetUnit(c.params[0]); // check if we have valid target parameter and that we aren't attacking ourselves if (targetUnit != NULL && targetUnit != owner) { float3 fix = targetUnit->pos + owner->posErrorVector * 128; float3 diff = float3(fix - owner->pos).Normalize(); SetGoal(fix - diff * targetUnit->radius, owner->pos); orderTarget = targetUnit; AddDeathDependence(orderTarget); inCommand = true; } else { // unit may not fire on itself, cancel order StopMove(); FinishCommand(); return; } } else if (c.params.size() >= 3) { // user gave force-fire attack command float3 pos(c.params[0], c.params[1], c.params[2]); SetGoal(pos, owner->pos); inCommand = true; } } else if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) { // the trailing CMD_SET_WANTED_MAX_SPEED in a command pair does not count if ((commandQue.size() > 2) || (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) { StopMove(); FinishCommand(); return; } } // if our target is dead or we lost it then stop attacking // NOTE: unit should actually just continue to target area! if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) { // cancel keeppointingto StopMove(); FinishCommand(); return; } // user clicked on enemy unit (note that we handle aircrafts slightly differently) if (orderTarget) { //bool b1 = owner->AttackUnit(orderTarget, c.id == CMD_DGUN); bool b2 = false; bool b3 = false; bool b4 = false; float edgeFactor = 0.f; // percent offset to target center float3 diff = owner->pos - orderTarget->midPos; if (owner->weapons.size() > 0) { if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) { StopMove(); FinishCommand(); return; } CWeapon* w = owner->weapons.front(); // if we have at least one weapon then check if we // can hit target with our first (meanest) one b2 = w->TryTargetRotate(orderTarget, c.id == CMD_DGUN); b3 = Square(w->range - (w->relWeaponPos).Length()) > (orderTarget->pos.SqDistance(owner->pos)); b4 = w->TryTargetHeading(GetHeadingFromVector(-diff.x, -diff.z), orderTarget->pos, orderTarget != NULL, orderTarget); edgeFactor = fabs(w->targetBorder); } float diffLength2d = diff.Length2D(); // if w->AttackUnit() returned true then we are already // in range with our biggest weapon so stop moving // also make sure that we're not locked in close-in/in-range state loop // due to rotates invoked by in-range or out-of-range states if (b2) { if (!(tempOrder && owner->moveState == 0) && (diffLength2d * 1.4f > owner->maxRange - orderTarget->speed.SqLength() / owner->unitDef->maxAcc) && b4 && diff.dot(orderTarget->speed) < 0) { SetGoal(owner->pos + (orderTarget->speed * 80), owner->pos, SQUARE_SIZE, orderTarget->speed.Length() * 1.1f); } else { StopMove(); // FIXME kill magic frame number if (gs->frameNum > lastCloseInTry + MAX_CLOSE_IN_RETRY_TICKS) { owner->moveType->KeepPointingTo(orderTarget->midPos, std::min((float) owner->losRadius * loshandler->losDiv, owner->maxRange * 0.9f), true); } } owner->AttackUnit(orderTarget, c.id == CMD_DGUN); } // if we're on hold pos in a temporary order, then none of the close-in // code below should run, and the attack command is cancelled. else if (tempOrder && owner->moveState == 0) { StopMove(); FinishCommand(); return; } // if ((our movetype has type TAAirMoveType and length of 2D vector from us to target // less than 90% of our maximum range) OR squared length of 2D vector from us to target // less than 1024) then we are close enough else if(diffLength2d < (owner->maxRange * 0.9f)){ if (dynamic_cast<CTAAirMoveType*>(owner->moveType) || (diff.SqLength2D() < 1024)) { StopMove(); owner->moveType->KeepPointingTo(orderTarget->midPos, std::min((float) owner->losRadius * loshandler->losDiv, owner->maxRange * 0.9f), true); } // if (((first weapon range minus first weapon length greater than distance to target) // and length of 2D vector from us to target less than 90% of our maximum range) // then we are close enough, but need to move sideways to get a shot. //assumption is flawed: The unit may be aiming or otherwise unable to shoot else if (owner->unitDef->strafeToAttack && b3 && diffLength2d < (owner->maxRange * 0.9f)) { moveDir ^= (owner->moveType->progressState == AMoveType::Failed); float sin = moveDir ? 3.0/5 : -3.0/5; float cos = 4.0/5; float3 goalDiff(0, 0, 0); goalDiff.x = diff.dot(float3(cos, 0, -sin)); goalDiff.z = diff.dot(float3(sin, 0, cos)); goalDiff *= (diffLength2d < (owner->maxRange * 0.3f)) ? 1/cos : cos; goalDiff += orderTarget->pos; SetGoal(goalDiff, owner->pos); } } // if 2D distance of (target position plus attacker error vector times 128) // to goal position greater than // (10 plus 20% of 2D distance between attacker and target) then we need to close // in on target more else if ((orderTarget->pos + owner->posErrorVector * 128).SqDistance2D(goalPos) > Square(10 + orderTarget->pos.distance2D(owner->pos) * 0.2f)) { // if the target isn't in LOS, go to its approximate position // otherwise try to go precisely to the target // this should fix issues with low range weapons (mainly melee) float3 fix = orderTarget->pos + (orderTarget->losStatus[owner->allyteam] & LOS_INLOS ? float3(0.f,0.f,0.f) : owner->posErrorVector * 128); float3 norm = float3(fix - owner->pos).Normalize(); float3 goal = fix - norm*(orderTarget->radius*edgeFactor*0.8f); SetGoal(goal, owner->pos); if (lastCloseInTry < gs->frameNum + MAX_CLOSE_IN_RETRY_TICKS) lastCloseInTry = gs->frameNum; } } // user is attacking ground else if (c.params.size() >= 3) { const float3 pos(c.params[0], c.params[1], c.params[2]); const float3 diff = owner->pos - pos; if (owner->weapons.size() > 0) { // if we have at least one weapon then check if // we can hit position with our first (assumed // to be meanest) one CWeapon* w = owner->weapons.front(); // XXX hack - dgun overrides any checks if (c.id == CMD_DGUN) { float rr = owner->maxRange * owner->maxRange; for (vector<CWeapon*>::iterator it = owner->weapons.begin(); it != owner->weapons.end(); ++it) { if (dynamic_cast<CDGunWeapon*>(*it)) rr = (*it)->range * (*it)->range; } if (diff.SqLength() < rr) { StopMove(); owner->AttackGround(pos, c.id == CMD_DGUN); owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true); } } else { const bool inAngle = w->TryTargetRotate(pos, c.id == CMD_DGUN); const bool inRange = diff.SqLength2D() < Square(w->range - (w->relWeaponPos).Length2D()); if (inAngle || inRange) { StopMove(); owner->AttackGround(pos, c.id == CMD_DGUN); owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true); } } } else if (diff.SqLength2D() < 1024) { StopMove(); owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true); } // if we are more than 10 units distant from target position then keeping moving closer else if (pos.SqDistance2D(goalPos) > 100) { SetGoal(pos, owner->pos); } } }
/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries, int ownerId, bool synced) const { SCOPED_TIMER("PFS"); // 0 indicates a no-path id if (pathId == 0) return float3(-1.0f, -1.0f, -1.0f); if (numRetries > 4) return float3(-1.0f, -1.0f, -1.0f); //Find corresponding multipath. std::map<unsigned int, MultiPath*>::const_iterator pi = pathMap.find(pathId); if (pi == pathMap.end()) return float3(-1.0f, -1.0f, -1.0f); MultiPath* multiPath = pi->second; if (callerPos == ZeroVector) { if (!multiPath->detailedPath.path.empty()) callerPos = multiPath->detailedPath.path.back(); } // check if detailed path needs bettering if (!multiPath->estimatedPath.path.empty() && (multiPath->estimatedPath.path.back().SqDistance2D(callerPos) < Square(MIN_DETAILED_DISTANCE * SQUARE_SIZE) || multiPath->detailedPath.path.size() <= 2)) { if (!multiPath->estimatedPath2.path.empty() && // if so, check if estimated path also needs bettering (multiPath->estimatedPath2.path.back().SqDistance2D(callerPos) < Square(MIN_ESTIMATE_DISTANCE * SQUARE_SIZE) || multiPath->estimatedPath.path.size() <= 2)) { Estimate2ToEstimate(*multiPath, callerPos, ownerId, synced); } if (multiPath->caller) { multiPath->caller->UnBlock(); } EstimateToDetailed(*multiPath, callerPos, ownerId); if (multiPath->caller) { multiPath->caller->Block(); } } float3 waypoint; do { // get the next waypoint from the high-res path // // if this is not possible, then either we are // at the goal OR the path could not reach all // the way to it (ie. a GoalOutOfRange result) if (multiPath->detailedPath.path.empty()) { if (multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty()) { if (multiPath->searchResult == IPath::Ok) { return multiPath->finalGoal; } else { return float3(-1.0f, -1.0f, -1.0f); } } else { return NextWaypoint(pathId, callerPos, minDistance, numRetries + 1, ownerId, synced); } } else { waypoint = multiPath->detailedPath.path.back(); multiPath->detailedPath.path.pop_back(); } } while (callerPos.SqDistance2D(waypoint) < Square(minDistance) && waypoint != multiPath->detailedPath.pathGoal); return waypoint; }
ReplayCommand::ReplayCommand(BoardData *data, QPair<int, int> &move, QUndoCommand *parent) : QUndoCommand(parent), _data(data), _from(Square(move.second)), _to(Square(move.first)), _removedCur(nullptr) {}
/* ================ idBotAI::Bot_VehicleFindEnemy We'll sort thru the clients, and ignore certain clients if we're too busy to be buggered (carrying obj, planting/hacking, etc) or they're not valid enemies (in disguise, hidden by smoke, etc). ================ */ bool idBotAI::Bot_VehicleFindEnemy() { bool hasAttackedMate; bool hasAttackedCriticalMate; bool hasObj; bool isDefusingOurBomb; bool inFront; bool botGotShotRecently; bool botIsBigShot; bool audible; bool isVisible; bool isFacingUs; bool isFiringWeapon; bool isNearOurObj; bool isAttackingDeployable = false; bool inAttackAirCraft = false; int i; int entClientNum = -1; float dist; float botSightDist; float tempSightDist; float entDist = idMath::INFINITY; proxyInfo_t enemyVehicleInfo; enemyVehicleInfo.entNum = 0; idVec3 vec; numVisEnemies = 0; vehicleEnemyWasInheritedFromFootCombat = false; botSightDist = Square( ENEMY_VEHICLE_SIGHT_DIST ); //mal_FIXME: break this out into a script cmd! /* if ( botSightDist > Square( 8000.0f ) ) { botSightDist = Square( 8000.0f ); } else if ( botSightDist < Square( 3000.0f ) ) { botSightDist = Square( 3000.0f ); } */ //mal: some debugging stuff.... if ( botWorld->gameLocalInfo.botIgnoreEnemies == 1 ) { return false; } else if ( botWorld->gameLocalInfo.botIgnoreEnemies == 2 ) { if ( botInfo->team == GDF ) { return false; } } else if ( botWorld->gameLocalInfo.botIgnoreEnemies == 3 ) { if ( botInfo->team == STROGG ) { return false; } } if ( botVehicleInfo->type != BUFFALO && Bot_VehicleIsUnderAVTAttack() != -1 && ( ( botVehicleInfo->flags & ARMOR ) || botVehicleInfo->type > ICARUS ) ) { return false; } if ( botVehicleInfo->type > ICARUS ) { botSightDist = Square( 6000.0f ); } if ( botVehicleInfo->type == BUFFALO ) { botSightDist = Square( 3500.0f ); } if ( botVehicleInfo->type == GOLIATH || botVehicleInfo->type == DESECRATOR ) { //mal: these 2 are really limited botSightDist = Square( PLASMA_CANNON_RANGE - 1000.0f ); } if ( botVehicleInfo->type == HUSKY ) { //mal: we're no match for anybody! return false; } #ifdef _XENON if ( botVehicleInfo->type == MCP && botVehicleInfo->driverEntNum == botNum ) { return false; } if ( botVehicleInfo->type == PLATYPUS && botVehicleInfo->driverEntNum == botNum ) { return false; } #endif if ( botVehicleInfo->type > ICARUS && Client_IsCriticalForCurrentObj( botNum, -1.0f ) ) { return false; } botIsBigShot = Client_IsCriticalForCurrentObj( botNum, 3500.0f ); if ( aiState == VLTG && vLTGType == V_DESTROY_DEPLOYABLE ) { deployableInfo_t deployable; if ( GetDeployableInfo( false, vLTGTarget, deployable ) ) { if ( deployable.type == APT || deployable.type == AVT || deployable.type == AIT ) { //mal: these are the priorities isAttackingDeployable = true; } } } for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !ClientIsValid( i, -1 ) ) { continue; //mal: no valid client in this client slot! } if ( i == botNum ) { continue; //mal: dont try to fight ourselves! } if ( EnemyIsIgnored( i ) ) { continue; //mal: dont try to fight someone we've flagged to ignore for whatever reason! } if ( !Bot_VehicleCanAttackEnemy( i ) ) { //mal: check if the bot has access to a weapon in the vehicle, that can hit this client. continue; } const clientInfo_t& playerInfo = botWorld->clientInfo[ i ]; if ( playerInfo.isNoTarget ) { continue; } //mal: dont target clients that have notarget set - this is useful for debugging, etc. bool enemyIsBigShot = Client_IsCriticalForCurrentObj( i, 2500.0f ); if ( playerInfo.inLimbo ) { continue; } if ( playerInfo.invulnerableEndTime > botWorld->gameLocalInfo.time ) { continue; //mal: ignore revived/just spawned in clients - get the ppl around them! } if ( playerInfo.isActor ) { continue; } if ( playerInfo.health <= 0 ) { continue; } if ( playerInfo.team == botInfo->team ) { continue; } if ( botVehicleInfo->type == MCP && botVehicleInfo->driverEntNum == botNum ) { if ( !InFrontOfVehicle( botInfo->proxyInfo.entNum, playerInfo.origin ) ) { continue; } } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && botVehicleInfo->type > ICARUS && !playerInfo.isBot ) { //mal: don't attack human players in training mode when we're in flyers. continue; } hasAttackedCriticalMate = ClientHasAttackedTeammate( i, true, 3000 ); hasAttackedMate = ClientHasAttackedTeammate( i, false, 3000 ); hasObj = ClientHasObj( i ); isDefusingOurBomb = ClientIsDefusingOurTeamCharge( i ); inFront = ( botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) ? InFrontOfClient( botNum, playerInfo.origin) : InFrontOfVehicle( botInfo->proxyInfo.entNum, playerInfo.origin ); isFacingUs = ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) ? InFrontOfClient( i, botInfo->origin ) : InFrontOfVehicle( playerInfo.proxyInfo.entNum, botInfo->origin ); botGotShotRecently = ( botInfo->lastAttackerTime + 3000 < botWorld->gameLocalInfo.time ) ? false : true; isFiringWeapon = playerInfo.weapInfo.isFiringWeap; isNearOurObj = ( LocationDistFromCurrentObj( botInfo->team, playerInfo.origin ) < 2500.0f ) ? true : false; bool isCriticalEnemy = Client_IsCriticalForCurrentObj( i, 2500.0f ); if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( playerInfo.proxyInfo.entNum, enemyVehicleInfo ); } if ( isAttackingDeployable ) { if ( botInfo->team == botWorld->botGoalInfo.attackingTeam ) { if ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { if ( playerInfo.weapInfo.weapon != ROCKET && !isDefusingOurBomb ) { continue; } } else { if ( !( enemyVehicleInfo.flags & ARMOR ) && enemyVehicleInfo.type != ANANSI && enemyVehicleInfo.type != HORNET ) { continue; } } } else { if ( !isDefusingOurBomb && playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !hasObj && playerInfo.weapInfo.weapon != ROCKET && ( !isCriticalEnemy || !isNearOurObj ) ) { continue; } } } if ( botIsBigShot && !isFacingUs && ( !botGotShotRecently || botInfo->lastAttacker != i ) && !isFiringWeapon && !hasObj && !isNearOurObj ) { continue; } //mal: if we're trying to do an important obj, dont get into a fight with everyone. vec = playerInfo.origin - botInfo->origin; if ( botVehicleInfo->isAirborneVehicle ) { vec.z = 0.0f; } dist = vec.LengthSqr(); if ( botIsBigShot && !inFront && dist > Square( 2500.0f ) && ( !botGotShotRecently || botInfo->lastAttacker != i ) && botVehicleInfo->driverEntNum == botNum ) { continue; } if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { //mal: pick the driver of a vehicle as the target, NOT passengers, unless there is no driver - then kill whoever. if ( enemyVehicleInfo.type == ANANSI || enemyVehicleInfo.type == HORNET ) { inAttackAirCraft = true; } if ( botIsBigShot && enemyVehicleInfo.type <= ICARUS ) { continue; } if ( enemyVehicleInfo.type == BUFFALO && botVehicleInfo->flags & ARMOR && playerInfo.isBot ) { continue; } if ( enemyVehicleInfo.type == MCP && enemyVehicleInfo.isImmobilized && enemyVehicleInfo.driverEntNum == i ) { continue; } if ( botVehicleInfo->type == ANANSI && enemyVehicleInfo.type == ICARUS ) { //mal: this is funny to watch, but is a waste of time. :-) continue; } if ( isAttackingDeployable ) { if ( botVehicleInfo->isAirborneVehicle && ( enemyVehicleInfo.type <= ICARUS || enemyVehicleInfo.type == BUFFALO ) ) { //mal: if attacking from the air, only worry about air vehicles. continue; } } if ( enemyVehicleInfo.driverEntNum != i && enemyVehicleInfo.driverEntNum != -1 ) { continue; } if ( inAttackAirCraft && enemyVehicleInfo.xyspeed > 500.0f && dist > Square( TANK_MINIGUN_RANGE ) && botVehicleInfo->flags & ARMOR ) { //mal: tanks won't attack fast moving aircraft that are too far away for their MGs continue; } if ( botVehicleInfo->type == BADGER ) { if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && enemyVehicleInfo.flags & ARMOR || enemyVehicleInfo.inWater || ( enemyVehicleInfo.isAirborneVehicle && dist > Square( 3000.0f ) || enemyVehicleInfo.type == HOG ) ) { continue; } } if ( botVehicleInfo->inWater && botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON ) { continue; } if ( botVehicleInfo->type != ANANSI && botVehicleInfo->type != HORNET ) { if ( enemyVehicleInfo.xyspeed > 600.0f && dist > Square( 1900.0f ) && !InFrontOfVehicle( enemyVehicleInfo.entNum, botInfo->origin ) && !ClientHasObj( i ) && !enemyIsBigShot ) { //mal: if they're in a mad dash away from us, forget about them! continue; } } } if ( botVehicleInfo->type == BUFFALO && !inAttackAirCraft ) { //mal_TODO: need to make the buffalo a more effective fighting platform! continue; } tempSightDist = botSightDist; if ( !ClientHasObj( i ) && !enemyIsBigShot && playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !playerInfo.isCamper && playerInfo.killsSinceSpawn < KILLING_SPREE && botVehicleInfo->driverEntNum == botNum && !isDefusingOurBomb ) { //mal: vehicles will prefer to fight other vehicles, not some guy on foot a mile away.... tempSightDist = Square( 3500.0f ); } if ( inAttackAirCraft && ( botVehicleInfo->type == ANANSI || botVehicleInfo->type == HORNET ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { tempSightDist = Square( AIRCRAFT_ATTACK_DIST ); } if ( dist > tempSightDist ) { continue; } if ( playerInfo.isDisguised ) { //mal: when in a vehicle, bots are much less likely to notice or worry about coverts if ( botThreadData.GetBotSkill() == BOT_SKILL_EASY ) { continue; } else { if ( ( playerInfo.disguisedClient != botNum && !hasAttackedMate ) || dist > Square( 2500.0f ) ) { continue; } } } if ( !ClientHasObj( i ) ) { audible = ClientIsAudibleToVehicle( i ); //mal: if we can hear you, we'll skip the FOV test in the vis check below } else { audible = true; dist = Square( 500.0f ); //mal: if you've got the docs, your our priority target, unless someone else is right on top of us! } isVisible = ClientIsVisibleToBot( i, !audible, false ); if ( !isVisible && !ClientHasObj( i ) ) { continue; } if ( botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO || botWorld->botGoalInfo.gameIsOnFinalObjective || botWorld->botGoalInfo.attackingTeam == botInfo->team ) { if ( isDefusingOurBomb ) { dist = Square( 100.0f ); } if ( hasAttackedCriticalMate && inFront && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { dist = Square( 600.0f ); //mal: will give higher priority to someone attacking a critical mate, if we can see it happening. } if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { if ( Client_IsCriticalForCurrentObj( i, 6000.0f ) ) { dist = Square( 700.0f ); //mal: if your a critical client, we're more likely to kill you. } } if ( botWorld->botGoalInfo.mapHasMCPGoal ) { if ( playerInfo.proxyInfo.entNum == botWorld->botGoalInfo.botGoal_MCP_VehicleNum ) { dist = 400.0f; } } //mal: if your in MCP, you get higher priority then a normal enemy. Especially when we're in a vehicle! if ( botVehicleInfo->type > ICARUS && botVehicleInfo->type != BUFFALO && ( playerInfo.isCamper || playerInfo.killsSinceSpawn >= KILLING_SPREE ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY && !playerInfo.isBot ) { dist = Square( 600.0f ); } //mal: target trouble making humans! } else { if ( !playerInfo.isBot || playerInfo.isActor ) { dist += Square( TRAINING_MODE_RANGE_ADDITION ); } } numVisEnemies++; if ( dist < entDist ) { entClientNum = i; entDist = dist; } } if ( entClientNum != -1 ) { enemy = entClientNum; enemySpawnID = botWorld->clientInfo[ entClientNum ].spawnID; enemyInfo.enemy_FS_Pos = botWorld->clientInfo[ entClientNum ].origin; enemyInfo.enemy_LS_Pos = enemyInfo.enemy_FS_Pos; bot_FS_Enemy_Pos = botInfo->origin; bot_LS_Enemy_Pos = bot_FS_Enemy_Pos; enemyInfo.enemyLastVisTime = botWorld->gameLocalInfo.time; enemyAcquireTime = botWorld->gameLocalInfo.time; Bot_SetAttackTimeDelay( inFront ); //mal: this sets a delay on how long the bot should take to see enemy, based on bot's state. VEHICLE_COMBAT_AI_SUB_NODE = NULL; //mal: reset the bot's combat AI node COMBAT_MOVEMENT_STATE = NULL; return true; } return false; }
/* ======================== idCommonLocal::RunNetworkSnapshotFrame ======================== */ void idCommonLocal::RunNetworkSnapshotFrame() { // Process any reliable messages we've received for ( int i = 0; i < reliableQueue.Num(); i++ ) { game->ProcessReliableMessage( reliableQueue[i].client, reliableQueue[i].type, idBitMsg( (const byte *)reliableQueue[i].data, reliableQueue[i].dataSize ) ); Mem_Free( reliableQueue[i].data ); } reliableQueue.Clear(); // abuse the game timing to time presentable thinking on clients time_gameFrame = Sys_Microseconds(); time_maxGameFrame = 0; count_numGameFrames = 0; if ( snapPrevious.serverTime >= 0 ) { int msec_interval = 1 + idMath::Ftoi( (float)initialBaseTicksPerSec ); static int clientTimeResidual = 0; static int lastTime = Sys_Milliseconds(); int currentTime = Sys_Milliseconds(); int deltaFrameTime = idMath::ClampInt( 1, 33, currentTime - lastTime ); clientTimeResidual += idMath::ClampInt( 0, 50, currentTime - lastTime ); lastTime = currentTime; extern idCVar com_fixedTic; if ( com_fixedTic.GetBool() ) { clientTimeResidual = 0; } do { // If we are extrapolating and have fresher snapshots, then use the freshest one while ( ( snapCurrentTime >= snapRate || com_forceLatestSnap.GetBool() ) && readSnapshotIndex < writeSnapshotIndex ) { snapCurrentTime -= snapRate; ProcessNextSnapshot(); } // this only matters when running < 60 fps // JAF Game()->GetRenderWorld()->UpdateDeferredPositions(); // Clamp the current time so that it doesn't fall outside of our extrapolation bounds snapCurrentTime = idMath::ClampInt( 0, snapRate + Min( (int)snapRate, (int)net_maxExtrapolationInMS.GetInteger() ), snapCurrentTime ); if ( snapRate <= 0 ) { idLib::Warning("snapRate <= 0. Resetting to 100"); snapRate = 100; } float fraction = (float)snapCurrentTime / (float)snapRate; if ( !IsValid( fraction ) ) { idLib::Warning("Interpolation Fraction invalid: snapCurrentTime %d / snapRate %d", (int)snapCurrentTime, (int)snapRate ); fraction = 0.0f; } InterpolateSnapshot( snapPrevious, snapCurrent, fraction, true ); // Default to a snap scale of 1 float snapRateScale = net_interpolationBaseRate.GetFloat(); snapTimeBuffered = CalcSnapTimeBuffered( totalBufferedTime, totalRecvTime ); effectiveSnapRate = static_cast< float > ( totalBufferedTime ) / static_cast< float > ( totalRecvTime ); if ( net_minBufferedSnapPCT_Static.GetFloat() > 0.0f ) { optimalPCTBuffer = session->GetTitleStorageFloat( "net_minBufferedSnapPCT_Static", net_minBufferedSnapPCT_Static.GetFloat() ); } // Calculate optimal amount of buffered time we want if ( net_optimalDynamic.GetBool() ) { optimalTimeBuffered = idMath::ClampInt( 0, net_maxBufferedSnapMS.GetInteger(), snapRate * optimalPCTBuffer ); optimalTimeBufferedWindow = snapRate * net_minBufferedSnapWinPCT_Static.GetFloat(); } else { optimalTimeBuffered = net_optimalSnapTime.GetFloat(); optimalTimeBufferedWindow = net_optimalSnapWindow.GetFloat(); } // Scale snapRate based on where we are in the buffer if ( snapTimeBuffered <= optimalTimeBuffered ) { if ( snapTimeBuffered <= idMath::FLT_SMALLEST_NON_DENORMAL ) { snapRateScale = 0; } else { snapRateScale = net_interpolationFallbackRate.GetFloat(); // When we interpolate past our cushion of buffered snapshot, we want to slow smoothly slow the // rate of interpolation. frac will go from 1.0 to 0.0 (if snapshots stop coming in). float startSlowdown = ( net_interpolationSlowdownStart.GetFloat() * optimalTimeBuffered ); if ( startSlowdown > 0 && snapTimeBuffered < startSlowdown ) { float frac = idMath::ClampFloat( 0.0f, 1.0f, snapTimeBuffered / startSlowdown ); if ( !IsValid( frac ) ) { frac = 0.0f; } snapRateScale = Square( frac ) * snapRateScale; if ( !IsValid( snapRateScale ) ) { snapRateScale = 0.0f; } } } } else if ( snapTimeBuffered > optimalTimeBuffered + optimalTimeBufferedWindow ) { // Go faster snapRateScale = net_interpolationCatchupRate.GetFloat(); } float delta_interpolate = (float)initialBaseTicksPerSec * snapRateScale; if ( net_effectiveSnapRateEnable.GetBool() ) { float deltaFrameGameMS = static_cast<float>( initialBaseTicksPerSec ) * static_cast<float>( deltaFrameTime / 1000.0f ); delta_interpolate = ( deltaFrameGameMS * snapRateScale * effectiveSnapRate ) + snapCurrentResidual; if ( !IsValid( delta_interpolate ) ) { delta_interpolate = 0.0f; } snapCurrentResidual = idMath::Frac( delta_interpolate ); // fixme: snapCurrentTime should just be a float, but would require changes in d4 too if ( !IsValid( snapCurrentResidual ) ) { snapCurrentResidual = 0.0f; } if ( net_effectiveSnapRateDebug.GetBool() ) { idLib::Printf("%d/%.2f snapRateScale: %.2f effectiveSR: %.2f d.interp: %.2f snapTimeBuffered: %.2f res: %.2f\n", deltaFrameTime, deltaFrameGameMS, snapRateScale, effectiveSnapRate, delta_interpolate, snapTimeBuffered, snapCurrentResidual ); } } assert( IsValid( delta_interpolate ) ); int interpolate_interval = idMath::Ftoi( delta_interpolate ); snapCurrentTime += interpolate_interval; // advance interpolation time by the scaled interpolate_interval clientTimeResidual -= msec_interval; // advance local client residual time (fixed step) } while ( clientTimeResidual >= msec_interval ); if ( clientTimeResidual < 0 ) { clientTimeResidual = 0; } } time_gameFrame = Sys_Microseconds() - time_gameFrame; }
/* ================ idBotAI::Bot_ShouldVehicleChaseHiddenEnemy ================ */ bool idBotAI::Bot_ShouldVehicleChaseHiddenEnemy() { proxyInfo_t enemyVehicleInfo; idVec3 vec; chasingEnemy = false; if ( ClientHasObj( botNum ) || Client_IsCriticalForCurrentObj( botNum, -1.0f ) ) { //mal: never chase if we are important! return false; } if ( botVehicleInfo->driverEntNum != botNum ) { //mal: we dont get the choice to chase someone if we're not the driver! return false; } if ( botVehicleInfo->health <= ( botVehicleInfo->maxHealth / 4 ) && !ClientHasObj( enemy ) ) { //mal: if we're in pretty bad shape, randomly decide to sometimes give up the fight.... if ( botThreadData.random.RandomInt( 100 ) > 50 ) { return false; } } if ( ( botVehicleInfo->flags & PERSONAL ) || botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && !ClientHasObj( enemy ) ) { return false; } //mal: if we dont have a vehicle weapon to fight with, or we're in a personal transport, dont go chasing ppl. if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.inWater && !botVehicleInfo->isAirborneVehicle || !( botVehicleInfo->flags & WATER ) ) { return false; } //mal: hes in the water, but we can't chase him, so forget him! if ( !ClientHasObj( enemy ) && !Client_IsCriticalForCurrentObj( enemy, 2000.0f ) ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { return false; } } } if ( AIStack.STACK_AI_NODE != NULL && AIStack.isPriority != false && !ClientHasObj( enemy ) ) { return false; } // we have something important on our mind, and cant chase ATM - UNLESS they have the obj! Always chase them! vec = enemyInfo.enemy_LS_Pos - botInfo->origin; if ( vec.LengthSqr() > Square( ENEMY_CHASE_DIST ) ) { return false; } // too far away to chase vec = enemyInfo.enemy_LS_Pos - botWorld->clientInfo[ enemy ].origin; if ( vec.LengthSqr() > Square( 900.0f ) && !ClientHasObj( enemy ) && !Client_IsCriticalForCurrentObj( enemy, 1500.0f ) ) { // unless he's REALLY close or a threat, sometimes we'll stop the chase, just because.... if ( botThreadData.random.RandomInt( 100 ) > 50 ) { return false; } } chasingEnemy = true; if ( ClientHasObj( enemy ) ) { chaseEnemyTime = botWorld->gameLocalInfo.time + 30000; } else if ( Client_IsCriticalForCurrentObj( enemy, 1500.0f ) ) { chaseEnemyTime = botWorld->gameLocalInfo.time + 15000; } else { chaseEnemyTime = botWorld->gameLocalInfo.time + 7000; } return true; }
/* ================ idEntityFx::Run ================ */ void idEntityFx::Run( int time ) { int ieff, j; idEntity *ent = NULL; const idDict *projectileDef = NULL; idProjectile *projectile = NULL; if( !fxEffect ) { return; } for( ieff = 0; ieff < fxEffect->events.Num(); ieff++ ) { const idFXSingleAction &fxaction = fxEffect->events[ieff]; idFXLocalAction &laction = actions[ieff]; // // if we're currently done with this one // if( laction.start == -1 ) { continue; } // // see if it's delayed // if( laction.delay ) { if( laction.start + ( time - laction.start ) < laction.start + ( laction.delay * 1000 ) ) { continue; } } // // each event can have it's own delay and restart // int actualStart = laction.delay ? laction.start + ( int )( laction.delay * 1000 ) : laction.start; float pct = ( float )( time - actualStart ) / ( 1000 * fxaction.duration ); if( pct >= 1.0f ) { laction.start = -1; float totalDelay = 0.0f; if( fxaction.restart ) { if( fxaction.random1 || fxaction.random2 ) { totalDelay = fxaction.random1 + gameLocal.random.RandomFloat() * ( fxaction.random2 - fxaction.random1 ); } else { totalDelay = fxaction.delay; } laction.delay = totalDelay; laction.start = time; } continue; } if( fxaction.fire.Length() ) { for( j = 0; j < fxEffect->events.Num(); j++ ) { if( fxEffect->events[j].name.Icmp( fxaction.fire ) == 0 ) { actions[j].delay = 0; } } } idFXLocalAction *useAction; if( fxaction.sibling == -1 ) { useAction = &laction; } else { useAction = &actions[fxaction.sibling]; } assert( useAction ); switch( fxaction.type ) { case FX_ATTACHLIGHT: case FX_LIGHT: { if( useAction->lightDefHandle == -1 ) { if( fxaction.type == FX_LIGHT ) { memset( &useAction->renderLight, 0, sizeof( renderLight_t ) ); useAction->renderLight.origin = GetPhysics()->GetOrigin() + fxaction.offset; useAction->renderLight.axis = GetPhysics()->GetAxis(); useAction->renderLight.lightRadius[0] = fxaction.lightRadius; useAction->renderLight.lightRadius[1] = fxaction.lightRadius; useAction->renderLight.lightRadius[2] = fxaction.lightRadius; useAction->renderLight.shader = declManager->FindMaterial( fxaction.data, false ); useAction->renderLight.shaderParms[ SHADERPARM_RED ] = fxaction.lightColor.x; useAction->renderLight.shaderParms[ SHADERPARM_GREEN ] = fxaction.lightColor.y; useAction->renderLight.shaderParms[ SHADERPARM_BLUE ] = fxaction.lightColor.z; useAction->renderLight.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f; useAction->renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time ); useAction->renderLight.referenceSound = refSound.referenceSound; useAction->renderLight.pointLight = true; if( fxaction.noshadows ) { useAction->renderLight.noShadows = true; } useAction->lightDefHandle = gameRenderWorld->AddLightDef( &useAction->renderLight ); } if( fxaction.noshadows ) { for( j = 0; j < fxEffect->events.Num(); j++ ) { idFXLocalAction &laction2 = actions[j]; if( laction2.modelDefHandle != -1 ) { laction2.renderEntity.noShadow = true; } } } } ApplyFade( fxaction, *useAction, time, actualStart ); break; } case FX_SOUND: { if( !useAction->soundStarted ) { useAction->soundStarted = true; const idSoundShader *shader = declManager->FindSound( fxaction.data ); StartSoundShader( shader, SND_CHANNEL_ANY, 0, false, NULL ); for( j = 0; j < fxEffect->events.Num(); j++ ) { idFXLocalAction &laction2 = actions[j]; if( laction2.lightDefHandle != -1 ) { laction2.renderLight.referenceSound = refSound.referenceSound; gameRenderWorld->UpdateLightDef( laction2.lightDefHandle, &laction2.renderLight ); } } } break; } case FX_DECAL: { if( !useAction->decalDropped ) { useAction->decalDropped = true; gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetGravity(), 8.0f, true, fxaction.size, fxaction.data ); } break; } case FX_SHAKE: { if( !useAction->shakeStarted ) { idDict args; args.Clear(); args.SetFloat( "kick_time", fxaction.shakeTime ); args.SetFloat( "kick_amplitude", fxaction.shakeAmplitude ); for( j = 0; j < gameLocal.numClients; j++ ) { idPlayer *player = gameLocal.GetClientByNum( j ); if( player && ( player->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).LengthSqr() < Square( fxaction.shakeDistance ) ) { if( !gameLocal.isMultiplayer || !fxaction.shakeIgnoreMaster || GetBindMaster() != player ) { player->playerView.DamageImpulse( fxaction.offset, &args ); } } } if( fxaction.shakeImpulse != 0.0f && fxaction.shakeDistance != 0.0f ) { idEntity *ignore_ent = NULL; if( gameLocal.isMultiplayer ) { ignore_ent = this; if( fxaction.shakeIgnoreMaster ) { ignore_ent = GetBindMaster(); } } // lookup the ent we are bound to? gameLocal.RadiusPush( GetPhysics()->GetOrigin(), fxaction.shakeDistance, fxaction.shakeImpulse, this, ignore_ent, 1.0f, true ); } useAction->shakeStarted = true; } break; } case FX_ATTACHENTITY: case FX_PARTICLE: case FX_MODEL: { if( useAction->modelDefHandle == -1 ) { memset( &useAction->renderEntity, 0, sizeof( renderEntity_t ) ); useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset; useAction->renderEntity.axis = ( fxaction.explicitAxis ) ? fxaction.axis : GetPhysics()->GetAxis(); useAction->renderEntity.hModel = renderModelManager->FindModel( fxaction.data ); useAction->renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f; useAction->renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f; useAction->renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f; useAction->renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time ); useAction->renderEntity.shaderParms[3] = 1.0f; useAction->renderEntity.shaderParms[5] = 0.0f; if( useAction->renderEntity.hModel ) { useAction->renderEntity.bounds = useAction->renderEntity.hModel->Bounds( &useAction->renderEntity ); } useAction->modelDefHandle = gameRenderWorld->AddEntityDef( &useAction->renderEntity ); } else if( fxaction.trackOrigin ) { useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset; useAction->renderEntity.axis = fxaction.explicitAxis ? fxaction.axis : GetPhysics()->GetAxis(); #ifdef _D3XP gameRenderWorld->UpdateEntityDef( useAction->modelDefHandle, &useAction->renderEntity ); #endif } ApplyFade( fxaction, *useAction, time, actualStart ); break; } case FX_LAUNCH: { if( gameLocal.isClient ) { // client never spawns entities outside of ClientReadSnapshot useAction->launched = true; break; } if( !useAction->launched ) { useAction->launched = true; projectile = NULL; // FIXME: may need to cache this if it is slow projectileDef = gameLocal.FindEntityDefDict( fxaction.data, false ); if( !projectileDef ) { gameLocal.Warning( "projectile \'%s\' not found", fxaction.data.c_str() ); } else { gameLocal.SpawnEntityDef( *projectileDef, &ent, false ); if( ent && ent->IsType( idProjectile::Type ) ) { projectile = ( idProjectile * )ent; projectile->Create( this, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0] ); projectile->Launch( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0], vec3_origin ); } } } break; } #ifdef _D3XP case FX_SHOCKWAVE: { if( gameLocal.isClient ) { useAction->shakeStarted = true; break; } if( !useAction->shakeStarted ) { idStr shockDefName; useAction->shakeStarted = true; shockDefName = fxaction.data; if( !shockDefName.Length() ) { shockDefName = "func_shockwave"; } projectileDef = gameLocal.FindEntityDefDict( shockDefName, false ); if( !projectileDef ) { gameLocal.Warning( "shockwave \'%s\' not found", shockDefName.c_str() ); } else { gameLocal.SpawnEntityDef( *projectileDef, &ent ); ent->SetOrigin( GetPhysics()->GetOrigin() + fxaction.offset ); ent->PostEventMS( &EV_Remove, ent->spawnArgs.GetInt( "duration" ) ); } } break; } #endif } } }
// Returns an intersection if found with distance maxDistance // viewDir must be a unit vector. // intersectDistance and visPoint are returned values. bool ViewableSphere::FindIntersectionNT ( const VectorR3& viewPos, const VectorR3& viewDir, double maxDist, double *intersectDistance, VisiblePoint& returnedPoint ) const { VectorR3 tocenter(Center); tocenter -= viewPos; // Vector view position to the center // D = Distance to pt on view line closest to sphere // v = vector from sphere center to the closest pt on view line // ASq = the distance from v to sphere center squared double D = (viewDir^tocenter); VectorR3 v(viewDir); v *= D; v -= tocenter; double ASq = v.NormSq(); // Ray-line completely misses sphere, or just grazes it. if ( ASq >= RadiusSq ) { return false; } double BSq = RadiusSq-ASq; if ( D>0.0 && D*D>BSq && (D<maxDist || BSq>Square(D-maxDist) ) ) { // Return the point where view intersects with the outside of // the sphere. *intersectDistance = D-sqrt(BSq); v = viewDir; v *= *intersectDistance; v += viewPos; // Position of intersection returnedPoint.SetPosition( v ); v -= Center; v /= Radius; // Normalize: normal out from intersection pt v.ReNormalize(); returnedPoint.SetNormal( v ); returnedPoint.SetMaterial ( *OuterMaterial ); returnedPoint.SetFrontFace(); // Front face direction CalcUV( v, &(returnedPoint.GetUV()) ); returnedPoint.SetFaceNumber( 0 ); return true; } else if ( (D>0.0 || D*D<BSq) && D<maxDist && BSq<Square(D-maxDist) ) { // return the point where view exits the sphere *intersectDistance = D+sqrt(BSq); v = viewDir; v *= *intersectDistance; v += viewPos; returnedPoint.SetPosition( v ); v -= Center; v /= Radius; // Normalize, but still points outward v.ReNormalize(); // Just in case returnedPoint.SetNormal( v ); returnedPoint.SetMaterial ( *InnerMaterial ); returnedPoint.SetBackFace(); CalcUV( v, &(returnedPoint.GetUV()) ); return true; } else { return false; } }
void UOpenALAudioSubsystem::Update( FPointRegion Region, FCoords& Coords ) { guard(UOpenALAudioSubsystem::Update); if( !Viewport ) return; AActor *ViewActor = FindViewActor(); guard(UpdateMusic); if( Viewport->Actor->Song != PlayingSong ) { StopMusic(); PlayingSong = Viewport->Actor->Song; if( PlayingSong != NULL ) { MODULE* Module = GetModuleFromUMusic( PlayingSong ); Player_Start( Module ); } } if( Player_Active() ) MikMod_Update(); unguard; // Update the listener. { FVector At = ViewActor->Rotation.Vector(); FVector Up = -(GMath.UnitCoords / ViewActor->Rotation).ZAxis; FLOAT Orientation[6] = { At.X, At.Y, At.Z, Up.X, Up.Y, Up.Z }; alListenerfv( AL_POSITION, &ViewActor->Location.X ); alListenerfv( AL_VELOCITY, &ViewActor->Velocity.X ); alListenerfv( AL_ORIENTATION, Orientation ); } // See if any new ambient sounds need to be started. UBOOL Realtime = Viewport->IsRealtime() && Viewport->Actor->Level->Pauser==TEXT(""); if( Realtime ) { guard(StartAmbience); for( INT i=0; i<Viewport->Actor->GetLevel()->Actors.Num(); i++ ) { AActor* Actor = Viewport->Actor->GetLevel()->Actors(i); if ( Actor && Actor->AmbientSound && FDistSquared(ViewActor->Location,Actor->Location)<=Square(Actor->WorldSoundRadius()) ) { INT Slot = Actor->GetIndex()*16+SLOT_Ambient*2; INT j; // See if there's already an existing slot. for( j=0; j<NumSources; j++ ) if( Sources[j].Slot==Slot ) break; // If not, start playing. if( j==NumSources ) PlaySound( Actor, Slot, Actor->AmbientSound, Actor->Location, AmbientFactor*Actor->SoundVolume/255.0, Actor->WorldSoundRadius(), Actor->SoundPitch/64.0, 1 ); } } unguard; } // Update all playing ambient sounds. guard(UpdateAmbience); for( INT i=0; i<NumSources; i++ ) { FAudioSource& Source = Sources[i]; if( (Source.Slot&14)==SLOT_Ambient*2 ) { check(Source.Actor); if ( FDistSquared(ViewActor->Location,Source.Actor->Location)>Square(Source.Actor->WorldSoundRadius()) || Source.Actor->AmbientSound!=Source.Sound || !Realtime ) { // Ambient sound went out of range. StopSource( Source ); } else { // Update basic sound properties. FLOAT Volume = 2.0 * (AmbientFactor*Source.Actor->SoundVolume/255.0); // XXX: Huh? What does light brightness have to do with it? if( Source.Actor->LightType!=LT_None ) Volume *= Source.Actor->LightBrightness/255.0; Source.Volume = Volume; Source.Radius = Source.Actor->WorldSoundRadius(); const ALuint Id = Source.Id; alSourcef( Id, AL_GAIN, Source.Volume ); alSourcef( Id, AL_MAX_DISTANCE, Source.Radius ); alSourcef( Id, AL_PITCH, Source.Actor->SoundPitch/64.0 ); } } } unguard; // Update all active sounds. guard(UpdateSounds); for( INT Index=0; Index<NumSources; Index++ ) { FAudioSource& Source = Sources[Index]; // We should've been notified about this. if( Source.Actor ) check(Source.Actor->IsValid()); // Check if the sound is playing. if( Source.Slot==0 ) continue; // Check if the sound is finished. ALint state; alGetSourcei( Source.Id, AL_SOURCE_STATE, &state ); if( state==AL_STOPPED ) { StopSource( Source ); continue; } // Update positioning from actor, if available. if( Source.Actor ) { Source.Location = Source.Actor->Location; alSourcefv( Source.Id, AL_POSITION, &Source.Actor->Location.X ); alSourcefv( Source.Id, AL_VELOCITY, &Source.Actor->Velocity.X ); } // Update the priority. Source.Priority = SoundPriority( Source.Location, Source.Volume, Source.Radius ); } unguard; unguard; }
void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) { const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; #ifdef HL2_DLL if( bInWater ) { // Only muffle the explosion if deeper than 2 feet in water. if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) ) { bInWater = false; } } #endif // HL2_DLL vecSrc.z += 1;// in case grenade is lying on the ground float flHalfRadiusSqr = Square( flRadius / 2.0f ); // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) { // This value is used to scale damage when the explosion is blocked by some other object. float flBlockedDamagePercent = 0.0f; if ( pEntity == pEntityIgnore ) continue; if ( pEntity->m_takedamage == DAMAGE_NO ) continue; // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // Check that the explosion can 'see' this entity. vecSpot = pEntity->BodyTarget( vecSrc, false ); UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( old_radius_damage.GetBool() ) { if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) continue; } else { if ( tr.fraction != 1.0 ) { if ( IsExplosionTraceBlocked(&tr) ) { if( ShouldUseRobustRadiusDamage( pEntity ) ) { if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) { // Only use robust model on a target within one-half of the explosion's radius. continue; } Vector vecToTarget = vecSpot - tr.endpos; VectorNormalize( vecToTarget ); // We're going to deflect the blast along the surface that // interrupted a trace from explosion to this target. Vector vecUp, vecDeflect; CrossProduct( vecToTarget, tr.plane.normal, vecUp ); CrossProduct( tr.plane.normal, vecUp, vecDeflect ); VectorNormalize( vecDeflect ); // Trace along the surface that intercepted the blast... UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); if( tr.fraction != 1.0 && tr.DidHitWorld() ) { // Still can't reach the target. continue; } // else fall through } else { continue; } } // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? // HL2 - Dissolve damage is not reduced by interposing non-world objects if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) { // Some entity was hit by the trace, meaning the explosion does not have clear // line of sight to the entity that it's trying to hurt. If the world is also // blocking, we do no damage. CBaseEntity *pBlockingEntity = tr.m_pEnt; //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { continue; } // Now, if the interposing object is physics, block some explosion force based on its mass. if( pBlockingEntity->VPhysicsGetObject() ) { const float MASS_ABSORB_ALL_DAMAGE = 350.0f; float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); float scale = flMass / MASS_ABSORB_ALL_DAMAGE; // Absorbed all the damage. if( scale >= 1.0f ) { continue; } ASSERT( scale > 0.0f ); flBlockedDamagePercent = scale; //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); } else { // Some object that's not the world and not physics. Generically block 25% damage flBlockedDamagePercent = 0.25f; } } } } // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage <= 0 ) { continue; } // the explosion can 'see' this entity, so hurt them! if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } CTakeDamageInfo adjustedInfo = info; //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); // Now make a consideration for skill level! if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) { // An explosion set off by the player is harming an NPC. Adjust damage accordingly. adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); } Vector dir = vecSpot - vecSrc; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); } } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) { ClearMultiDamage( ); pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); ApplyMultiDamage(); } else { pEntity->TakeDamage( adjustedInfo ); } // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); #if defined( GAME_DLL ) if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) { // This is a total hack!!! bool bIsPrimary = true; CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) { bIsPrimary = false; } gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); } #endif } }
/* ================= idSurface_Patch::Subdivide ================= */ void idSurface_Patch::Subdivide( float maxHorizontalError, float maxVerticalError, float maxLength, bool genNormals ) { int i, j, k, l; idDrawVert prev, next, mid; idVec3 prevxyz, nextxyz, midxyz; idVec3 delta; float maxHorizontalErrorSqr, maxVerticalErrorSqr, maxLengthSqr; // generate normals for the control mesh if ( genNormals ) { GenerateNormals(); } maxHorizontalErrorSqr = Square( maxHorizontalError ); maxVerticalErrorSqr = Square( maxVerticalError ); maxLengthSqr = Square( maxLength ); Expand(); // horizontal subdivisions for ( j = 0; j + 2 < width; j += 2 ) { // check subdivided midpoints against control points for ( i = 0; i < height; i++ ) { for ( l = 0; l < 3; l++ ) { prevxyz[l] = verts[i*maxWidth + j+1].xyz[l] - verts[i*maxWidth + j ].xyz[l]; nextxyz[l] = verts[i*maxWidth + j+2].xyz[l] - verts[i*maxWidth + j+1].xyz[l]; midxyz[l] = (verts[i*maxWidth + j ].xyz[l] + verts[i*maxWidth + j+1].xyz[l] * 2.0f + verts[i*maxWidth + j+2].xyz[l] ) * 0.25f; } if ( maxLength > 0.0f ) { // if the span length is too long, force a subdivision if ( prevxyz.LengthSqr() > maxLengthSqr || nextxyz.LengthSqr() > maxLengthSqr ) { break; } } // see if this midpoint is off far enough to subdivide delta = verts[i*maxWidth + j+1].xyz - midxyz; if ( delta.LengthSqr() > maxHorizontalErrorSqr ) { break; } } if ( i == height ) { continue; // didn't need subdivision } if ( width + 2 >= maxWidth ) { ResizeExpanded( maxHeight, maxWidth + 4 ); } // insert two columns and replace the peak width += 2; for ( i = 0; i < height; i++ ) { idSurface_Patch::LerpVert( verts[i*maxWidth + j ], verts[i*maxWidth + j+1], prev ); idSurface_Patch::LerpVert( verts[i*maxWidth + j+1], verts[i*maxWidth + j+2], next ); idSurface_Patch::LerpVert( prev, next, mid ); for ( k = width - 1; k > j + 3; k-- ) { verts[i*maxWidth + k] = verts[i*maxWidth + k-2]; } verts[i*maxWidth + j+1] = prev; verts[i*maxWidth + j+2] = mid; verts[i*maxWidth + j+3] = next; } // back up and recheck this set again, it may need more subdivision j -= 2; } // vertical subdivisions for ( j = 0; j + 2 < height; j += 2 ) { // check subdivided midpoints against control points for ( i = 0; i < width; i++ ) { for ( l = 0; l < 3; l++ ) { prevxyz[l] = verts[(j+1)*maxWidth + i].xyz[l] - verts[j*maxWidth + i].xyz[l]; nextxyz[l] = verts[(j+2)*maxWidth + i].xyz[l] - verts[(j+1)*maxWidth + i].xyz[l]; midxyz[l] = (verts[j*maxWidth + i].xyz[l] + verts[(j+1)*maxWidth + i].xyz[l] * 2.0f + verts[(j+2)*maxWidth + i].xyz[l] ) * 0.25f; } if ( maxLength > 0.0f ) { // if the span length is too long, force a subdivision if ( prevxyz.LengthSqr() > maxLengthSqr || nextxyz.LengthSqr() > maxLengthSqr ) { break; } } // see if this midpoint is off far enough to subdivide delta = verts[(j+1)*maxWidth + i].xyz - midxyz; if ( delta.LengthSqr() > maxVerticalErrorSqr ) { break; } } if ( i == width ) { continue; // didn't need subdivision } if ( height + 2 >= maxHeight ) { ResizeExpanded( maxHeight + 4, maxWidth ); } // insert two columns and replace the peak height += 2; for ( i = 0; i < width; i++ ) { LerpVert( verts[j*maxWidth + i], verts[(j+1)*maxWidth + i], prev ); LerpVert( verts[(j+1)*maxWidth + i], verts[(j+2)*maxWidth + i], next ); LerpVert( prev, next, mid ); for ( k = height - 1; k > j + 3; k-- ) { verts[k*maxWidth + i] = verts[(k-2)*maxWidth + i]; } verts[(j+1)*maxWidth + i] = prev; verts[(j+2)*maxWidth + i] = mid; verts[(j+3)*maxWidth + i] = next; } // back up and recheck this set again, it may need more subdivision j -= 2; } PutOnCurve(); RemoveLinearColumnsRows(); Collapse(); // normalize all the lerped normals if ( genNormals ) { for ( i = 0; i < width * height; i++ ) { verts[i].normal.Normalize(); } } GenerateIndexes(); }
void Errors(const Model & model, std::vector<double> & vec_errors) const { vec_errors.resize(x1_.cols()); for (size_t sample = 0; sample < x1_.cols(); ++sample) vec_errors[sample] = Square(ErrorT::Error(model, x1_.col(sample), x2_.col(sample))); }
/* determine if two extraction areas overlap */ bool CExtractorBuilding::IsNeighbour(CExtractorBuilding* other) { // circle vs. circle return (this->pos.SqDistance2D(other->pos) < Square(this->extractionRange + other->extractionRange)); }
void idSurface_Patch::GenerateNormals( void ) { int i, j, k, dist; idVec3 norm; idVec3 sum; int count; idVec3 base; idVec3 delta; int x, y; idVec3 around[8], temp; bool good[8]; bool wrapWidth, wrapHeight; static int neighbors[8][2] = { {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} }; assert( expanded == false ); // // if all points are coplanar, set all normals to that plane // idVec3 extent[3]; float offset; extent[0] = verts[width - 1].xyz - verts[0].xyz; extent[1] = verts[(height-1) * width + width - 1].xyz - verts[0].xyz; extent[2] = verts[(height-1) * width].xyz - verts[0].xyz; norm = extent[0].Cross( extent[1] ); if ( norm.LengthSqr() == 0.0f ) { norm = extent[0].Cross( extent[2] ); if ( norm.LengthSqr() == 0.0f ) { norm = extent[1].Cross( extent[2] ); } } // wrapped patched may not get a valid normal here if ( norm.Normalize() != 0.0f ) { offset = verts[0].xyz * norm; for ( i = 1; i < width * height; i++ ) { float d = verts[i].xyz * norm; if ( idMath::Fabs( d - offset ) > COPLANAR_EPSILON ) { break; } } if ( i == width * height ) { // all are coplanar for ( i = 0; i < width * height; i++ ) { verts[i].normal = norm; } return; } } // check for wrapped edge cases, which should smooth across themselves wrapWidth = false; for ( i = 0; i < height; i++ ) { delta = verts[i * width].xyz - verts[i * width + width-1].xyz; if ( delta.LengthSqr() > Square( 1.0f ) ) { break; } } if ( i == height ) { wrapWidth = true; } wrapHeight = false; for ( i = 0; i < width; i++ ) { delta = verts[i].xyz - verts[(height-1) * width + i].xyz; if ( delta.LengthSqr() > Square( 1.0f ) ) { break; } } if ( i == width ) { wrapHeight = true; } for ( i = 0; i < width; i++ ) { for ( j = 0; j < height; j++ ) { count = 0; base = verts[j * width + i].xyz; for ( k = 0; k < 8; k++ ) { around[k] = vec3_origin; good[k] = false; for ( dist = 1; dist <= 3; dist++ ) { x = i + neighbors[k][0] * dist; y = j + neighbors[k][1] * dist; if ( wrapWidth ) { if ( x < 0 ) { x = width - 1 + x; } else if ( x >= width ) { x = 1 + x - width; } } if ( wrapHeight ) { if ( y < 0 ) { y = height - 1 + y; } else if ( y >= height ) { y = 1 + y - height; } } if ( x < 0 || x >= width || y < 0 || y >= height ) { break; // edge of patch } temp = verts[y * width + x].xyz - base; if ( temp.Normalize() == 0.0f ) { continue; // degenerate edge, get more dist } else { good[k] = true; around[k] = temp; break; // good edge } } } sum = vec3_origin; for ( k = 0; k < 8; k++ ) { if ( !good[k] || !good[(k+1)&7] ) { continue; // didn't get two points } norm = around[(k+1)&7].Cross( around[k] ); if ( norm.Normalize() == 0.0f ) { continue; } sum += norm; count++; } if ( count == 0 ) { //idLib::common->Printf("bad normal\n"); count = 1; } verts[j * width + i].normal = sum; verts[j * width + i].normal.Normalize(); } } }
/* ============ idAI::FindPathAroundObstacles Finds a path around dynamic obstacles using a path tree with clockwise and counter clockwise edge walks. ============ */ bool idAI::FindPathAroundObstacles( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path ) { int numObstacles, areaNum, insideObstacle; obstacle_t obstacles[MAX_OBSTACLES]; idBounds clipBounds; idBounds bounds; pathNode_t *root; bool pathToGoalExists; path.seekPos = seekPos; path.firstObstacle = NULL; path.startPosOutsideObstacles = startPos; path.startPosObstacle = NULL; path.seekPosOutsideObstacles = seekPos; path.seekPosObstacle = NULL; if ( !aas ) { return true; } bounds[1] = aas->GetSettings()->boundingBoxes[0][1]; bounds[0] = -bounds[1]; bounds[1].z = 32.0f; // get the AAS area number and a valid point inside that area areaNum = aas->PointReachableAreaNum( path.startPosOutsideObstacles, bounds, (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ); aas->PushPointIntoAreaNum( areaNum, path.startPosOutsideObstacles ); // get all the nearby obstacles numObstacles = GetObstacles( physics, aas, ignore, areaNum, path.startPosOutsideObstacles, path.seekPosOutsideObstacles, obstacles, MAX_OBSTACLES, clipBounds ); // get a source position outside the obstacles GetPointOutsideObstacles( obstacles, numObstacles, path.startPosOutsideObstacles.ToVec2(), &insideObstacle, NULL ); if ( insideObstacle != -1 ) { path.startPosObstacle = obstacles[insideObstacle].entity; } // get a goal position outside the obstacles GetPointOutsideObstacles( obstacles, numObstacles, path.seekPosOutsideObstacles.ToVec2(), &insideObstacle, NULL ); if ( insideObstacle != -1 ) { path.seekPosObstacle = obstacles[insideObstacle].entity; } // if start and destination are pushed to the same point, we don't have a path around the obstacle if ( ( path.seekPosOutsideObstacles.ToVec2() - path.startPosOutsideObstacles.ToVec2() ).LengthSqr() < Square( 1.0f ) ) { if ( ( seekPos.ToVec2() - startPos.ToVec2() ).LengthSqr() > Square( 2.0f ) ) { return false; } } // build a path tree root = BuildPathTree( obstacles, numObstacles, clipBounds, path.startPosOutsideObstacles.ToVec2(), path.seekPosOutsideObstacles.ToVec2(), path ); // draw the path tree if ( ai_showObstacleAvoidance.GetBool() ) { DrawPathTree( root, physics->GetOrigin().z ); } // prune the tree PrunePathTree( root, path.seekPosOutsideObstacles.ToVec2() ); // find the optimal path pathToGoalExists = FindOptimalPath( root, obstacles, numObstacles, physics->GetOrigin().z, physics->GetLinearVelocity(), path.seekPos ); // free the tree FreePathTree_r( root ); return pathToGoalExists; }