示例#1
0
/*
==============
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;
}
示例#2
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);
	}
}