/* ============== idGrabber::Update ============== */ int idGrabber::Update( idEntity* player, bool hide ) { trace_t trace; idEntity* newEnt; if ( owner && owner->GetUserCmd() == NULL ) return 3; // pause before allowing refire if( lastFiredTime + FIRING_DELAY > gameLocal.time ) { return 3; } // Dead players release the trigger if( hide || player->health <= 0 ) { StopDrag( true ); if( hide ) { lastFiredTime = gameLocal.time - FIRING_DELAY + 250; } return 3; } // Check if object being held has been removed (dead demon, projectile, etc.) if( endTime > gameLocal.time ) { bool abort = !dragEnt.IsValid(); if( !abort && dragEnt.GetEntity()->IsType( idProjectile::Type ) ) { idProjectile* proj = ( idProjectile* )dragEnt.GetEntity(); if( proj->GetProjectileState() >= 3 ) { abort = true; } } if( !abort && dragEnt.GetEntity() && dragEnt.GetEntity()->IsHidden() ) { abort = true; } // Not in multiplayer :: Pressing "reload" lets you carefully drop an item if( !common->IsMultiplayer() && !abort && ( player->GetUserCmd()->impulseSequence != oldImpulseSequence ) && ( player->GetUserCmd()->impulse == IMPULSE_13 ) ) { abort = true; } if( abort ) { StopDrag( true ); return 3; } } owner = player; // if no entity selected for dragging if( !dragEnt.GetEntity() ) { idVec3 viewPos; idMat3 viewAxis; owner->GetViewPos( viewPos, viewAxis ); idBounds bounds; idVec3 end = viewPos + viewAxis[0] * dragTraceDist; bounds.Zero(); bounds.ExpandSelf( TRACE_BOUNDS_SIZE ); gameLocal.clip.TraceBounds( trace, viewPos, end, bounds, MASK_SHOT_RENDERMODEL | CONTENTS_PROJECTILE | CONTENTS_MOVEABLECLIP, player ); // If the trace hit something if( trace.fraction < 1.0f ) { newEnt = gameLocal.entities[ trace.c.entityNum ]; // if entity is already being grabbed then bypass if( common->IsMultiplayer() && newEnt && newEnt->IsGrabbed() ) { return 0; } // Check if this is a valid entity to hold if( newEnt && ( newEnt->IsType( idMoveable::Type ) || newEnt->IsType( idMoveableItem::Type ) || newEnt->IsType( idProjectile::Type ) || newEnt->IsType( idAFEntity_Gibbable::Type ) ) && newEnt->noGrab == false && newEnt->GetPhysics()->GetBounds().GetRadius() < MAX_PICKUP_SIZE && newEnt->GetPhysics()->GetLinearVelocity().LengthSqr() < MAX_PICKUP_VELOCITY ) { bool validAF = true; if( newEnt->IsType( idAFEntity_Gibbable::Type ) ) { idAFEntity_Gibbable* afEnt = static_cast<idAFEntity_Gibbable*>( newEnt ); if( grabbableAI( newEnt->spawnArgs.GetString( "classname" ) ) ) { // Make sure it's also active if( !afEnt->IsActive() ) { validAF = false; } } else if( !afEnt->IsActiveAF() ) { validAF = false; } } if( validAF && player->GetUserCmd()->buttons & BUTTON_ATTACK ) { // Grab this entity and start dragging it around StartDrag( newEnt, trace.c.id ); } else if( validAF ) { // A holdable object is ready to be grabbed return 1; } } } } // check backwards server time in multiplayer bool allow = true; if( common->IsMultiplayer() ) { // if we've marched backwards if( gameLocal.slow.time < startDragTime ) { allow = false; } } // if there is an entity selected for dragging if( dragEnt.GetEntity() && allow ) { idPhysics* entPhys = dragEnt.GetEntity()->GetPhysics(); idVec3 goalPos; // If the player lets go of attack, or time is up if( !( player->GetUserCmd()->buttons & BUTTON_ATTACK ) ) { StopDrag( false ); return 3; } if( gameLocal.time > endTime ) { StopDrag( true ); return 3; } // Check if the player is standing on the object if( !holdingAF ) { idBounds playerBounds; idBounds objectBounds = entPhys->GetAbsBounds(); idVec3 newPoint = player->GetPhysics()->GetOrigin(); // create a bounds at the players feet playerBounds.Clear(); playerBounds.AddPoint( newPoint ); newPoint.z -= 1.f; playerBounds.AddPoint( newPoint ); playerBounds.ExpandSelf( 8.f ); // If it intersects the object bounds, then drop it if( playerBounds.IntersectsBounds( objectBounds ) ) { StopDrag( true ); return 3; } } // Shake the object at the end of the hold if( g_grabberEnableShake.GetBool() && !common->IsMultiplayer() ) { ApplyShake(); } idVec3 viewPos; idMat3 viewAxis; owner->GetViewPos( viewPos, viewAxis ); // Set and evaluate drag force goalPos = viewPos + localPlayerPoint * viewAxis; drag.SetGoalPosition( goalPos ); drag.Evaluate( gameLocal.time ); // If an object is flying too fast toward the player, stop it hard if( g_grabberHardStop.GetBool() ) { idPlane theWall; idVec3 toPlayerVelocity, objectCenter; float toPlayerSpeed; toPlayerVelocity = -viewAxis[0]; toPlayerSpeed = entPhys->GetLinearVelocity() * toPlayerVelocity; if( toPlayerSpeed > 64.f ) { objectCenter = entPhys->GetAbsBounds().GetCenter(); theWall.SetNormal( viewAxis[0] ); theWall.FitThroughPoint( goalPos ); if( theWall.Side( objectCenter, 0.1f ) == PLANESIDE_BACK ) { int i, num; num = entPhys->GetNumClipModels(); for( i = 0; i < num; i++ ) { entPhys->SetLinearVelocity( vec3_origin, i ); } } } // Make sure the object isn't spinning too fast const float MAX_ROTATION_SPEED = 12.f; idVec3 angVel = entPhys->GetAngularVelocity(); float rotationSpeed = angVel.LengthFast(); if( rotationSpeed > MAX_ROTATION_SPEED ) { angVel.NormalizeFast(); angVel *= MAX_ROTATION_SPEED; entPhys->SetAngularVelocity( angVel ); } } // Orient projectiles away from the player if( dragEnt.GetEntity()->IsType( idProjectile::Type ) ) { idAngles ang = viewAxis[0].ToAngles(); ang.pitch += 90.f; entPhys->SetAxis( ang.ToMat3() ); } // Some kind of effect from gun to object? UpdateBeams(); // If the object is stuck away from its intended position for more than 500ms, let it go. if( drag.GetDistanceToGoal() > DRAG_FAIL_LEN ) { if( dragFailTime < ( gameLocal.slow.time - 500 ) ) { StopDrag( true ); return 3; } } else { dragFailTime = gameLocal.slow.time; } // Currently holding an object return 2; } // Not holding, nothing to hold return 0; }
void CCellView::MouseDown(BPoint where) { StPenState save(this); try { bool optional = IsOptionalClick(Window()->CurrentMessage()); if (!IsFocus() && !fEntering) MakeFocus(); ResetOffset(-1); BRect myRect, bounds(Bounds()); cell myCell = cell(fFrozen.h ? 1 : fPosition.h, fFrozen.v ? 1 : fPosition.v); if (fFirstGraphic) { if (fFirstGraphic->HandleMouseDown(where)) return; else if (fFirstGraphic->HasFocus()) fFirstGraphic->MakeFocus(false); } if (fCellBounds.Contains(where)) { if ((PointIsInSelection(where) && !fEntering) && (optional || WaitMouseMoved(where, false))) { StartDrag(where, optional); } else if (optional) GridMenu(where); else SelectCell(where); } if (!fShowBorders) return; myRect = bounds; myRect.top = fBorderHeight; myRect.left = 0.0; myRect.right = fBorderWidth; if (myRect.Contains(where)) { if (optional) BorderMenu(where); else { do { myCell.v++; GetCellRect(myCell, myRect); } while (myRect.top + 2.0 <= where.y); if (where.y >= myRect.top - 2.0 && where.y <= myRect.top + 2.0) ResizeRow(where, myCell.v - 1); else SelectRow(where, myCell.v - 1); } return; } myRect.Set(fBorderWidth, 0.0, bounds.right, fBorderHeight); if (myRect.Contains(where)) { if (optional) BorderMenu(where); else { do { myCell.h++; GetCellRect(myCell, myRect); } while (myRect.left + 2.0 <= where.x); if (where.x >= myRect.left - 2.0 && where.x <= myRect.left + 2.0) ResizeCol(where, myCell.h - 1); else SelectCol(where, myCell.h - 1); } return; } myRect.Set(0.0, 0.0, fBorderWidth, fBorderHeight); if (myRect.Contains(where)) { if (!fEntering) SetSelection(range(1, 1, kColCount, kRowCount)); else beep(); } } catch(CErr& e) { CATCHED; e.DoError(); return; } catch(...) { CATCHED; ASSERT(FALSE); } }