bool idMoveable::Collide( const trace_t &collision, const idVec3 &velocity ) {
	// greebo: Check whether we are colliding with the nearly exact same point again
	bool sameCollisionAgain = ( lastCollision.fraction != -1 && lastCollision.c.point.Compare( collision.c.point, 0.05f ) );
	// greebo: Save the collision info for the next call
	lastCollision = collision;
	float v = -( velocity * collision.c.normal );
	if( !sameCollisionAgain ) {
		float bounceSoundMinVelocity = cv_bounce_sound_min_vel.GetFloat();
		float bounceSoundMaxVelocity = cv_bounce_sound_max_vel.GetFloat();
		if( ( v > bounceSoundMinVelocity ) && ( gameLocal.time > nextSoundTime ) ) {
			// grayman #3331 - some moveables should not bother with bouncing sounds
			if( !spawnArgs.GetBool( "no_bounce_sound", "0" ) ) {
				const idMaterial *material = collision.c.material;
				idStr sndNameLocal;
				idStr surfaceName; // "tile", "glass", etc.
				if( material != NULL ) {
					surfaceName = g_Global.GetSurfName( material );
					// Prepend the snd_bounce_ prefix to check for a surface-specific sound
					idStr sndNameWithSurface = "snd_bounce_" + surfaceName;
					if( spawnArgs.FindKey( sndNameWithSurface ) != NULL ) {
						sndNameLocal = sndNameWithSurface;
					} else {
						sndNameLocal = "snd_bounce";
					}
				}
				const char *sound = spawnArgs.GetString( sndNameLocal );
				const idSoundShader *sndShader = declManager->FindSound( sound );
				//f = v > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( v - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) );
				// angua: modify the volume set in the def instead of setting a fixed value.
				// At minimum velocity, the volume should be "min_velocity_volume_decrease" lower (in db) than the one specified in the def
				float f = ( v > bounceSoundMaxVelocity ) ? 0.0f : spawnArgs.GetFloat( "min_velocity_volume_decrease", "0" ) * ( idMath::Sqrt( v - bounceSoundMinVelocity ) * ( 1.0f / idMath::Sqrt( bounceSoundMaxVelocity - bounceSoundMinVelocity ) ) - 1 );
				float volume = sndShader->GetParms()->volume + f;
				if( cv_moveable_collision.GetBool() ) {
					gameRenderWorld->DrawText( va( "Velocity: %f", v ), ( physicsObj.GetOrigin() + idVec3( 0, 0, 20 ) ), 0.25f, colorGreen, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1, 100 * gameLocal.msec );
					gameRenderWorld->DrawText( va( "Volume: %f", volume ), ( physicsObj.GetOrigin() + idVec3( 0, 0, 10 ) ), 0.25f, colorGreen, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1, 100 * gameLocal.msec );
					gameRenderWorld->DebugArrow( colorMagenta, collision.c.point, ( collision.c.point + 30 * collision.c.normal ), 4.0f, 1 );
				}
				SetSoundVolume( volume );
				// greebo: We don't use StartSound() here, we want to do the sound propagation call manually
				StartSoundShader( sndShader, SND_CHANNEL_ANY, 0, false, NULL );
				// grayman #2603 - don't propagate a sound if this is a doused torch dropped by an AI
				if( !spawnArgs.GetBool( "is_torch", "0" ) ) {
					idStr sndPropName = GetSoundPropNameForMaterial( surfaceName );
					// Propagate a suspicious sound, using the "group" convention (soft, hard, small, med, etc.)
					PropSoundS( NULL, sndPropName, f, 0 ); // grayman #3355
				}
				SetSoundVolume( 0.0f );
				nextSoundTime = gameLocal.time + 500;
			}
		}
		// tels:
		//DM_LOG(LC_ENTITY, LT_INFO)LOGSTRING("Moveable %s might call script_collide %s because m_collideScriptCounter = %i and v = %f and time (%d) > m_nextCollideScriptTime (%d)\r",
		//		name.c_str(), m_scriptCollide.c_str(), m_collideScriptCounter, v, gameLocal.time, m_nextCollideScriptTime );
		if( ( m_collideScriptCounter != 0 ) && ( v > m_minScriptVelocity ) && ( gameLocal.time > m_nextCollideScriptTime ) ) {
			if( m_collideScriptCounter > 0 ) {
				// if positive, decrement it, so -1 stays as it is (for 0, we never come here)
				m_collideScriptCounter --;
			}
			// call the script
			const function_t *pScriptFun = scriptObject.GetFunction( m_scriptCollide.c_str() );
			if( pScriptFun == NULL ) {
				// Local function not found, check in global namespace
				pScriptFun = gameLocal.program.FindFunction( m_scriptCollide.c_str() );
			}
			if( pScriptFun != NULL ) {
				DM_LOG( LC_ENTITY, LT_INFO )LOGSTRING( "Moveable %s calling script_collide %s.\r",
													   name.c_str(), m_scriptCollide.c_str() );
				idThread *pThread = new idThread( pScriptFun );
				pThread->CallFunctionArgs( pScriptFun, true, "e", this );
				pThread->DelayedStart( 0 );
			} else {
				// script function not found!
				DM_LOG( LC_ENTITY, LT_ERROR )LOGSTRING( "Moveable %s could not find script_collide %s.\r",
														name.c_str(), m_scriptCollide.c_str() );
				m_collideScriptCounter = 0;
			}
			m_nextCollideScriptTime = gameLocal.time + 300;
		}
	}
	idEntity *ent = gameLocal.entities[ collision.c.entityNum ];
	trace_t newCollision = collision; // grayman #2816 - in case we need to modify collision
	// grayman #2816 - if we hit the world, skip all the damage work
	if( ent && ( ent != gameLocal.world ) ) {
		idActor *entActor = NULL;
		if( ent->IsType( idActor::Type ) ) {
			entActor = static_cast<idActor *>( ent ); // the object hit an actor directly
		} else if( ent->IsType( idAFAttachment::Type ) ) {
			newCollision.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( static_cast<idAFAttachment *>( ent )->GetAttachJoint() );
		}
		// go up the bindMaster chain to see if an Actor is lurking
		if( entActor == NULL ) { // no actor yet, so ent is an attachment or an attached moveable
			idEntity *bindMaster = ent->GetBindMaster();
			while( bindMaster != NULL ) {
				if( bindMaster->IsType( idActor::Type ) ) {
					entActor = static_cast<idActor *>( bindMaster ); // the object hit something attached to an actor
					// If ent is an idAFAttachment, we can leave ent alone
					// and pass the damage to it. It will, in turn, pass the
					// damage to the actor it's attached to. (helmets)
					// If ent is NOT an attachment, we have to change it to
					// be the actor we just found. Inventor goggles are an
					// example of when we have to do this, because they're
					// an idMoveable, and they DON'T transfer their damage
					// to the actor they're attached to.
					if( !ent->IsType( idAFAttachment::Type ) ) {
						ent = bindMaster;
					}
					break;
				}
				bindMaster = bindMaster->GetBindMaster(); // go up the chain
			}
		}
		// grayman #2816 - in order to allow knockouts from dropped objects,
		// we have to allow collisions where the velocity is < minDamageVelocity,
		// because dropped objects can have low velocity, while at the same time
		// carrying enough damage to warrant a KO possibility.
		if( canDamage && damage.Length() && ( gameLocal.time > nextDamageTime ) ) {
			if( !entActor || !entActor->AI_DEAD ) {
				float f;
				if( v < minDamageVelocity ) {
					f = 0.0f;
				} else if( v < maxDamageVelocity ) {
					f = idMath::Sqrt( ( v - minDamageVelocity ) / ( maxDamageVelocity - minDamageVelocity ) );
				} else {
					f = 1.0f; // capped when v >= maxDamageVelocity
				}
				// scale the damage by the surface type multiplier, if any
				idStr SurfTypeName;
				g_Global.GetSurfName( newCollision.c.material, SurfTypeName );
				SurfTypeName = "damage_mult_" + SurfTypeName;
				f *= spawnArgs.GetFloat( SurfTypeName.c_str(), "1.0" );
				idVec3 dir = velocity;
				dir.NormalizeFast();
				// Use a technique similar to what's used for a melee collision
				// to find a better joint (location), because when the head is
				// hit, the joint isn't identified correctly w/o it.
				int location = JOINT_HANDLE_TO_CLIPMODEL_ID( newCollision.c.id );
				// If this moveable is attached to an AI, identify that AI.
				// Otherwise, assume it was put in motion by someone.
				idEntity *attacker = GetPhysics()->GetClipModel()->GetOwner();
				if( attacker == NULL ) {
					attacker = m_SetInMotionByActor.GetEntity();
				}
				// grayman #3370 - if the entity being hit is the attacker, don't do damage
				if( attacker != ent ) {
					int preHealth = ent->health;
					ent->Damage( this, attacker, dir, damage, f, location, const_cast<trace_t *>( &newCollision ) );
					if( ent->health < preHealth ) { // only set the timer if there was damage
						nextDamageTime = gameLocal.time + 1000;
					}
				}
			}
		}
		// Darkmod: Collision stims and a tactile alert if it collides with an AI
		ProcCollisionStims( ent, newCollision.c.id ); // grayman #2816 - use new collision
		if( entActor && entActor->IsType( idAI::Type ) ) {
			static_cast<idAI *>( entActor )->TactileAlert( this );
		}
	}
	if( fxCollide.Length() && ( gameLocal.time > nextCollideFxTime ) ) {
		idEntityFx::StartFx( fxCollide, &collision.c.point, NULL, this, false );
		nextCollideFxTime = gameLocal.time + 3500;
	}
	return false;
}
idVec3 v4to3( const idVec4 &v ) {
	return idVec3( v.x / v.w, v.y / v.w, v.z / v.w );
}
Пример #3
0
/*
================
idIK_Walk::Init
================
*/
bool idIK_Walk::Init( idEntity *self, const char *anim, const idVec3 &modelOffset ) {
	int i;
	float footSize;
	idVec3 verts[4];
	idTraceModel trm;
	const char *jointName;
	idVec3 dir, ankleOrigin, kneeOrigin, hipOrigin, dirOrigin;
	idMat3 axis, ankleAxis, kneeAxis, hipAxis;

	static idVec3 footWinding[4] = {
		idVec3(  1.0f,  1.0f, 0.0f ),
		idVec3( -1.0f,  1.0f, 0.0f ),
		idVec3( -1.0f, -1.0f, 0.0f ),
		idVec3(  1.0f, -1.0f, 0.0f )
	};

	if ( !self ) {
		return false;
	}

	numLegs = Min( self->spawnArgs.GetInt( "ik_numLegs", "0" ), MAX_LEGS );
	if ( numLegs == 0 ) {
		return true;
	}

	if ( !idIK::Init( self, anim, modelOffset ) ) {
		return false;
	}

	int numJoints = animator->NumJoints();
	idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( joints[0] ) );

	// create the animation frame used to setup the IK
	gameEdit->ANIM_CreateAnimFrame( animator->ModelHandle(), animator->GetAnim( modifiedAnim )->MD5Anim( 0 ), numJoints, joints, 1, animator->ModelDef()->GetVisualOffset() + modelOffset, animator->RemoveOrigin() );

	enabledLegs = 0;

	// get all the joints
	for ( i = 0; i < numLegs; i++ ) {

		jointName = self->spawnArgs.GetString( va( "ik_foot%d", i+1 ) );
		footJoints[i] = animator->GetJointHandle( jointName );
		if ( footJoints[i] == INVALID_JOINT ) {
			gameLocal.Error( "idIK_Walk::Init: invalid foot joint '%s'", jointName );
		}

		jointName = self->spawnArgs.GetString( va( "ik_ankle%d", i+1 ) );
		ankleJoints[i] = animator->GetJointHandle( jointName );
		if ( ankleJoints[i] == INVALID_JOINT ) {
			gameLocal.Error( "idIK_Walk::Init: invalid ankle joint '%s'", jointName );
		}

		jointName = self->spawnArgs.GetString( va( "ik_knee%d", i+1 ) );
		kneeJoints[i] = animator->GetJointHandle( jointName );
		if ( kneeJoints[i] == INVALID_JOINT ) {
			gameLocal.Error( "idIK_Walk::Init: invalid knee joint '%s'\n", jointName );
		}

		jointName = self->spawnArgs.GetString( va( "ik_hip%d", i+1 ) );
		hipJoints[i] = animator->GetJointHandle( jointName );
		if ( hipJoints[i] == INVALID_JOINT ) {
			gameLocal.Error( "idIK_Walk::Init: invalid hip joint '%s'\n", jointName );
		}

		jointName = self->spawnArgs.GetString( va( "ik_dir%d", i+1 ) );
		dirJoints[i] = animator->GetJointHandle( jointName );

		enabledLegs |= 1 << i;
	}

	jointName = self->spawnArgs.GetString( "ik_waist" );
	waistJoint = animator->GetJointHandle( jointName );
	if ( waistJoint == INVALID_JOINT ) {
		gameLocal.Error( "idIK_Walk::Init: invalid waist joint '%s'\n", jointName );
	}

	// get the leg bone lengths and rotation matrices
	for ( i = 0; i < numLegs; i++ ) {
		oldAnkleHeights[i] = 0.0f;

		ankleAxis = joints[ ankleJoints[ i ] ].ToMat3();
		ankleOrigin = joints[ ankleJoints[ i ] ].ToVec3();

		kneeAxis = joints[ kneeJoints[ i ] ].ToMat3();
		kneeOrigin = joints[ kneeJoints[ i ] ].ToVec3();

		hipAxis = joints[ hipJoints[ i ] ].ToMat3();
		hipOrigin = joints[ hipJoints[ i ] ].ToVec3();

		// get the IK direction
		if ( dirJoints[i] != INVALID_JOINT ) {
			dirOrigin = joints[ dirJoints[ i ] ].ToVec3();
			dir = dirOrigin - kneeOrigin;
		} else {
			dir.Set( 1.0f, 0.0f, 0.0f );
		}

		hipForward[i] = dir * hipAxis.Transpose();
		kneeForward[i] = dir * kneeAxis.Transpose();

		// conversion from upper leg bone axis to hip joint axis
		upperLegLength[i] = GetBoneAxis( hipOrigin, kneeOrigin, dir, axis );
		upperLegToHipJoint[i] = hipAxis * axis.Transpose();

		// conversion from lower leg bone axis to knee joint axis
		lowerLegLength[i] = GetBoneAxis( kneeOrigin, ankleOrigin, dir, axis );
		lowerLegToKneeJoint[i] = kneeAxis * axis.Transpose();
	}

	smoothing = self->spawnArgs.GetFloat( "ik_smoothing", "0.75" );
	waistSmoothing = self->spawnArgs.GetFloat( "ik_waistSmoothing", "0.75" );
	footShift = self->spawnArgs.GetFloat( "ik_footShift", "0" );
	waistShift = self->spawnArgs.GetFloat( "ik_waistShift", "0" );
	minWaistFloorDist = self->spawnArgs.GetFloat( "ik_minWaistFloorDist", "0" );
	minWaistAnkleDist = self->spawnArgs.GetFloat( "ik_minWaistAnkleDist", "0" );
	footUpTrace = self->spawnArgs.GetFloat( "ik_footUpTrace", "32" );
	footDownTrace = self->spawnArgs.GetFloat( "ik_footDownTrace", "32" );
	tiltWaist = self->spawnArgs.GetBool( "ik_tiltWaist", "0" );
	usePivot = self->spawnArgs.GetBool( "ik_usePivot", "0" );

	// setup a clip model for the feet
	footSize = self->spawnArgs.GetFloat( "ik_footSize", "4" ) * 0.5f;
	if ( footSize > 0.0f ) {
		for ( i = 0; i < 4; i++ ) {
			verts[i] = footWinding[i] * footSize;
		}
		trm.SetupPolygon( verts, 4 );
		footModel = new (TAG_PHYSICS_CLIP) idClipModel( trm );
	}

	initialized = true;

	return true;
}
Пример #4
0
/*
============
idMoveableItem::Event_Gib
============
*/
void idMoveableItem::Event_Gib(const char *damageDefName)
{
	Gib(idVec3(0, 0, 1), damageDefName);
}
Пример #5
0
/*
============
idAI::PredictPath

  Can also be used when there is no AAS file available however ledges are not detected.
============
*/
bool idAI::PredictPath( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path ) {
	int i, j, step, numFrames, curFrameTime;
	idVec3 delta, curStart, curEnd, curVelocity, lastEnd, stepUp, tmpStart;
	idVec3 gravity, gravityDir, invGravityDir;
	float maxStepHeight, minFloorCos;
	pathTrace_t trace;

	if ( aas && aas->GetSettings() ) {
		gravity = aas->GetSettings()->gravity;
		gravityDir = aas->GetSettings()->gravityDir;
		invGravityDir = aas->GetSettings()->invGravityDir;
		maxStepHeight = aas->GetSettings()->maxStepHeight;
		minFloorCos = aas->GetSettings()->minFloorCos;
	} else {
		gravity = DEFAULT_GRAVITY_VEC3;
		gravityDir = idVec3( 0, 0, -1 );
		invGravityDir = idVec3( 0, 0, 1 );
		maxStepHeight = 14.0f;
		minFloorCos = 0.7f;
	}

	path.endPos = start;
	path.endVelocity = velocity;
	path.endNormal.Zero();
	path.endEvent = 0;
	path.endTime = 0;
	path.blockingEntity = NULL;

	curStart = start;
	curVelocity = velocity;

	numFrames = ( totalTime + frameTime - 1 ) / frameTime;
	curFrameTime = frameTime;
	for ( i = 0; i < numFrames; i++ ) {

		if ( i == numFrames-1 ) {
			curFrameTime = totalTime - i * curFrameTime;
		}

		delta = curVelocity * curFrameTime * 0.001f;

		path.endVelocity = curVelocity;
		path.endTime = i * frameTime;

		// allow sliding along a few surfaces per frame
		for ( j = 0; j < MAX_FRAME_SLIDE; j++ ) {

			idVec3 lineStart = curStart;

			// allow stepping up three times per frame
			for ( step = 0; step < 3; step++ ) {

				curEnd = curStart + delta;
				if ( PathTrace( ent, aas, curStart, curEnd, stopEvent, trace, path ) ) {
					return true;
				}

				if ( step ) {

					// step down at end point
					tmpStart = trace.endPos;
					curEnd = tmpStart - stepUp;
					if ( PathTrace( ent, aas, tmpStart, curEnd, stopEvent, trace, path ) ) {
						return true;
					}

					// if not moved any further than without stepping up, or if not on a floor surface
					if ( (lastEnd - start).LengthSqr() > (trace.endPos - start).LengthSqr() - 0.1f ||
								( trace.normal * invGravityDir ) < minFloorCos ) {
						if ( stopEvent & SE_BLOCKED ) {
							path.endPos = lastEnd;
							path.endEvent = SE_BLOCKED;

							if ( ai_debugMove.GetBool() ) {
								gameRenderWorld->DebugLine( colorRed, lineStart, lastEnd );
							}

							return true;
						}

						curStart = lastEnd;
						break;
					}
				}

				path.endNormal = trace.normal;
				path.blockingEntity = trace.blockingEntity;

				// if the trace is not blocked or blocked by a floor surface
				if ( trace.fraction >= 1.0f || ( trace.normal * invGravityDir ) > minFloorCos ) {
					curStart = trace.endPos;
					break;
				}

				// save last result
				lastEnd = trace.endPos;

				// step up
				stepUp = invGravityDir * maxStepHeight;
				if ( PathTrace( ent, aas, curStart, curStart + stepUp, stopEvent, trace, path ) ) {
					return true;
				}
				stepUp *= trace.fraction;
				curStart = trace.endPos;
			}

			if ( ai_debugMove.GetBool() ) {
				gameRenderWorld->DebugLine( colorRed, lineStart, curStart );
			}

			if ( trace.fraction >= 1.0f ) {
				break;
			}

			delta.ProjectOntoPlane( trace.normal, OVERCLIP );
			curVelocity.ProjectOntoPlane( trace.normal, OVERCLIP );

			if ( stopEvent & SE_BLOCKED ) {
				// if going backwards
				if ( (curVelocity - gravityDir * curVelocity * gravityDir ) *
						(velocity - gravityDir * velocity * gravityDir) < 0.0f ) {
					path.endPos = curStart;
					path.endEvent = SE_BLOCKED;

					return true;
				}
			}
		}

		if ( j >= MAX_FRAME_SLIDE ) {
			if ( stopEvent & SE_BLOCKED ) {
				path.endPos = curStart;
				path.endEvent = SE_BLOCKED;
				return true;
			}
		}

		// add gravity
		curVelocity += gravity * frameTime * 0.001f;
	}

	path.endTime = totalTime;
	path.endVelocity = curVelocity;
	path.endPos = curStart;
	path.endEvent = 0;

	return false;
}
Пример #6
0
END_CLASS

/*
================
idTrigger::DrawDebugInfo
================
*/
void idTrigger::DrawDebugInfo()
{
	idMat3		axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3();
	idVec3		up = axis[ 2 ] * 5.0f;
	idBounds	viewTextBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
	idBounds	viewBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
	idBounds	box( idVec3( -4.0f, -4.0f, -4.0f ), idVec3( 4.0f, 4.0f, 4.0f ) );
	idEntity*	ent;
	idEntity*	target;
	int			i;
	bool		show;
	const function_t* func;
	
	viewTextBounds.ExpandSelf( 128.0f );
	viewBounds.ExpandSelf( 512.0f );
	for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() )
	{
		if( ent->GetPhysics()->GetContents() & ( CONTENTS_TRIGGER | CONTENTS_FLASHLIGHT_TRIGGER ) )
		{
			show = viewBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() );
			if( !show )
			{
				for( i = 0; i < ent->targets.Num(); i++ )
				{
					target = ent->targets[ i ].GetEntity();
					if( target != NULL && viewBounds.IntersectsBounds( target->GetPhysics()->GetAbsBounds() ) )
					{
						show = true;
						break;
					}
				}
			}
			
			if( !show )
			{
				continue;
			}
			
			gameRenderWorld->DebugBounds( colorOrange, ent->GetPhysics()->GetAbsBounds() );
			if( viewTextBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) )
			{
				gameRenderWorld->DrawText( ent->name.c_str(), ent->GetPhysics()->GetAbsBounds().GetCenter(), 0.1f, colorWhite, axis, 1 );
				gameRenderWorld->DrawText( ent->GetEntityDefName(), ent->GetPhysics()->GetAbsBounds().GetCenter() + up, 0.1f, colorWhite, axis, 1 );
				if( ent->IsType( idTrigger::Type ) )
				{
					func = static_cast<idTrigger*>( ent )->GetScriptFunction();
				}
				else
				{
					func = NULL;
				}
				
				if( func )
				{
					gameRenderWorld->DrawText( va( "call script '%s'", func->Name() ), ent->GetPhysics()->GetAbsBounds().GetCenter() - up, 0.1f, colorWhite, axis, 1 );
				}
			}
			
			for( i = 0; i < ent->targets.Num(); i++ )
			{
				target = ent->targets[ i ].GetEntity();
				if( target )
				{
					gameRenderWorld->DebugArrow( colorYellow, ent->GetPhysics()->GetAbsBounds().GetCenter(), target->GetPhysics()->GetOrigin(), 10, 0 );
					gameRenderWorld->DebugBounds( colorGreen, box, target->GetPhysics()->GetOrigin() );
					if( viewTextBounds.IntersectsBounds( target->GetPhysics()->GetAbsBounds() ) )
					{
						gameRenderWorld->DrawText( target->name.c_str(), target->GetPhysics()->GetAbsBounds().GetCenter(), 0.1f, colorWhite, axis, 1 );
					}
				}
			}
		}
	}
}
Пример #7
0
void sdClientAnimated::Event_GetColor() {
	sdProgram::ReturnVector( idVec3( renderEntity.shaderParms[ SHADERPARM_RED ], renderEntity.shaderParms[ SHADERPARM_GREEN ], renderEntity.shaderParms[ SHADERPARM_BLUE ] ) );
}
Пример #8
0
/*
===============
idBotAI::BotAI_CheckThinkState

Should the bot think this frame?
===============
*/
bool idBotAI::BotAI_CheckThinkState() {
	if ( botWorld->gameLocalInfo.botsPaused ) {
		return false;
	}

	if ( botWorld->gameLocalInfo.botsSleep ) {
		return false;
	}

	if ( botInfo->team == NOTEAM || botInfo->classType == NOCLASS ) {
		if ( botThreadData.AllowDebugData() ) {
//			assert( false );
		}
		return false;
	}

	if ( botThreadData.AllowDebugData() ) {
		if ( bot_skipThinkClient.GetInteger() == botNum ) {
			botUcmd->botCmds.godMode = true;
			return false;
		}

		if ( bot_godMode.GetInteger() == botNum ) {
			botUcmd->botCmds.godMode = true;
		}
	}

	if ( botInfo->isTeleporting ) {
		return false;
	}

	if ( botAAS.aas == NULL ) {
		if ( botThreadData.random.RandomInt( 100 ) > 98 ) {
			botUcmd->botCmds.hasNoGoals = true; //mal: pass a warning to the player to let them know we have no goals
		}
		return false;
	}

	if ( !botInfo->hasGroundContact && botInfo->invulnerableEndTime > botWorld->gameLocalInfo.time ) {
		return false; 
	} //mal: dont start thinking  until we've actually touched the ground after spawning in.

	if ( botInfo->justSpawned ) {
		UpdateBotsInformation( botInfo->classType, botInfo->team, false );
		return false; //mal: dont think til we have some team/class stuff to think about!
	}

	if ( botWorld->gameLocalInfo.debugBotWeapons ) {
		botUcmd->botCmds.lookDown = true;
		botUcmd->idealWeaponSlot = GUN;
		botUcmd->botCmds.attack = true;
		if ( !botInfo->weapInfo.primaryWeapHasAmmo && !botInfo->weapInfo.sideArmHasAmmo && !botInfo->justSpawned ) {
			botUcmd->botCmds.suicide = true;
		}
		Bot_MoveToGoal( botInfo->origin + idVec3( 5.0f, 5.0f, 0.0f ), vec3_zero, RUN, ( botThreadData.random.RandomInt( 100 ) > 80 ) ? RANDOM_JUMP : NULLMOVETYPE );
		return false;
	}

	if ( botInfo->resetState > 0 ) { 
		ResetBotsAI( ( botInfo->resetState == MINOR_RESET_EVENT ) ? false : true );
		return false;
	}

	return true;
}
Пример #9
0
// Gets called each time the mind is thinking
void CombatState::Think(idAI* owner)
{
	// Do we have an expiry date?
	if (_endTime > 0)
	{
		if (gameLocal.time >= _endTime)
		{
			owner->GetMind()->EndState();
		}

		return;
	}

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner))
	{
//		owner->GetMind()->EndState(); // grayman #3182 - already done in CheckAlertLevel()
		return;
	}

	// grayman #3331 - make sure you're still fighting the same enemy.
	// grayman #3355 - fight the closest enemy
	idActor* enemy = _enemy.GetEntity();
	idActor* newEnemy = owner->GetEnemy();

	if ( enemy )
	{
		if ( newEnemy && ( newEnemy != enemy ) )
		{
			idVec3 ownerOrigin = owner->GetPhysics()->GetOrigin();
			float dist2EnemySqr = ( enemy->GetPhysics()->GetOrigin() - ownerOrigin ).LengthSqr();
			float dist2NewEnemySqr = ( newEnemy->GetPhysics()->GetOrigin() - ownerOrigin ).LengthSqr();
			if ( dist2NewEnemySqr < dist2EnemySqr )
			{
				owner->GetMind()->EndState();
				return; // state has ended
			}
		}
	}
	else
	{
		enemy = newEnemy;
	}

	if (!CheckEnemyStatus(enemy, owner))
	{
		owner->GetMind()->EndState();
		return; // state has ended
	}

	// grayman #3520 - don't look toward new alerts
	if ( owner->m_lookAtAlertSpot )
	{
		owner->m_lookAtAlertSpot = false;
		owner->m_lookAtPos = idVec3(idMath::INFINITY,idMath::INFINITY,idMath::INFINITY);
	}

	// angua: look at enemy
	owner->Event_LookAtPosition(enemy->GetEyePosition(), gameLocal.msec);

	Memory& memory = owner->GetMemory();

	idVec3 vec2Enemy = enemy->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin();
	float dist2Enemy = vec2Enemy.LengthFast();

	// grayman #3331 - need to take vertical separation into account. It's possible to have the origins
	// close enough to be w/in the melee zone, but still be unable to hit the enemy.

	bool inMeleeRange = ( dist2Enemy <= ( 3 * owner->GetMeleeRange() ) );

	ECombatType newCombatType;
	
	if ( inMeleeRange && !_meleePossible ) // grayman #3355 - can't fight up close
	{
		owner->fleeingEvent = false; // grayman #3356
		owner->emitFleeBarks = false; // grayman #3474
		owner->GetMind()->SwitchState(STATE_FLEE);
		return;
	}

	if ( !inMeleeRange && _rangedPossible )
	{
		newCombatType = COMBAT_RANGED;
	}
	else
	{
		newCombatType = COMBAT_MELEE;
	}

	// Check for situation where you're in the melee zone, yet you're unable to hit
	// the enemy. This can happen if the enemy is above or below you and you can't
	// reach them.

	switch(_combatSubState)
	{
	case EStateReaction:
		{
		if ( gameLocal.time < _reactionEndTime )
		{
			return; // stay in this state until the reaction time expires
		}

		// Check to see if the enemy is still visible.
		// grayman #2816 - Visibility doesn't matter if you're in combat because
		// you bumped into your enemy.

		idEntity* tactEnt = owner->GetTactEnt();
		if ( ( tactEnt == NULL ) || !tactEnt->IsType(idActor::Type) || ( tactEnt != enemy ) || !owner->AI_TACTALERT ) 
		{
			if ( !owner->CanSee(enemy, true) )
			{
				owner->ClearEnemy();
				owner->SetAlertLevel(owner->thresh_5 - 0.1); // reset alert level just under Combat
				owner->GetMind()->EndState();
				return;
			}
		}

		owner->m_ignorePlayer = false; // grayman #3063 - clear flag that prevents mission statistics on player sightings

		// The AI has processed his reaction, and needs to move into combat, or flee.

		_criticalHealth = owner->spawnArgs.GetInt("health_critical", "0");

		// greebo: Check for weapons and flee if ...
		if ( ( !_meleePossible && !_rangedPossible )		 || // ... I'm unarmed
			 ( owner->spawnArgs.GetBool("is_civilian", "0")) || // ... I'm a civilian, and don't fight
			 ( owner->health < _criticalHealth ) )			    // grayman #3140 ... I'm very damaged and can't afford to engage in combat
		{
			owner->fleeingEvent = false; // grayman #3356
			owner->emitFleeBarks = true; // grayman #3474
			owner->GetMind()->SwitchState(STATE_FLEE);
			return;
		}

		memory.stopRelight = true; // grayman #2603 - abort a relight in progress
		memory.stopExaminingRope = true; // grayman #2872 - stop examining a rope
		memory.stopReactingToHit = true; // grayman #2816

		_combatSubState = EStateDoOnce;
		break;
		}

	case EStateDoOnce:
		{
		// Check for sitting or sleeping

		moveType_t moveType = owner->GetMoveType();
		if (   moveType == MOVETYPE_SIT 
			|| moveType == MOVETYPE_SLEEP
			|| moveType == MOVETYPE_SIT_DOWN
			|| moveType == MOVETYPE_LAY_DOWN )
		{
			owner->GetUp(); // okay if called multiple times
			return;
		}

		// grayman #3009 - check for getting up from sitting or sleeping
		if ( moveType == MOVETYPE_GET_UP || 
			 moveType == MOVETYPE_GET_UP_FROM_LYING )
		{
			return;
		}

		// not sitting or sleeping at this point

		// Stop what you're doing
		owner->StopMove(MOVE_STATUS_DONE);
		owner->movementSubsystem->ClearTasks();
		owner->senseSubsystem->ClearTasks();
		owner->actionSubsystem->ClearTasks();

		// Bark

		// This will hold the message to be delivered with the bark, if appropriate
		CommMessagePtr message;
	
		// Only alert the bystanders if we didn't receive the alert by message ourselves
		if (!memory.alertedDueToCommunication)
		{
			message = CommMessagePtr(new CommMessage(
				CommMessage::DetectedEnemy_CommType, 
				owner, NULL, // from this AI to anyone 
				enemy,
				memory.lastEnemyPos,
				0
			));
		}

		// grayman #3496 - This is an alert bark, but it's not subject to the delay
		// between alert barks because the previous bark will end before we get here.
		// It's also the culmination of a journey up from Idle State, and if the AI is
		// going to go after an enemy, this bark needs to be heard.
		// We'll still reset the last alert bark time, though.

		// The communication system plays starting bark

		// grayman #3343 - accommodate different barks for human and non-human enemies

		idPlayer* player(NULL);
		if (enemy->IsType(idPlayer::Type))
		{
			player = static_cast<idPlayer*>(enemy);
		}

		idStr bark = "";

		if (player && player->m_bShoulderingBody)
		{
			bark = "snd_spotted_player_with_body";
		}
		else if ((MS2SEC(gameLocal.time - memory.lastTimeFriendlyAISeen)) <= MAX_FRIEND_SIGHTING_SECONDS_FOR_ACCOMPANIED_ALERT_BARK)
		{
			idStr enemyAiUse = enemy->spawnArgs.GetString("AIUse");
			if ( ( enemyAiUse == AIUSE_MONSTER ) || ( enemyAiUse == AIUSE_UNDEAD ) )
			{
				bark = "snd_to_combat_company_monster";
			}
			else
			{
				bark = "snd_to_combat_company";
			}
		}
		else
		{
			idStr enemyAiUse = enemy->spawnArgs.GetString("AIUse");
			if ( ( enemyAiUse == AIUSE_MONSTER ) || ( enemyAiUse == AIUSE_UNDEAD ) )
			{
				bark = "snd_to_combat_monster";
			}
			else
			{
				bark = "snd_to_combat";
			}
		}

		owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask(bark, message)));

		owner->GetMemory().lastTimeAlertBark = gameLocal.time; // grayman #3496

		if (cv_ai_debug_transition_barks.GetBool())
		{
			gameLocal.Printf("%d: %s starts combat, barks '%s'\n",gameLocal.time,owner->GetName(),bark.c_str());
		}

		_justDrewWeapon = false;
		_combatSubState = EStateCheckWeaponState;
		break;
		}

	case EStateCheckWeaponState:
		// check which combat type we should use
		{
		// Can you continue with your current combat type, and not have to switch weapons?

		// Check for case where melee combat has stalled. You're in the melee zone, but you're
		// unable to hit the enemy. Perhaps he's higher or lower than you and you can't reach him.

		if ( !owner->AI_FORWARD && // not moving
			 ( _combatType == COMBAT_MELEE ) && // in melee combat
			 _rangedPossible &&    // ranged combat is possible
			 !owner->TestMelee() ) // I can't hit the enemy
		{
			float        orgZ = owner->GetPhysics()->GetOrigin().z;
			float      height = owner->GetPhysics()->GetBounds().GetSize().z;
			float   enemyOrgZ = enemy->GetPhysics()->GetOrigin().z;
			float enemyHeight = enemy->GetPhysics()->GetBounds().GetSize().z;
			if ( ( (orgZ + height + owner->melee_range_vert) < enemyOrgZ ) || // enemy too high
							     ( (enemyOrgZ + enemyHeight) < orgZ ) ) // enemy too low
			{
				newCombatType = COMBAT_RANGED;
			}
		}

		if ( newCombatType == _combatType )
		{
			// yes - no need to run weapon-switching animations
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		// Do you need to switch a melee or ranged weapon? You might already have one
		// drawn, or you might have none drawn, or you might have to change weapons,
		// or you might be using unarmed attacks, and you don't need a drawn weapon.

		// Check for unarmed combat.

		if ( _unarmedMelee && ( newCombatType == COMBAT_MELEE ) )
		{
			// unarmed combat doesn't need attached weapons
			_combatType = COMBAT_NONE; // clear ranged combat tasks and start melee combat tasks
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		if ( _unarmedRanged && ( newCombatType == COMBAT_RANGED ) )
		{
			// unarmed combat doesn't need attached weapons
			_combatType = COMBAT_NONE; // clear melee combat tasks and start ranged combat tasks
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		// Do you have a drawn weapon?

		if ( owner->GetAttackFlag(COMBAT_MELEE) && ( newCombatType == COMBAT_MELEE ) )
		{
			// melee weapon is already drawn
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		if ( owner->GetAttackFlag(COMBAT_RANGED) && ( newCombatType == COMBAT_RANGED ) )
		{
			// ranged weapon is already drawn
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		// At this point, we know we need to draw a weapon that's not already drawn.
		// See if you need to sheathe a drawn weapon.

		if ( ( ( newCombatType == COMBAT_RANGED ) && owner->GetAttackFlag(COMBAT_MELEE)  ) ||
		     ( ( newCombatType == COMBAT_MELEE  ) && owner->GetAttackFlag(COMBAT_RANGED) ) )
		{
			// switch from one type of weapon to another
			owner->movementSubsystem->ClearTasks();
			owner->actionSubsystem->ClearTasks();
			_combatType = COMBAT_NONE;

			// sheathe current weapon so you can draw the other weapon
			owner->SheathWeapon();
			_waitEndTime = gameLocal.time + 2000; // safety net
			_combatSubState = EStateSheathingWeapon;
			return;
		}

		// No need to sheathe a weapon
		_combatSubState = EStateDrawWeapon;

		break;
		}

	case EStateSheathingWeapon:
		{
		// if you're sheathing a weapon, stay in this state until it's done, or until the timer expires
		// grayman #3355 - check wait state
		if ( ( gameLocal.time < _waitEndTime ) && ( idStr(owner->WaitState()) == "sheath") )
		{
			return;
		}

		_combatSubState = EStateDrawWeapon;

		break;
		}

	case EStateDrawWeapon:
		{
		// grayman #3331 - if you don't already have the correct weapon drawn,
		// draw a ranged weapon if you're far from the enemy, and you have a 
		// ranged weapon, otherwise draw your melee weapon

		bool drawingWeapon = false;

		if ( !inMeleeRange )
		{
			// beyond melee range
			if ( !owner->GetAttackFlag(COMBAT_RANGED) && _rangedPossible )
			{
				owner->DrawWeapon(COMBAT_RANGED);
				drawingWeapon = true;
			}
			else // no ranged weapon
			{
				owner->DrawWeapon(COMBAT_MELEE);
				drawingWeapon = true;
			}
		}
		else // in melee range
		{
			if ( _meleePossible && !owner->GetAttackFlag(COMBAT_MELEE) )
			{
				owner->DrawWeapon(COMBAT_MELEE);
				drawingWeapon = true;
			}
		}

		// grayman #3331 - if this is the first weapon draw, to make sure the weapon is drawn
		// before starting combat, delay some before starting to chase the enemy.
		// The farther away the enemy is, the better the chance that you'll start chasing before your
		// weapon is drawn. If he's close, this gives you time to completely draw your weapon before
		// engaging him. The interesting distance is how far you have to travel to get w/in melee range.

		if ( _needInitialDrawDelay ) // True if this is the first time through, and you don't already have a raised weapon
		{
			int delay = 0;

			if ( drawingWeapon )
			{
				delay = (int)(2064.0f - 20.0f*(dist2Enemy - owner->GetMeleeRange()));
				if ( delay < 0 )
				{
					delay = gameLocal.random.RandomInt(2064);
				}
				_waitEndTime = gameLocal.time + delay;
				_combatSubState = EStateDrawingWeapon;

				// grayman #3563 - safety net when drawing a weapon
				_drawEndTime = gameLocal.time + MAX_DRAW_DURATION;
			}
			else
			{
				_combatSubState = EStateCombatAndChecks;
			}
			_needInitialDrawDelay = false; // No need to do this again
		}
		else
		{
			if ( drawingWeapon )
			{
				_waitEndTime = gameLocal.time;
				_combatSubState = EStateDrawingWeapon;

				// grayman #3563 - safety net when drawing a weapon
				_drawEndTime = gameLocal.time + MAX_DRAW_DURATION;
			}
			else
			{
				_combatSubState = EStateCombatAndChecks;
			}
		}
		break;
		}

	case EStateDrawingWeapon:
		{
		// grayman #3355 - check wait state
		if ( idStr(owner->WaitState()) == "draw" )
		{
			if ( gameLocal.time < _drawEndTime ) // grayman #3563 - check safety net
			{
				return; // wait until weapon is drawn
			}
		}

		if ( gameLocal.time < _waitEndTime )
		{
			return; // wait until timer expires
		}

		// Weapon is now drawn

		_justDrewWeapon = true;
		_combatSubState = EStateCombatAndChecks;

		break;
		}

	case EStateCombatAndChecks:
		{
		// Need to check if a weapon that was just drawn is correct for the zone you're now in, in case
		// you started drawing the correct weapon for one zone, and while it was drawing, you switched
		// to the other zone.
		
		if ( _justDrewWeapon )
		{
			if ( newCombatType == COMBAT_RANGED )
			{
				// beyond melee range
				if ( !owner->GetAttackFlag(COMBAT_RANGED) && _rangedPossible )
				{
					// wrong weapon raised - go back and get the correct one
					_justDrewWeapon = false;
					_combatSubState = EStateCheckWeaponState;
					return;
				}
			}
			else // in melee combat
			{
				if ( !owner->GetAttackFlag(COMBAT_MELEE) && _meleePossible )
				{
					// wrong weapon raised - go back and get the correct one
					_justDrewWeapon = false;
					_combatSubState = EStateCheckWeaponState;
					return;
				}
			}
		}

		_justDrewWeapon = false;
		if ( _combatType == COMBAT_NONE ) // Either combat hasn't been initially set up, or you're switching weapons
		{
			if ( newCombatType == COMBAT_RANGED )
			{
				// Set up ranged combat
				owner->actionSubsystem->PushTask(RangedCombatTask::CreateInstance());
				owner->movementSubsystem->PushTask(ChaseEnemyRangedTask::CreateInstance());
				_combatType = COMBAT_RANGED;
			}
			else
			{
				// Set up melee combat
				ChaseEnemyTaskPtr chaseEnemy = ChaseEnemyTask::CreateInstance();
				chaseEnemy->SetEnemy(enemy);
				owner->movementSubsystem->PushTask(chaseEnemy);

				owner->actionSubsystem->PushTask(MeleeCombatTask::CreateInstance());
				_combatType = COMBAT_MELEE;
			}

			// Let the AI update their weapons (make them nonsolid)
			owner->UpdateAttachmentContents(false);
		}

		// Check the distance to the enemy, the subsystem tasks need it.
		memory.canHitEnemy = owner->CanHitEntity(enemy, _combatType);
		// grayman #3331 - willBeAbleToHitEnemy is only relevant if canHitEnemy is FALSE
		if ( owner->m_bMeleePredictProximity && !memory.canHitEnemy )
		{
			memory.willBeAbleToHitEnemy = owner->WillBeAbleToHitEntity(enemy, _combatType);
		}

		// Check whether the enemy can hit us in the near future
		memory.canBeHitByEnemy = owner->CanBeHitByEntity(enemy, _combatType);

		if ( !owner->AI_ENEMY_VISIBLE && 
			 ( ( ( _combatType == COMBAT_MELEE )  && !memory.canHitEnemy ) || ( _combatType == COMBAT_RANGED) ) )
		{
			// The enemy is not visible, let's keep track of him for a small amount of time
			if (gameLocal.time - memory.lastTimeEnemySeen < MAX_BLIND_CHASE_TIME)
			{
				// Cheat a bit and take the last reachable position as "visible & reachable"
				owner->lastVisibleReachableEnemyPos = owner->lastReachableEnemyPos;
			}
			else if (owner->ReachedPos(owner->lastVisibleReachableEnemyPos, MOVE_TO_POSITION) || 
					( ( gameLocal.time - memory.lastTimeEnemySeen ) > 2 * MAX_BLIND_CHASE_TIME) )
			{
				// BLIND_CHASE_TIME has expired, we have lost the enemy!
				owner->GetMind()->SwitchState(STATE_LOST_TRACK_OF_ENEMY);
				return;
			}
		}

		// Flee if you're damaged and the current melee action is finished
		if ( ( owner->health < _criticalHealth ) && ( owner->m_MeleeStatus.m_ActionState == MELEEACTION_READY ) )
		{
			DM_LOG(LC_AI, LT_INFO)LOGSTRING("I'm badly hurt, I'm afraid, and am fleeing!\r");
			owner->fleeingEvent = false; // grayman #3182
			owner->emitFleeBarks = true; // grayman #3474
			owner->GetMind()->SwitchState(STATE_FLEE);
			return;
		}

		_combatSubState = EStateCheckWeaponState;

		break;
		}

	default:
		break;
	}
}
Пример #10
0
/*
==============
sdSnowPrecipitation::Update
==============
*/
void sdSnowPrecipitation::Update( void ) {
    renderEntity_t *re = GetRenderEntity();
    if ( re->hModel == NULL ) {
        return;
    }

    idBounds modelbb = re->hModel->Bounds();
    idVec3 extents = (modelbb.GetMaxs() - modelbb.GetMins()) * 0.5f;

    idPlayer *p = gameLocal.GetLocalViewPlayer();
    idVec3 const &v = p->GetViewPos();

    for (int i=0; i<MAX_GROUPS; i++) {
        groups[i].time -= 1.f / 30.f;
        if ( groups[i].time < 0.f ) {
            groups[i].axis = idVec3( idRandom::StaticRandom().RandomFloat()- 0.15f , idRandom::StaticRandom().RandomFloat() - 0.5f , idRandom::StaticRandom().RandomFloat() - 0.5f );
            groups[i].axis.z *= 40.25f;
            groups[i].axis.Normalize();
            groups[i].rotate = 0.f;
            groups[i].rotateSpeed = idRandom::StaticRandom().RandomFloat() * 50.f + 50.f;
            groups[i].rotationPoint = idVec3( idRandom::StaticRandom().RandomFloat() * extents.x,
                                              idRandom::StaticRandom().RandomFloat() * extents.y,
                                              idRandom::StaticRandom().RandomFloat() * extents.z );

            groups[i].alpha = 0.f;
            groups[i].time = idRandom::StaticRandom().RandomFloat() * 1.f + 1.f;
            groups[i].worldPos = v + idVec3( (idRandom::StaticRandom().RandomFloat()-0.5f) * extents.x * 3,
                                             (idRandom::StaticRandom().RandomFloat()-0.5f) * extents.y * 3,
                                             (idRandom::StaticRandom().RandomFloat()-0.5f) * extents.z * 3 );
        } else {
            if ( groups[i].time > 0.25f ) {
                groups[i].alpha += 1.f / 7.5f;
                if ( groups[i].alpha > 1.f ) {
                    groups[i].alpha = 1.f;
                }
            } else {
                groups[i].alpha = groups[i].time * 4.f;
                if ( groups[i].alpha < 0.f ) {
                    groups[i].alpha = 0.f;
                }
            }
            groups[i].worldPos += idVec3( 0.f, 0.f, -600.f ) * 1.f / 30.f;
            groups[i].rotate += groups[i].rotateSpeed * 1.f / 30.f;
        }
    }


    int gridx = idMath::Ftoi( idMath::Floor(v.x / extents.x) );
    int gridy = idMath::Ftoi( idMath::Floor(v.y / extents.y) );

    idBounds bounds;
    bounds.Clear();
    sdInstInfo *inst = re->insts;
    for (int i=0; i<MAX_GROUPS; i++) {
        idRotation r( groups[i].rotationPoint, groups[i].axis, groups[i].rotate );

        idBounds bb2;
        inst->inst.color[0] = 0xff;
        inst->inst.color[1] = 0xff;
        inst->inst.color[2] = 0xff;
        inst->inst.color[3] = 0xff;
        inst->fadeOrigin = inst->inst.origin = groups[i].worldPos;
        inst->inst.axis = r.ToMat3();
        inst->maxVisDist = 0;
        inst->minVisDist = 0.f;
        bb2.FromTransformedBounds( modelbb, inst->inst.origin, inst->inst.axis );
        bounds.AddBounds( bb2 );
        inst++;
    }
    re->flags.overridenBounds = true;
    re->bounds = bounds;

    if ( renderEntityHandle == -1 ) {
        renderEntityHandle = gameRenderWorld->AddEntityDef( re );
    } else {
        gameRenderWorld->UpdateEntityDef( renderEntityHandle, re );
    }

    if ( !effect.GetRenderEffect().declEffect ) return;

    idVec3 viewOrg;
    renderView_t view;
    if ( sdDemoManager::GetInstance().CalculateRenderView( &view ) ) {
        viewOrg = view.vieworg;
    } else {
        // If we are inside don't run the bacground effect
        idPlayer* player = gameLocal.GetLocalViewPlayer();

        if ( player == NULL ) {
            return;
        }
        viewOrg = player->GetRenderView()->vieworg;
    }

    int area = gameRenderWorld->PointInArea( viewOrg );
    bool runEffect = false;
    if ( area >= 0 ) {
        if ( gameRenderWorld->GetAreaPortalFlags( area ) & ( 1 << PORTAL_OUTSIDE ) ) {
            runEffect = true && !g_skipLocalizedPrecipitation.GetBool();
        }
    }

    // Update the background effect
    if ( runEffect ) {
        effect.GetRenderEffect().origin = viewOrg;
        if ( !effectRunning ) {
            effect.Start( gameLocal.time );
            effectRunning = true;
        } else {
            effect.Update();
        }
    } else {
        effect.StopDetach();
        effectRunning = false;
    }
}
Пример #11
0
/*
==============
sdSnowEffect::Think
==============
*/
void		sdSnowEffect::Think( void ) {
    renderEntity_t *re = GetRenderEntity();
    if ( re->hModel == NULL ) {
        return;
    }

    idBounds modelbb = re->hModel->Bounds();
    idVec3 extents = (modelbb.GetMaxs() - modelbb.GetMins()) * 0.5f;

    idPlayer *p = gameLocal.GetLocalViewPlayer();
    idVec3 const &v = p->GetViewPos();

    for (int i=0; i<MAX_GROUPS; i++) {
        groups[i].time -= 1.f / 30.f;
        if ( groups[i].time < 0.f ) {
            groups[i].axis = idVec3( idRandom::StaticRandom().RandomFloat()- 0.15f , idRandom::StaticRandom().RandomFloat() - 0.5f , idRandom::StaticRandom().RandomFloat() - 0.5f );
            groups[i].axis.z *= 40.25f;
            groups[i].axis.Normalize();
            groups[i].rotate = 0.f;
            groups[i].rotateSpeed = idRandom::StaticRandom().RandomFloat() * 50.f + 50.f;
            groups[i].rotationPoint = idVec3( idRandom::StaticRandom().RandomFloat() * extents.x,
                                              idRandom::StaticRandom().RandomFloat() * extents.y,
                                              idRandom::StaticRandom().RandomFloat() * extents.z );

            groups[i].alpha = 0.f;
            groups[i].time = idRandom::StaticRandom().RandomFloat() * 1.f + 1.f;
            groups[i].worldPos = v + idVec3( (idRandom::StaticRandom().RandomFloat()-0.5f) * extents.x * 3,
                                             (idRandom::StaticRandom().RandomFloat()-0.5f) * extents.y * 3,
                                             (idRandom::StaticRandom().RandomFloat()-0.5f) * extents.z * 3 );
        } else {
            if ( groups[i].time > 0.25f ) {
                groups[i].alpha += 1.f / 7.5f;
                if ( groups[i].alpha > 1.f ) {
                    groups[i].alpha = 1.f;
                }
            } else {
                groups[i].alpha = groups[i].time * 4.f;
                if ( groups[i].alpha < 0.f ) {
                    groups[i].alpha = 0.f;
                }
            }
            groups[i].worldPos += idVec3( 0.f, 0.f, -600.f ) * 1.f / 30.f;
            groups[i].rotate += groups[i].rotateSpeed * 1.f / 30.f;
        }
    }


    int gridx = idMath::Ftoi( idMath::Floor(v.x / extents.x) );
    int gridy = idMath::Ftoi( idMath::Floor(v.y / extents.y) );

    idBounds bounds;
    bounds.Clear();
    sdInstInfo *inst = re->insts;
    for (int i=0; i<MAX_GROUPS; i++) {
        idRotation r( groups[i].rotationPoint, groups[i].axis, groups[i].rotate );

        idBounds bb2;
        inst->inst.color[0] = 0xff;
        inst->inst.color[1] = 0xff;
        inst->inst.color[2] = 0xff;
        inst->inst.color[3] = 0xff;
        inst->fadeOrigin = inst->inst.origin = groups[i].worldPos;
        inst->inst.axis = r.ToMat3();
        inst->maxVisDist = 0;
        inst->minVisDist = 0.f;
        bb2.FromTransformedBounds( modelbb, inst->inst.origin, inst->inst.axis );
        bounds.AddBounds( bb2 );
        inst++;
    }
    re->flags.overridenBounds = true;
    re->bounds = bounds;

    UpdateVisuals();
    Present();
}
Пример #12
0
bool sdTransportPositionManager::EjectPlayer( sdVehiclePosition& position, bool force ) {
	idPlayer* player = position.GetPlayer();
	if ( !player ) {
		return true;
	}

	//
	// Find a position to eject to
	//
	bool foundOrg = false;
	idVec3 selectedOrg = player->GetPhysics()->GetOrigin();
	idMat3 selectedAxes = player->GetPhysics()->GetAxis();

	if ( transport->UnbindOnEject() ) {
		if( !gameLocal.isClient ) {
			player->DisableClip( false );

			sdTeleporter* teleportEnt = transport->GetTeleportEntity();
			if ( teleportEnt != NULL ) {
				teleportEnt->GetTeleportEndPoint( transport, selectedOrg, selectedAxes );
				selectedOrg.z += 64.f;
				foundOrg = true;
			} else {
				// prioritize exit joints by the nearest 
				idStaticList< sdExitJointDistanceInfo, MAX_EXIT_JOINTS > sortedExitJoints;
				sortedExitJoints.SetNum( exitJoints.Num() );
				idVec3 traceFromPoint;
				transport->GetWorldOrigin( position.GetAttachJoint(), traceFromPoint );
				for( int i = 0; i < exitJoints.Num(); i++ ) {
					sortedExitJoints[ i ].joint = exitJoints[ i ];
					transport->GetWorldOriginAxis( exitJoints[ i ], sortedExitJoints[ i ].origin, sortedExitJoints[ i ].axis );
					sortedExitJoints[ i ].distanceSqr = ( traceFromPoint - sortedExitJoints[ i ].origin ).LengthSqr();
				}

				sortedExitJoints.Sort( sdExitJointDistanceInfo::SortByDistance );

				// choose a point to do the cast-to-exit-point from - if we just use the origin it could
				// potentially be in all sorts of wacky positions depending how the vehicle is built
				// this enures the the point casted from is inside the vehicle
				traceFromPoint = transport->GetPhysics()->GetAxis().TransposeMultiply( traceFromPoint - transport->GetPhysics()->GetOrigin() );
				const idBounds& transportBounds = transport->GetPhysics()->GetBounds();
				traceFromPoint.z = ( transportBounds[ 0 ].z + transportBounds[ 1 ].z ) * 0.5f;
				traceFromPoint = traceFromPoint * transport->GetPhysics()->GetAxis() + transport->GetPhysics()->GetOrigin();

				// default position to get out is inside the vehicle
				selectedOrg = traceFromPoint;
				selectedAxes;

				const idClipModel* playerClip = player->GetPlayerPhysics().GetNormalClipModel();

				for ( int i = 0; i < sortedExitJoints.Num(); i++ ) {
					idVec3 org = sortedExitJoints[ i ].origin;
					idMat3 axes = sortedExitJoints[ i ].axis;

					if ( gameRenderWorld->PointInArea( org ) == -1 ) {
						// outside the map, so no go
						continue;
					}

					// check that the point is clear
					int contents = gameLocal.clip.Contents( CLIP_DEBUG_PARMS org, playerClip, mat3_identity, MASK_PLAYERSOLID, NULL );
					if( !contents ) {
						// check that theres nothing in between the vehicle and the exit point
						trace_t trace;
						if( !gameLocal.clip.TracePoint( CLIP_DEBUG_PARMS trace, traceFromPoint, org, MASK_PLAYERSOLID, transport ) ) {
							selectedOrg = org;
							selectedAxes = axes;
							foundOrg = true;
							break;
						}
					}
				}

				if( !foundOrg ) {
					// Search all 8 positions around every exit joint, should find at least one.
					for ( int i = 0; i < sortedExitJoints.Num(); i++ ) {
						idVec3 orgBase = sortedExitJoints[ i ].origin;
						idMat3 axes = sortedExitJoints[ i ].axis;
						const int size = playerClip->GetBounds().GetSize().x;
						const int spacing = 8;

						for ( int j = -1; j < 2 && !foundOrg; j++ ) {
							for ( int k = -1; k < 2 && !foundOrg; k++ ) {
								if ( j == 0 && k == 0 ) {
									continue;
								}

								idVec3 org = orgBase + idVec3( j * size + j * spacing, k * size + k * spacing, 0.0f );

								if ( gameRenderWorld->PointInArea( org ) == -1 ) {
									// outside the map, so no go
									continue;
								}

								// check that the point is clear
								int contents = gameLocal.clip.Contents( CLIP_DEBUG_PARMS org, playerClip, mat3_identity, MASK_PLAYERSOLID, NULL );
								if( !contents ) {
									// check that theres nothing in between the vehicle and the exit point
									trace_t trace;
									if( !gameLocal.clip.TracePoint( CLIP_DEBUG_PARMS trace, traceFromPoint, org, MASK_PLAYERSOLID, transport ) ) {
										selectedOrg = org;
										selectedAxes = axes;
										foundOrg = true;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ( !gameLocal.isClient ) {
		if ( !foundOrg ) {
			if ( !force ) {
				return false;
			} else {
				gameLocal.Warning( "sdTransportPositionManager::EjectPlayer No Valid Eject Position Found" );
			}
		}
	}



	//
	// Actually eject
	//

	player->SetSuppressPredictionReset( true );
	RemovePlayer( position );

	if ( transport->UnbindOnEject() ) {
		// copy the velocity over
		idVec3 v = transport->GetPhysics()->GetLinearVelocity();
		for ( int i = 0; i < 3; i++ ) {
			if ( FLOAT_IS_NAN( v[ i ] ) ) {
				v[ i ] = 0.f;
			}
		}
		v.FixDenormals();

		player->GetPhysics()->SetLinearVelocity( v );

		// set the position
		if ( foundOrg ) {
			idAngles temp;
			temp = selectedAxes.ToAngles();
			temp.roll = 0.0f;
			if ( temp.pitch < -10.0f ) {
				temp.pitch = -10.0f;
			}
			player->SetViewAngles( temp );
			player->SetOrigin( selectedOrg );
		}
		player->EnableClip();
	}


	player->SetProxyEntity( NULL, 0 );
	// this forces the reset message to be re-sent
	player->SetSuppressPredictionReset( false );
	player->ResetPredictionErrorDecay();

	return true;
}
Пример #13
0
/*
===============
idRenderModelSprite::InstantiateDynamicModel
===============
*/
idRenderModel 	*idRenderModelSprite::InstantiateDynamicModel(const struct renderEntity_s *renderEntity, const struct viewDef_s *viewDef, idRenderModel *cachedModel)
{
	idRenderModelStatic *staticModel;
	srfTriangles_t *tri;
	modelSurface_t surf;

	if (cachedModel && !r_useCachedDynamicModels.GetBool()) {
		delete cachedModel;
		cachedModel = NULL;
	}

	if (renderEntity == NULL || viewDef == NULL) {
		delete cachedModel;
		return NULL;
	}

	if (cachedModel != NULL) {

		assert(dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL);
		assert(idStr::Icmp(cachedModel->Name(), sprite_SnapshotName) == 0);

		staticModel = static_cast<idRenderModelStatic *>(cachedModel);
		surf = *staticModel->Surface(0);
		tri = surf.geometry;

	} else {

		staticModel = new idRenderModelStatic;
		staticModel->InitEmpty(sprite_SnapshotName);

		tri = R_AllocStaticTriSurf();
		R_AllocStaticTriSurfVerts(tri, 4);
		R_AllocStaticTriSurfIndexes(tri, 6);

		tri->verts[ 0 ].Clear();
		tri->verts[ 0 ].normal.Set(1.0f, 0.0f, 0.0f);
		tri->verts[ 0 ].tangents[0].Set(0.0f, 1.0f, 0.0f);
		tri->verts[ 0 ].tangents[1].Set(0.0f, 0.0f, 1.0f);
		tri->verts[ 0 ].st[ 0 ] = 0.0f;
		tri->verts[ 0 ].st[ 1 ] = 0.0f;

		tri->verts[ 1 ].Clear();
		tri->verts[ 1 ].normal.Set(1.0f, 0.0f, 0.0f);
		tri->verts[ 1 ].tangents[0].Set(0.0f, 1.0f, 0.0f);
		tri->verts[ 1 ].tangents[1].Set(0.0f, 0.0f, 1.0f);
		tri->verts[ 1 ].st[ 0 ] = 1.0f;
		tri->verts[ 1 ].st[ 1 ] = 0.0f;

		tri->verts[ 2 ].Clear();
		tri->verts[ 2 ].normal.Set(1.0f, 0.0f, 0.0f);
		tri->verts[ 2 ].tangents[0].Set(0.0f, 1.0f, 0.0f);
		tri->verts[ 2 ].tangents[1].Set(0.0f, 0.0f, 1.0f);
		tri->verts[ 2 ].st[ 0 ] = 1.0f;
		tri->verts[ 2 ].st[ 1 ] = 1.0f;

		tri->verts[ 3 ].Clear();
		tri->verts[ 3 ].normal.Set(1.0f, 0.0f, 0.0f);
		tri->verts[ 3 ].tangents[0].Set(0.0f, 1.0f, 0.0f);
		tri->verts[ 3 ].tangents[1].Set(0.0f, 0.0f, 1.0f);
		tri->verts[ 3 ].st[ 0 ] = 0.0f;
		tri->verts[ 3 ].st[ 1 ] = 1.0f;

		tri->indexes[ 0 ] = 0;
		tri->indexes[ 1 ] = 1;
		tri->indexes[ 2 ] = 3;
		tri->indexes[ 3 ] = 1;
		tri->indexes[ 4 ] = 2;
		tri->indexes[ 5 ] = 3;

		tri->numVerts = 4;
		tri->numIndexes = 6;

		surf.geometry = tri;
		surf.id = 0;
		surf.shader = tr.defaultMaterial;
		staticModel->AddSurface(surf);
	}

	int	red			= idMath::FtoiFast(renderEntity->shaderParms[ SHADERPARM_RED ] * 255.0f);
	int green		= idMath::FtoiFast(renderEntity->shaderParms[ SHADERPARM_GREEN ] * 255.0f);
	int	blue		= idMath::FtoiFast(renderEntity->shaderParms[ SHADERPARM_BLUE ] * 255.0f);
	int	alpha		= idMath::FtoiFast(renderEntity->shaderParms[ SHADERPARM_ALPHA ] * 255.0f);

	idVec3 right	= idVec3(0.0f, renderEntity->shaderParms[ SHADERPARM_SPRITE_WIDTH ] * 0.5f, 0.0f);
	idVec3 up		= idVec3(0.0f, 0.0f, renderEntity->shaderParms[ SHADERPARM_SPRITE_HEIGHT ] * 0.5f);

	tri->verts[ 0 ].xyz = up + right;
	tri->verts[ 0 ].color[ 0 ] = red;
	tri->verts[ 0 ].color[ 1 ] = green;
	tri->verts[ 0 ].color[ 2 ] = blue;
	tri->verts[ 0 ].color[ 3 ] = alpha;

	tri->verts[ 1 ].xyz = up - right;
	tri->verts[ 1 ].color[ 0 ] = red;
	tri->verts[ 1 ].color[ 1 ] = green;
	tri->verts[ 1 ].color[ 2 ] = blue;
	tri->verts[ 1 ].color[ 3 ] = alpha;

	tri->verts[ 2 ].xyz = - right - up;
	tri->verts[ 2 ].color[ 0 ] = red;
	tri->verts[ 2 ].color[ 1 ] = green;
	tri->verts[ 2 ].color[ 2 ] = blue;
	tri->verts[ 2 ].color[ 3 ] = alpha;

	tri->verts[ 3 ].xyz = right - up;
	tri->verts[ 3 ].color[ 0 ] = red;
	tri->verts[ 3 ].color[ 1 ] = green;
	tri->verts[ 3 ].color[ 2 ] = blue;
	tri->verts[ 3 ].color[ 3 ] = alpha;

	R_BoundTriSurf(tri);

	staticModel->bounds = tri->bounds;

	return staticModel;
}
Пример #14
0
/*
========================
idSoundWorldLocal::Update
========================
*/
void idSoundWorldLocal::Update() {

	if ( s_noSound.GetBool() ) { 
		return;
	}

	// ------------------
	// Update emitters
	//
	// Only loop through the list once to avoid extra cache misses
	// ------------------

	// The naming convention is weird here because we reuse the name "channel"
	// An idSoundChannel is a channel on an emitter, which may have an explicit channel assignment or SND_CHANNEL_ANY
	// A hardware channel is a channel from the sound file itself (IE: left, right, LFE)
	// We only allow MAX_HARDWARE_CHANNELS channels, which may wind up being a smaller number of idSoundChannels
	idStaticList< idActiveChannel, MAX_HARDWARE_VOICES > activeEmitterChannels;
	int	maxEmitterChannels = s_maxEmitterChannels.GetInteger() + 1;	// +1 to leave room for insert-before-sort
	if ( maxEmitterChannels > MAX_HARDWARE_VOICES ) {
		maxEmitterChannels = MAX_HARDWARE_VOICES;
	}

	int activeHardwareChannels = 0;
	int	totalHardwareChannels = 0;
	int	totalEmitterChannels = 0;

	int currentTime = GetSoundTime();
	for ( int e = emitters.Num() - 1; e >= 0; e-- ) {
		// check for freeing a one-shot emitter that is finished playing
		if ( emitters[e]->CheckForCompletion( currentTime ) ) {
			// do a fast list collapse by swapping the last element into
			// the slot we are deleting
			emitters[e]->Reset();
			emitterAllocator.Free( emitters[e] );
			int lastEmitter = emitters.Num() - 1;
			if ( e != lastEmitter ) {
				emitters[e] = emitters[lastEmitter];
				emitters[e]->index = e;
			}
			emitters.SetNum( lastEmitter );
			continue;
		}

		emitters[e]->Update( currentTime );

		totalEmitterChannels += emitters[e]->channels.Num();

		// sort the active channels into the hardware list
		for ( int i = 0; i < emitters[e]->channels.Num(); i++ ) {
			idSoundChannel * channel = emitters[e]->channels[i];

			// check if this channel contributes at all
			const bool canMute = channel->CanMute();
			if ( canMute && channel->volumeDB <= DB_SILENCE ) {
				channel->Mute();
				continue;
			}

			// Calculate the sort key.
			// VO can't be stopped and restarted accurately, so always keep VO channels by adding a large value to the sort key.
			const int sortKey = idMath::Ftoi( channel->volumeDB * 100.0f + ( canMute ? 0.0f : 100000.0f ) );

			// Keep track of the total number of hardware channels.
			// This is done after calculating the sort key to avoid a load-hit-store that
			// would occur when using the sort key in the loop below after the Ftoi above.
			const int sampleChannels = channel->leadinSample->NumChannels();
			totalHardwareChannels += sampleChannels;

			// Find the location to insert this channel based on the sort key.
			int insertIndex = 0;
			for ( insertIndex = 0; insertIndex < activeEmitterChannels.Num(); insertIndex++ ) {
				if ( sortKey > activeEmitterChannels[insertIndex].sortKey ) {
					break;
				}
			}

			// Only insert at the end if there is room.
			if ( insertIndex == activeEmitterChannels.Num() ) {
				// Always leave one spot free in the 'activeEmitterChannels' so there is room to insert sort a potentially louder sound later.
				if ( activeEmitterChannels.Num() + 1 >= activeEmitterChannels.Max() || activeHardwareChannels + sampleChannels > MAX_HARDWARE_CHANNELS ) {
					// We don't have enough voices to play this, so mute it if it was playing.
					channel->Mute();
					continue;
				}
			}

			// We want to insert the sound at this point.
			activeEmitterChannels.Insert( idActiveChannel( channel, sortKey ), insertIndex );
			activeHardwareChannels += sampleChannels;

			// If we are over our voice limit or at our channel limit, mute sounds until it fits.
			// If activeEmitterChannels is full, always remove the last one so there is room to insert sort a potentially louder sound later.
			while ( activeEmitterChannels.Num() == maxEmitterChannels || activeHardwareChannels > MAX_HARDWARE_CHANNELS ) {
				const int indexToRemove = activeEmitterChannels.Num() - 1;
				idSoundChannel * const channelToMute = activeEmitterChannels[ indexToRemove ].channel;
				channelToMute->Mute();
				activeHardwareChannels -= channelToMute->leadinSample->NumChannels();
				activeEmitterChannels.RemoveIndex( indexToRemove );
			}
		}
	}

	const float secondsPerFrame = 1.0f / com_engineHz_latched;

	// ------------------
	// In the very common case of having more sounds that would contribute to the
	// mix than there are available hardware voices, it can be an audible discontinuity
	// when a channel initially gets a voice or loses a voice.
	// To avoid this, make sure that the last few hardware voices are mixed with a volume
	// of zero, so they won't make a difference as they come and go.
	// It isn't obvious what the exact best volume ramping method should be, just that
	// it smoothly change frame to frame.
	// ------------------
	const int uncushionedChannels = maxEmitterChannels - s_cushionFadeChannels.GetInteger();
	currentCushionDB = AdjustForCushionChannels( activeEmitterChannels, uncushionedChannels, 
		currentCushionDB, s_cushionFadeRate.GetFloat() * secondsPerFrame );

	// ------------------
	// Update Hardware
	// ------------------
	shakeAmp = 0.0f;

	idStr showVoiceTable;
	bool showVoices = s_showVoices.GetBool();
	if ( showVoices ) {
		showVoiceTable.Format( "currentCushionDB: %5.1f  freeVoices: %i zombieVoices: %i buffers:%i/%i\n", currentCushionDB, 
			soundSystemLocal.hardware.GetNumFreeVoices(), soundSystemLocal.hardware.GetNumZombieVoices(),
			soundSystemLocal.activeStreamBufferContexts.Num(), soundSystemLocal.freeStreamBufferContexts.Num() );
	}
	for ( int i = 0; i < activeEmitterChannels.Num(); i++ ) {
		idSoundChannel * chan = activeEmitterChannels[i].channel;
		chan->UpdateHardware( 0.0f, currentTime );

		if ( showVoices ) {
			idStr voiceLine;
			voiceLine.Format( "%5.1f db [%3i:%2i] %s", chan->volumeDB, chan->emitter->index, chan->logicalChannel, chan->CanMute() ? "" : " <CANT MUTE>\n" );
			idSoundSample * leadinSample = chan->leadinSample;
			idSoundSample * loopingSample = chan->loopingSample;
			if ( loopingSample == NULL ) {
				voiceLine.Append( va( "%ikhz*%i %s\n", leadinSample->SampleRate()/1000, leadinSample->NumChannels(), leadinSample->GetName() ) );
			} else if ( loopingSample == leadinSample ) {
				voiceLine.Append( va( "%ikhz*%i <LOOPING> %s\n", leadinSample->SampleRate()/1000, leadinSample->NumChannels(), leadinSample->GetName() ) );
			} else {
				voiceLine.Append( va( "%ikhz*%i %s | %ikhz*%i %s\n", leadinSample->SampleRate()/1000, leadinSample->NumChannels(), leadinSample->GetName(), loopingSample->SampleRate()/1000, loopingSample->NumChannels(), loopingSample->GetName() ) );
			}
			showVoiceTable += voiceLine;
		}

		// Calculate shakes
		if ( chan->hardwareVoice == NULL ) {
			continue;
		}

		shakeAmp += chan->parms.shakes * chan->hardwareVoice->GetGain() * chan->currentAmplitude;
	}
	if ( showVoices ) {
		static idOverlayHandle handle;
		console->PrintOverlay( handle, JUSTIFY_LEFT, showVoiceTable.c_str() );
	}

	if ( s_drawSounds.GetBool() && renderWorld != NULL ) {
		for ( int e = 0; e < emitters.Num(); e++ ) {
			idSoundEmitterLocal * emitter = emitters[e];
			bool audible = false;
			float maxGain = 0.0f;
			for ( int c = 0; c < emitter->channels.Num(); c++ ) {
				if ( emitter->channels[c]->hardwareVoice != NULL ) {
					audible = true;
					maxGain = Max( maxGain, emitter->channels[c]->hardwareVoice->GetGain() );
				}
			}
			if ( !audible ) {
				continue;
			}

			static const int lifetime = 20;

			idBounds ref;
			ref.Clear();
			ref.AddPoint( idVec3( -10.0f ) );
			ref.AddPoint( idVec3(  10.0f ) );

			// draw a box
			renderWorld->DebugBounds( idVec4( maxGain, maxGain, 1.0f, 1.0f ), ref, emitter->origin, lifetime );
			if ( emitter->origin != emitter->spatializedOrigin ) {
				renderWorld->DebugLine( idVec4( 1.0f, 0.0f, 0.0f, 1.0f ), emitter->origin, emitter->spatializedOrigin, lifetime );
			}

			// draw the index
			idVec3 textPos = emitter->origin;
			textPos.z -= 8;
			renderWorld->DrawText( va("%i", e), textPos, 0.1f, idVec4(1,0,0,1), listener.axis, 1, lifetime );
			textPos.z += 8;

			// run through all the channels
			for ( int k = 0; k < emitter->channels.Num(); k++ ) {
				idSoundChannel * chan = emitter->channels[k];
				float	min = chan->parms.minDistance;
				float	max = chan->parms.maxDistance;
				const char * defaulted = chan->leadinSample->IsDefault() ? " *DEFAULTED*" : "";
				idStr text;
				text.Format( "%s (%i %i/%i)%s", chan->soundShader->GetName(), idMath::Ftoi( emitter->spatializedDistance ), idMath::Ftoi( min ), idMath::Ftoi( max ), defaulted );
				renderWorld->DrawText( text, textPos, 0.1f, idVec4(1,0,0,1), listener.axis, 1, lifetime );
				textPos.z += 8;
			}
		}
	}
}
Пример #15
0
/*
================
idAF::AddBindConstraints
================
*/
void idAF::AddBindConstraints( void ) {
	const idKeyValue *kv;
	idStr name;
	idAFBody *body;
	idLexer lexer;
	idToken type, bodyName, jointName;
	idVec3 origin, renderOrigin;
	idMat3 axis, renderAxis;

	if ( !IsLoaded() ) {
		return;
	}

	const idDict &args = self->spawnArgs;

	// get the render position
	origin = physicsObj.GetOrigin( 0 );
	axis = physicsObj.GetAxis( 0 );
	renderAxis = baseAxis.Transpose() * axis;
	renderOrigin = origin - baseOrigin * renderAxis;

	// parse all the bind constraints
	for ( kv = args.MatchPrefix( "bindConstraint ", NULL ); kv; kv = args.MatchPrefix( "bindConstraint ", kv ) ) {
		name = kv->GetKey();
		name.Strip( "bindConstraint " );

		lexer.LoadMemory( kv->GetValue(), kv->GetValue().Length(), kv->GetKey() );
		lexer.ReadToken( &type );

		lexer.ReadToken( &bodyName );
		body = physicsObj.GetBody( bodyName );
		if ( !body ) {
			gameLocal.Warning( "idAF::AddBindConstraints: body '%s' not found on entity '%s'", bodyName.c_str(), self->name.c_str() );
			lexer.FreeSource();
			continue;
		}

		if ( type.Icmp( "fixed" ) == 0 ) {
			idAFConstraint_Fixed *c;

			c = new idAFConstraint_Fixed( name, body, NULL );
			physicsObj.AddConstraint( c );
		}
		else if ( type.Icmp( "ballAndSocket" ) == 0 ) {
			idAFConstraint_BallAndSocketJoint *c;

			c = new idAFConstraint_BallAndSocketJoint( name, body, NULL );
			physicsObj.AddConstraint( c );
			lexer.ReadToken( &jointName );

			jointHandle_t joint = animator->GetJointHandle( jointName );
			if ( joint == INVALID_JOINT ) {
				gameLocal.Warning( "idAF::AddBindConstraints: joint '%s' not found", jointName.c_str() );
			}

			animator->GetJointTransform( joint, gameLocal.time, origin, axis );
			c->SetAnchor( renderOrigin + origin * renderAxis );
		}
		else if ( type.Icmp( "universal" ) == 0 ) {
			idAFConstraint_UniversalJoint *c;

			c = new idAFConstraint_UniversalJoint( name, body, NULL );
			physicsObj.AddConstraint( c );
			lexer.ReadToken( &jointName );

			jointHandle_t joint = animator->GetJointHandle( jointName );
			if ( joint == INVALID_JOINT ) {
				gameLocal.Warning( "idAF::AddBindConstraints: joint '%s' not found", jointName.c_str() );
			}
			animator->GetJointTransform( joint, gameLocal.time, origin, axis );
			c->SetAnchor( renderOrigin + origin * renderAxis );
			c->SetShafts( idVec3( 0, 0, 1 ), idVec3( 0, 0, -1 ) );
		}
		else {
			gameLocal.Warning( "idAF::AddBindConstraints: unknown constraint type '%s' on entity '%s'", type.c_str(), self->name.c_str() );
		}

		lexer.FreeSource();
	}

	hasBindConstraints = true;
}
Пример #16
0
/*
=================
idMapBrush::ParseQ3
=================
*/
idMapBrush *idMapBrush::ParseQ3( idLexer &src, const idVec3 &origin ) {
	int i, shift[2], rotate;
	float scale[2];
	idVec3 planepts[3];
	idToken token;
	idList<idMapBrushSide*> sides;
	idMapBrushSide	*side;
	idDict epairs;

	do {
		if ( src.CheckTokenString( "}" ) ) {
			break;
		}

		side = new idMapBrushSide();
		sides.Append( side );

		// read the three point plane definition
		if (!src.Parse1DMatrix( 3, planepts[0].ToFloatPtr() ) ||
			!src.Parse1DMatrix( 3, planepts[1].ToFloatPtr() ) ||
			!src.Parse1DMatrix( 3, planepts[2].ToFloatPtr() ) ) {
			src.Error( "idMapBrush::ParseQ3: unable to read brush side plane definition" );
			sides.DeleteContents( true );
			return NULL;
		}

		planepts[0] -= origin;
		planepts[1] -= origin;
		planepts[2] -= origin;

		side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );

		// read the material
		if ( !src.ReadTokenOnLine( &token ) ) {
			src.Error( "idMapBrush::ParseQ3: unable to read brush side material" );
			sides.DeleteContents( true );
			return NULL;
		}

		// we have an implicit 'textures/' in the old format
		side->material = "textures/" + token;

		// read the texture shift, rotate and scale
		shift[0] = src.ParseInt();
		shift[1] = src.ParseInt();
		rotate = src.ParseInt();
		scale[0] = src.ParseFloat();
		scale[1] = src.ParseFloat();
		side->texMat[0] = idVec3( 0.03125f, 0.0f, 0.0f );
		side->texMat[1] = idVec3( 0.0f, 0.03125f, 0.0f );
		side->origin = origin;
		
		// Q2 allowed override of default flags and values, but we don't any more
		if ( src.ReadTokenOnLine( &token ) ) {
			if ( src.ReadTokenOnLine( &token ) ) {
				if ( src.ReadTokenOnLine( &token ) ) {
				}
			}
		}
	} while( 1 );

	idMapBrush *brush = new idMapBrush();
	for ( i = 0; i < sides.Num(); i++ ) {
		brush->AddSide( sides[i] );
	}

	brush->epairs = epairs;

	return brush;
}
Пример #17
0
/*
============
idBox::FromPoints

  Tight box for a collection of points.
============
*/
void idBox::FromPoints( const idVec3 *points, const int numPoints ) {
	int i;
	float invNumPoints, sumXX, sumXY, sumXZ, sumYY, sumYZ, sumZZ;
	idVec3 dir;
	idBounds bounds;
	idMatX eigenVectors;
	idVecX eigenValues;

	// compute mean of points
	center = points[0];
	for ( i = 1; i < numPoints; i++ ) {
		center += points[i];
	}
	invNumPoints = 1.0f / numPoints;
	center *= invNumPoints;

	// compute covariances of points
	sumXX = 0.0f; sumXY = 0.0f; sumXZ = 0.0f;
	sumYY = 0.0f; sumYZ = 0.0f; sumZZ = 0.0f;
	for ( i = 0; i < numPoints; i++ ) {
		dir = points[i] - center;
		sumXX += dir.x * dir.x;
		sumXY += dir.x * dir.y;
		sumXZ += dir.x * dir.z;
		sumYY += dir.y * dir.y;
		sumYZ += dir.y * dir.z;
		sumZZ += dir.z * dir.z;
	}
	sumXX *= invNumPoints;
	sumXY *= invNumPoints;
	sumXZ *= invNumPoints;
	sumYY *= invNumPoints;
	sumYZ *= invNumPoints;
	sumZZ *= invNumPoints;

	// compute eigenvectors for covariance matrix
	eigenValues.SetData( 3, VECX_ALLOCA( 3 ) );
	eigenVectors.SetData( 3, 3, MATX_ALLOCA( 3 * 3 ) );

	eigenVectors[0][0] = sumXX;
	eigenVectors[0][1] = sumXY;
	eigenVectors[0][2] = sumXZ;
	eigenVectors[1][0] = sumXY;
	eigenVectors[1][1] = sumYY;
	eigenVectors[1][2] = sumYZ;
	eigenVectors[2][0] = sumXZ;
	eigenVectors[2][1] = sumYZ;
	eigenVectors[2][2] = sumZZ;
	eigenVectors.Eigen_SolveSymmetric( eigenValues );
	eigenVectors.Eigen_SortIncreasing( eigenValues );

	axis[0][0] = eigenVectors[0][0];
	axis[0][1] = eigenVectors[0][1];
	axis[0][2] = eigenVectors[0][2];
	axis[1][0] = eigenVectors[1][0];
	axis[1][1] = eigenVectors[1][1];
	axis[1][2] = eigenVectors[1][2];
	axis[2][0] = eigenVectors[2][0];
	axis[2][1] = eigenVectors[2][1];
	axis[2][2] = eigenVectors[2][2];

	extents[0] = eigenValues[0];
	extents[1] = eigenValues[0];
	extents[2] = eigenValues[0];

	// refine by calculating the bounds of the points projected onto the axis and adjusting the center and extents
	bounds.Clear();
    for ( i = 0; i < numPoints; i++ ) {
		bounds.AddPoint( idVec3( points[i] * axis[0], points[i] * axis[1], points[i] * axis[2] ) );
    }
	center = ( bounds[0] + bounds[1] ) * 0.5f;
	extents = bounds[1] - center;
	center *= axis;
}
Пример #18
0
/*
=============
idEditEntities::DisplayEntities
=============
*/
void idEditEntities::DisplayEntities( void ) {
	idEntity *ent;

	if ( !gameLocal.GetLocalPlayer() ) {
		return;
	}

	selectableEntityClasses.Clear();
	selectedTypeInfo_t sit;

	switch( g_editEntityMode.GetInteger() ) {
		case 1:
			sit.typeInfo = &idLight::Type;
			sit.textKey = "texture";
			selectableEntityClasses.Append( sit );
			break;
		case 2:
			sit.typeInfo = &idSound::Type;
			sit.textKey = "s_shader";
			selectableEntityClasses.Append( sit );
			sit.typeInfo = &idLight::Type;
			sit.textKey = "texture";
			selectableEntityClasses.Append( sit );
			break;
		case 3:
			sit.typeInfo = &idAFEntity_Base::Type;
			sit.textKey = "articulatedFigure";
			selectableEntityClasses.Append( sit );
			break;
		case 4:
			sit.typeInfo = &idFuncEmitter::Type;
			sit.textKey = "model";
			selectableEntityClasses.Append( sit );
			break;
		case 5:
			sit.typeInfo = &idAI::Type;
			sit.textKey = "name";
			selectableEntityClasses.Append( sit );
			break;
		case 6:
			sit.typeInfo = &idEntity::Type;
			sit.textKey = "name";
			selectableEntityClasses.Append( sit );
			break;
		case 7:
			sit.typeInfo = &idEntity::Type;
			sit.textKey = "model";
			selectableEntityClasses.Append( sit );
			break;
		default:
			return;
	}

	idBounds viewBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
	idBounds viewTextBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
	idMat3 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3();

	viewBounds.ExpandSelf( 512 );
	viewTextBounds.ExpandSelf( 128 );

	idStr textKey;

	for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {

		idVec4 color;

		textKey = "";
		if ( !EntityIsSelectable( ent, &color, &textKey ) ) {
			continue;
		}

		bool drawArrows = false;
		if ( ent->GetType() == &idAFEntity_Base::Type ) {
			if ( !static_cast<idAFEntity_Base *>(ent)->IsActiveAF() ) {
				continue;
			}
		} else if ( ent->GetType() == &idSound::Type ) {
			if ( ent->fl.selected ) {
				drawArrows = true;
			}
			const idSoundShader * ss = declManager->FindSound( ent->spawnArgs.GetString( textKey ) );
			if ( ss->HasDefaultSound() || ss->base->GetState() == DS_DEFAULTED ) {
				color.Set( 1.0f, 0.0f, 1.0f, 1.0f );
			}
		} else if ( ent->GetType() == &idFuncEmitter::Type ) {
			if ( ent->fl.selected ) {
				drawArrows = true;
			}
		}

		if ( !viewBounds.ContainsPoint( ent->GetPhysics()->GetOrigin() ) ) {
			continue;
		}

		gameRenderWorld->DebugBounds( color, idBounds( ent->GetPhysics()->GetOrigin() ).Expand( 8 ) );
		if ( drawArrows ) {
			idVec3 start = ent->GetPhysics()->GetOrigin();
			idVec3 end = start + idVec3( 1, 0, 0 ) * 20.0f;
			gameRenderWorld->DebugArrow( colorWhite, start, end, 2 );
			gameRenderWorld->DrawText( "x+", end + idVec3( 4, 0, 0 ), 0.15f, colorWhite, axis );
			end = start + idVec3( 1, 0, 0 ) * -20.0f;
			gameRenderWorld->DebugArrow( colorWhite, start, end, 2 );
			gameRenderWorld->DrawText( "x-", end + idVec3( -4, 0, 0 ), 0.15f, colorWhite, axis );
			end = start + idVec3( 0, 1, 0 ) * +20.0f;
			gameRenderWorld->DebugArrow( colorGreen, start, end, 2 );
			gameRenderWorld->DrawText( "y+", end + idVec3( 0, 4, 0 ), 0.15f, colorWhite, axis );
			end = start + idVec3( 0, 1, 0 ) * -20.0f;
			gameRenderWorld->DebugArrow( colorGreen, start, end, 2 );
			gameRenderWorld->DrawText( "y-", end + idVec3( 0, -4, 0 ), 0.15f, colorWhite, axis );
			end = start + idVec3( 0, 0, 1 ) * +20.0f;
			gameRenderWorld->DebugArrow( colorBlue, start, end, 2 );
			gameRenderWorld->DrawText( "z+", end + idVec3( 0, 0, 4 ), 0.15f, colorWhite, axis );
			end = start + idVec3( 0, 0, 1 ) * -20.0f;
			gameRenderWorld->DebugArrow( colorBlue, start, end, 2 );
			gameRenderWorld->DrawText( "z-", end + idVec3( 0, 0, -4 ), 0.15f, colorWhite, axis );
		}

		if ( textKey.Length() ) {
			const char *text = ent->spawnArgs.GetString( textKey );
			if ( viewTextBounds.ContainsPoint( ent->GetPhysics()->GetOrigin() ) ) {
				gameRenderWorld->DrawText( text, ent->GetPhysics()->GetOrigin() + idVec3(0, 0, 12), 0.25, colorWhite, axis, 1 );
			}
		}
	}
}
Пример #19
0
void idKeypad::OnFrob( idEntity* activator )
{
	int index;
	
	if (!activator->spawnArgs.GetInt( "index", "", index))
	{
		return;
	}

	//common->Printf("%d\n", index);

	if (index == 16)
	{
		this->StartSound( "snd_error" , SND_CHANNEL_ANY, 0, false, NULL );
		return;
	}

	//PostEventSec( &EV_Turret_muzzleflashoff, MUZZLEFLASHTIME);
	if (index >= 0 && index <= 8)
	{
		jointHandle_t joint;

		joint = animator.GetJointHandle( GetJointViaIndex(index) );
		animator.SetJointPos(joint, JOINTMOD_LOCAL, idVec3(-0.8f, 0, 0) );

		transitions[index] = gameLocal.time + PRESSTIME;
	}


	StartSound( "snd_press", SND_CHANNEL_ANY, 0, false, NULL );
	
	if (counter <= 0)
	{
		Event_PlayAnim("marker0", 4);
	}
	else if (counter == 1)
	{
		Event_PlayAnim("marker1", 4);
	}
	else if (counter == 2)
	{
		Event_PlayAnim("marker2", 4);
	}
	else if (counter == 3)
	{
		Event_PlayAnim("marker3", 4);
	}

	input[counter] = index;

	counter++;

	if (counter >= 4)
	{
		int i;		
		for (i = 0; i < 9; i++)
		{
			this->frobcubes[i]->isFrobbable = false;
		}
		counter = 0;

		//TODO if successful.
		// gameLocal.GetLocalPlayer()->Event_useAmmo("ammo_hacktool", 1)
		if ( input[0] == keycode[0] && input[1] == keycode[1] && input[2] == keycode[2] && input[3] == keycode[3] )
		{
			//done success.
			bluebox->Hide();
			ActivateTargets( this );

			state = CONFIRM_SUCCESS;
			int doneTime = Event_PlayAnim("success", 4);
			
			nextStateTime = doneTime;

			SetSkin(declManager->FindSkin("skins/keypad/green"));	

			//add hud message.

			StartSound( "snd_deactivated", SND_CHANNEL_ANY, 0, false, NULL);

			return;
		}
		else
		{
			//fail.
			state = CONFIRM_FAIL;
			int doneTime = Event_PlayAnim("fail", 4);
			nextStateTime = doneTime;

			SetSkin(declManager->FindSkin("skins/keypad/red"));
			return;
		}
	}
}
Пример #20
0
/*
====================
idRenderModelLiquid::InitFromFile
====================
*/
void idRenderModelLiquid::InitFromFile( const char *fileName ) {
	int				i, x, y;
	idToken			token;
	idParser		parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
	idList<int>		tris;
	float			size_x, size_y;
	float			rate;

	name = fileName;

	if ( !parser.LoadFile( fileName ) ) {
		MakeDefaultModel();
		return;
	}

	size_x = scale_x * verts_x;
	size_y = scale_y * verts_y;

	while( parser.ReadToken( &token ) ) {
		if ( !token.Icmp( "seed" ) ) {
			seed = parser.ParseInt();
		} else if ( !token.Icmp( "size_x" ) ) {
			size_x = parser.ParseFloat();
		} else if ( !token.Icmp( "size_y" ) ) {
			size_y = parser.ParseFloat();
		} else if ( !token.Icmp( "verts_x" ) ) {
			verts_x = parser.ParseFloat();
			if ( verts_x < 2 ) {
				parser.Warning( "Invalid # of verts.  Using default model." );
				MakeDefaultModel();
				return;
			}
		} else if ( !token.Icmp( "verts_y" ) ) {
			verts_y = parser.ParseFloat();
			if ( verts_y < 2 ) {
				parser.Warning( "Invalid # of verts.  Using default model." );
				MakeDefaultModel();
				return;
			}
		} else if ( !token.Icmp( "liquid_type" ) ) {
			liquid_type = parser.ParseInt() - 1;
			if ( ( liquid_type < 0 ) || ( liquid_type >= LIQUID_MAX_TYPES ) ) {
				parser.Warning( "Invalid liquid_type.  Using default model." );
				MakeDefaultModel();
				return;
			}
		} else if ( !token.Icmp( "density" ) ) {
			density = parser.ParseFloat();
		} else if ( !token.Icmp( "drop_height" ) ) {
			drop_height = parser.ParseFloat();
		} else if ( !token.Icmp( "drop_radius" ) ) {
			drop_radius = parser.ParseInt();
		} else if ( !token.Icmp( "drop_delay" ) ) {
			drop_delay = SEC2MS( parser.ParseFloat() );
		} else if ( !token.Icmp( "shader" ) ) {
			parser.ReadToken( &token );
			shader = declManager->FindMaterial( token );
		} else if ( !token.Icmp( "seed" ) ) {
			seed = parser.ParseInt();
		} else if ( !token.Icmp( "update_rate" ) ) {
			rate = parser.ParseFloat();
			if ( ( rate <= 0.0f ) || ( rate > 60.0f ) ) {
				parser.Warning( "Invalid update_rate.  Must be between 0 and 60.  Using default model." );
				MakeDefaultModel();
				return;
			}
			update_tics = 1000 / rate;
		} else {
			parser.Warning( "Unknown parameter '%s'.  Using default model.", token.c_str() );
			MakeDefaultModel();
			return;
		}
	}

	scale_x = size_x / ( verts_x - 1 );
	scale_y = size_y / ( verts_y - 1 );

	pages.SetNum( 2 * verts_x * verts_y );
	page1 = pages.Ptr();
	page2 = page1 + verts_x * verts_y;

	verts.SetNum( verts_x * verts_y );
	for ( i = 0, y = 0; y < verts_y; y++ ) {
		for ( x = 0; x < verts_x; x++, i++ ) {
			page1[ i ] = 0.0f;
			page2[ i ] = 0.0f;
			verts[ i ].Clear();
			verts[ i ].xyz.Set( x * scale_x, y * scale_y, 0.0f );
			verts[ i ].st.Set( (float) x / (float)( verts_x - 1 ), (float) -y / (float)( verts_y - 1 ) );
		}
	}

	tris.SetNum( ( verts_x - 1 ) * ( verts_y - 1 ) * 6 );
	for( i = 0, y = 0; y < verts_y - 1; y++ ) {
		for( x = 1; x < verts_x; x++, i += 6 ) {
			tris[ i + 0 ] = y * verts_x + x;
			tris[ i + 1 ] = y * verts_x + x - 1;
			tris[ i + 2 ] = ( y + 1 ) * verts_x + x - 1;

			tris[ i + 3 ] = ( y + 1 ) * verts_x + x - 1;
			tris[ i + 4 ] = ( y + 1 ) * verts_x + x;
			tris[ i + 5 ] = y * verts_x + x;
		}
	}

	// build the information that will be common to all animations of this mesh:
	// sil edge connectivity and normal / tangent generation information
	deformInfo = R_BuildDeformInfo( verts.Num(), verts.Ptr(), tris.Num(), tris.Ptr(), true );

	bounds.Clear();
	bounds.AddPoint( idVec3( 0.0f, 0.0f, drop_height * -10.0f ) );
	bounds.AddPoint( idVec3( ( verts_x - 1 ) * scale_x, ( verts_y - 1 ) * scale_y, drop_height * 10.0f ) );

	// set the timestamp for reloadmodels
	fileSystem->ReadFile( name, NULL, &timeStamp );

	Reset();
}
Пример #21
0
/*
=====================
idCameraAnim::GetViewParms
=====================
*/
void idCameraAnim::GetViewParms( renderView_t *view ) {
	int				realFrame;
	int				frame;
	int				frameTime;
	float			lerp;
	float			invlerp;
	cameraFrame_t	*camFrame;
	int				i;
	int				cut;
	idQuat			q1, q2, q3;

	assert( view );
	if ( !view ) {
		return;
	}

	if ( camera.Num() == 0 ) {
		// we most likely are in the middle of a restore
		// FIXME: it would be better to fix it so this doesn't get called during a restore
		return;
	}

#ifdef _D3XP
	SetTimeState ts( timeGroup );
#endif

	if ( frameRate == USERCMD_HZ ) {
		frameTime	= gameLocal.time - starttime;
		frame		= frameTime / gameLocal.msec;
		lerp		= 0.0f;
	} else {
		frameTime	= ( gameLocal.time - starttime ) * frameRate;
		frame		= frameTime / 1000;
		lerp		= ( frameTime % 1000 ) * 0.001f;
	}

	// skip any frames where camera cuts occur
	realFrame = frame;
	cut = 0;
	for( i = 0; i < cameraCuts.Num(); i++ ) {
		if ( frame < cameraCuts[ i ] ) {
			break;
		}
		frame++;
		cut++;
	}

	if ( g_debugCinematic.GetBool() ) {
		int prevFrameTime	= ( gameLocal.time - starttime - gameLocal.msec ) * frameRate;
		int prevFrame		= prevFrameTime / 1000;
		int prevCut;

		prevCut = 0;
		for( i = 0; i < cameraCuts.Num(); i++ ) {
			if ( prevFrame < cameraCuts[ i ] ) {
				break;
			}
			prevFrame++;
			prevCut++;
		}

		if ( prevCut != cut ) {
			gameLocal.Printf( "%d: '%s' cut %d\n", gameLocal.framenum, GetName(), cut );
		}
	}

	// clamp to the first frame.  also check if this is a one frame anim.  one frame anims would end immediately,
	// but since they're mainly used for static cams anyway, just stay on it infinitely.
	if ( ( frame < 0 ) || ( camera.Num() < 2 ) ) {
		view->viewaxis = camera[ 0 ].q.ToQuat().ToMat3();
		view->vieworg = camera[ 0 ].t + offset;
		view->fov_x = camera[ 0 ].fov;
	} else if ( frame > camera.Num() - 2 ) {
		if ( cycle > 0 ) {
			cycle--;
		}

		if ( cycle != 0 ) {
			// advance start time so that we loop
			starttime += ( ( camera.Num() - cameraCuts.Num() ) * 1000 ) / frameRate;
			GetViewParms( view );
			return;
		}

		Stop();
		if ( gameLocal.GetCamera() != NULL ) {
			// we activated another camera when we stopped, so get it's viewparms instead
			gameLocal.GetCamera()->GetViewParms( view );
			return;
		} else {
			// just use our last frame
			camFrame = &camera[ camera.Num() - 1 ];
			view->viewaxis = camFrame->q.ToQuat().ToMat3();
			view->vieworg = camFrame->t + offset;
			view->fov_x = camFrame->fov;
		}
	} else if ( lerp == 0.0f ) {
		camFrame = &camera[ frame ];
		view->viewaxis = camFrame[ 0 ].q.ToMat3();
		view->vieworg = camFrame[ 0 ].t + offset;
		view->fov_x = camFrame[ 0 ].fov;
	} else {
		camFrame = &camera[ frame ];
		invlerp = 1.0f - lerp;
		q1 = camFrame[ 0 ].q.ToQuat();
		q2 = camFrame[ 1 ].q.ToQuat();
		q3.Slerp( q1, q2, lerp );
		view->viewaxis = q3.ToMat3();
		view->vieworg = camFrame[ 0 ].t * invlerp + camFrame[ 1 ].t * lerp + offset;
		view->fov_x = camFrame[ 0 ].fov * invlerp + camFrame[ 1 ].fov * lerp;
	}

	gameLocal.CalcFov( view->fov_x, view->fov_x, view->fov_y );

	// setup the pvs for this frame
	UpdatePVSAreas( view->vieworg );

#if 0
	static int lastFrame = 0;
	static idVec3 lastFrameVec( 0.0f, 0.0f, 0.0f );
	if ( gameLocal.time != lastFrame ) {
		gameRenderWorld->DebugBounds( colorCyan, idBounds( view->vieworg ).Expand( 16.0f ), vec3_origin, gameLocal.msec );
		gameRenderWorld->DebugLine( colorRed, view->vieworg, view->vieworg + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false );
		gameRenderWorld->DebugLine( colorCyan, lastFrameVec, view->vieworg, 10000, false );
		gameRenderWorld->DebugLine( colorYellow, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 66.0f, 10000, false );
		gameRenderWorld->DebugLine( colorOrange, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 64.0f + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false );
		lastFrameVec = view->vieworg;
		lastFrame = gameLocal.time;
	}
#endif

	if ( g_showcamerainfo.GetBool() ) {
		gameLocal.Printf( "^5Frame: ^7%d/%d\n\n\n", realFrame + 1, camera.Num() - cameraCuts.Num() );
	}
}
Пример #22
0
/*
==============
sdDeployMaskEditSession::UpdateProjection
==============
*/
void sdDeployMaskEditSession::UpdateProjection( const idVec3& position ) {
	if ( !decalMaterial ) {
		return;
	}

	if ( decalHandle == -1 ) {
		decalHandle = gameLocal.RegisterLoggedDecal( decalMaterial );
	}
	gameLocal.ResetLoggedDecal( decalHandle );

	gameDecalInfo_t* decalInfo = gameLocal.GetLoggedDecal( decalHandle );

	sdDeployMaskInstance* mask = GetMask( position );
	const sdHeightMapInstance* heightMap = GetHeightMap( position );

	if ( mask != NULL && mask->IsValid() && heightMap != NULL ) {
		sdDeployMask::extents_t extents;
		GetExtents( position, *mask, extents );

		float depth = 512.0f;

		int maxX, maxY;
		mask->GetDimensions( maxX, maxY );

		sdDeployMask::extents_t expandedExtents;

		expandedExtents.minx = Max( 0, extents.minx - 2 );
		expandedExtents.miny = Max( 0, extents.miny - 2 );

		expandedExtents.maxx = Min( maxX, extents.maxx + 2 );
		expandedExtents.maxy = Min( maxY, extents.maxy + 2 );

		idList< const idMaterial* > megaTextureMaterials;
		const idStrList& megaTextureMaterialNames = gameLocal.GetMapInfo().GetMegatextureMaterials();
		for ( int i = 0; i < megaTextureMaterialNames.Num(); i++ ) {
			megaTextureMaterials.Append( declHolder.FindMaterial( megaTextureMaterialNames[ i ] ) );
		}

		idFixedWinding winding;
		
		int spawnID = WORLD_SPAWN_ID;

		for ( int i = expandedExtents.minx; i <= expandedExtents.maxx; i++ ) {
			for ( int j = expandedExtents.miny; j <= expandedExtents.maxy; j++ ) {
				gameDecalInfo_t* info = decalInfo;
				if ( !info ) {
					continue;
				}

				sdDeployMask::extents_t localExtents;
				localExtents.minx = i;
				localExtents.maxx = i;
				localExtents.miny = j;
				localExtents.maxy = j;

				idBounds bounds;
				mask->GetBounds( localExtents, bounds, heightMap );

				idVec3 top = bounds.GetCenter();
				top[ 2 ] = bounds.GetMaxs()[ 2 ];				

				deployResult_t localResult = mask->IsValid( localExtents );

				idVec4 localColor;
				switch ( localResult ) {
					case DR_CLEAR:
						localColor = colorGreen;
						break;
					default:
					case DR_FAILED:
						localColor = colorDkRed;
						break;
				}

				if ( !( ( i >= extents.minx ) && ( i <= extents.maxx ) && ( j >= extents.miny ) && ( j <= extents.maxy ) ) ) {
					localColor.x *= 0.3f;
					localColor.y *= 0.3f;
					localColor.z *= 0.3f;
				}

				winding.Clear();
				winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 0.0f ) );
				winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 1.0f ) );
				winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 1.0f ) );
				winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 0.0f ) );

				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0, 0, 64.f + depth ), true, localColor, info->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );
			}
		}
	}
}
Пример #23
0
void idTrembler::Event_Touch( idEntity *other, trace_t *trace )
{
	


	if (state == 0)
	{
		idEntity	*entityList[ MAX_GENTITIES ];
		int			i;
		int			flyforce;

		state = 1;

		Event_PlayAnim("bounce", 1);
		StartSound( "snd_trigger", SND_CHANNEL_BODY, 0, false, NULL );
		StartSound( "snd_trigger_idle", SND_CHANNEL_BODY2, 0, false, NULL );


		ticksoundTime = gameLocal.time + (spawnArgs.GetInt("ticktime", "10") * 1000);


		if (g_skill.GetInteger() > 0)
		{
			ActivateTargets(this); //activate alarm.
		}






		int listedEntities = gameLocal.EntitiesWithinRadius( GetPhysics()->GetOrigin(), FLYRADIUS, entityList, MAX_GENTITIES );

		flyforce = spawnArgs.GetInt("force", "256");

		renderEntity.shaderParms[ SHADERPARM_RED ] = 1;
		renderEntity.shaderParms[ SHADERPARM_GREEN ] = 0;
		renderEntity.shaderParms[ SHADERPARM_BLUE ] = 0;
		UpdateVisuals();



		//KA BOIIIIINNNGGGGGG
		for (i = 0; i < listedEntities; i++)
		{
			idEntity *ent = entityList[ i ];

			if (!ent)
			{
				continue;
			}

			float ent_zpos = ent->GetPhysics()->GetOrigin().z;
			float trembler_zpos = this->GetPhysics()->GetOrigin().z;

			//only affect things above the trembler.
			if (ent_zpos < trembler_zpos)
				continue;

			//only affect things within X height of trembler.
			if (ent_zpos > trembler_zpos + HEIGHT_MAX)
				continue;

			if ( !ent->IsType( idMoveableItem::Type ) && !ent->IsType( idMoveable::Type ) )
				continue;

			ent->GetPhysics()->SetLinearVelocity(idVec3(0,0,1) * flyforce);
		}
	}
}
Пример #24
0
/*
================
sdScriptedEntityHelper_LegIk::Init
================
*/
void sdScriptedEntityHelper_LegIk::Init( sdScriptEntity* owner, const sdDeclStringMap* map ) {
	sdScriptedEntityHelper::Init( owner, map );

	const idDict& dict = map->GetDict();
	idAnimator* animator = _owner->GetAnimator();

	upperLegJoint	= animator->GetJointHandle( dict.GetString( "joint_upper" ) );
	if ( upperLegJoint == INVALID_JOINT ) {
		gameLocal.Warning( "sdScriptedEntityHelper_LegIk::Init Invalid Upper Leg Joint" );
	}

	middleLegJoint	= animator->GetJointHandle( dict.GetString( "joint_middle" ) );
	if ( middleLegJoint == INVALID_JOINT ) {
		gameLocal.Warning( "sdScriptedEntityHelper_LegIk::Init Invalid Middle Leg Joint" );
	}

	lowerLegJoint	= animator->GetJointHandle( dict.GetString( "joint_lower" ) );
	if ( lowerLegJoint == INVALID_JOINT ) {
		gameLocal.Warning( "sdScriptedEntityHelper_LegIk::Init Invalid Lower Leg Joint" );
	}

	upDir			= dict.GetVector( "direction", "0 0 1" );

	groundOffset	= dict.GetFloat( "ground_offset" );
	blendRate		= dict.GetFloat( "blend_rate", "0.95" );

	maxUpTrace		= dict.GetFloat( "max_up_trace", "64" );
	maxDownTrace	= dict.GetFloat( "max_down_trace", "64" );

	lifetime		= dict.GetInt( "lifetime", "5000" );
	startTime		= gameLocal.time;



	idMat3 axis;

	idMat3 upperJointAxis,	middleJointAxis,	lowerJointAxis;
	idVec3 upperJointOrg,	middleJointOrg,		lowerJointOrg;

	animator->GetJointTransform( upperLegJoint,		gameLocal.time, upperJointOrg,	upperJointAxis );
	animator->GetJointTransform( middleLegJoint,	gameLocal.time, middleJointOrg, middleJointAxis );
	animator->GetJointTransform( lowerLegJoint,		gameLocal.time, lowerJointOrg,	lowerJointAxis );

	upperLength		= idIK::GetBoneAxis( upperJointOrg, middleJointOrg, upDir, axis );
	midToUpperJoint = upperJointAxis * axis.Transpose();

	lowerLength		= idIK::GetBoneAxis( middleJointOrg, lowerJointOrg, upDir, axis );
	lowerToMidJoint = middleJointAxis * axis.Transpose();

	{
		idVec3 lowerJointOrg;

		animator->GetJointTransform( lowerLegJoint,		gameLocal.time, lowerJointOrg );

		idVec3 traceOrg = _owner->GetRenderEntity()->origin + ( lowerJointOrg * _owner->GetRenderEntity()->axis );

		trace_t tr;
		gameLocal.clip.TracePoint( CLIP_DEBUG_PARMS tr, traceOrg + idVec3( 0, 0, maxUpTrace ), traceOrg - idVec3( 0, 0, maxDownTrace ), CONTENTS_SOLID, _owner );

		currentGroundOffset = traceOrg.z - tr.endpos.z;
	}

	owner->IncForcedAnimUpdate();
}
Пример #25
0
/*
============
idFrustum::ProjectionBounds
============
*/
bool idFrustum::ProjectionBounds( const idBox &box, idBounds &projectionBounds ) const
{
	int i, p1, p2, pointCull[8], culled, outside;
	float scale1, scale2;
	idFrustum localFrustum;
	idVec3 points[8], localOrigin;
	idMat3 localAxis, localScaled;
	idBounds bounds( -box.GetExtents(), box.GetExtents() );
	
	// if the frustum origin is inside the bounds
	if( bounds.ContainsPoint( ( origin - box.GetCenter() ) * box.GetAxis().Transpose() ) )
	{
		// bounds that cover the whole frustum
		float boxMin, boxMax, base;
		
		base = origin * axis[0];
		box.AxisProjection( axis[0], boxMin, boxMax );
		
		projectionBounds[0].x = boxMin - base;
		projectionBounds[1].x = boxMax - base;
		projectionBounds[0].y = projectionBounds[0].z = -1.0f;
		projectionBounds[1].y = projectionBounds[1].z = 1.0f;
		
		return true;
	}
	
	projectionBounds.Clear();
	
	// transform the bounds into the space of this frustum
	localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
	localAxis = box.GetAxis() * axis.Transpose();
	BoxToPoints( localOrigin, box.GetExtents(), localAxis, points );
	
	// test outer four edges of the bounds
	culled = -1;
	outside = 0;
	for( i = 0; i < 4; i++ )
	{
		p1 = i;
		p2 = 4 + i;
		AddLocalLineToProjectionBoundsSetCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
		culled &= pointCull[p1] & pointCull[p2];
		outside |= pointCull[p1] | pointCull[p2];
	}
	
	// if the bounds are completely outside this frustum
	if( culled )
	{
		return false;
	}
	
	// if the bounds are completely inside this frustum
	if( !outside )
	{
		return true;
	}
	
	// test the remaining edges of the bounds
	for( i = 0; i < 4; i++ )
	{
		p1 = i;
		p2 = ( i + 1 ) & 3;
		AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
	}
	
	for( i = 0; i < 4; i++ )
	{
		p1 = 4 + i;
		p2 = 4 + ( ( i + 1 ) & 3 );
		AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
	}
	
	// if the bounds extend beyond two or more boundaries of this frustum
	if( outside != 1 && outside != 2 && outside != 4 && outside != 8 )
	{
	
		localOrigin = ( origin - box.GetCenter() ) * box.GetAxis().Transpose();
		localScaled = axis * box.GetAxis().Transpose();
		localScaled[0] *= dFar;
		localScaled[1] *= dLeft;
		localScaled[2] *= dUp;
		
		// test the outer edges of this frustum for intersection with the bounds
		if( ( outside & 2 ) && ( outside & 8 ) )
		{
			BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] - localScaled[2], scale1, scale2 );
			if( scale1 <= scale2 && scale1 >= 0.0f )
			{
				projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, -1.0f ) );
				projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, -1.0f ) );
			}
		}
		if( ( outside & 2 ) && ( outside & 4 ) )
		{
			BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] + localScaled[2], scale1, scale2 );
			if( scale1 <= scale2 && scale1 >= 0.0f )
			{
				projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, 1.0f ) );
				projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, 1.0f ) );
			}
		}
		if( ( outside & 1 ) && ( outside & 8 ) )
		{
			BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] - localScaled[2], scale1, scale2 );
			if( scale1 <= scale2 && scale1 >= 0.0f )
			{
				projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, -1.0f ) );
				projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, -1.0f ) );
			}
		}
		if( ( outside & 1 ) && ( outside & 2 ) )
		{
			BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] + localScaled[2], scale1, scale2 );
			if( scale1 <= scale2 && scale1 >= 0.0f )
			{
				projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, 1.0f ) );
				projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, 1.0f ) );
			}
		}
	}
	
	return true;
}
Пример #26
0
/*
================
sdPlayerArmIK::Update
================
*/
void sdPlayerArmIK::Update( idPlayer* player, idEntity* target ) {
	struct arm_t {
		idMat3				targetShoulderAxis;
		idMat3				targetElbowAxis;
		idMat3				targetHandAxis;
	};

	arm_t					arms[ NUM_ARMS ];

	ClearJointMods( player );

	idAnimator* animator = player->GetAnimator();

	idMat3 tempAxis;

	idVec3 modelOrigin			= player->GetRenderEntity()->origin;
	idMat3 modelAxis			= player->GetRenderEntity()->axis;
	idMat3 transposeModelAxis	= modelAxis.Transpose();

	// get the arm bone lengths and rotation matrices
	for ( int i = 0; i < NUM_ARMS; i++ ) {
		if ( armTargets[ i ].joint == INVALID_JOINT ) {
			continue;
		}

		idMat3 handAxis;
		idVec3 handOrigin;
		animator->GetJointTransform( player->GetHandJoint( i ), gameLocal.time, handOrigin, handAxis );
		
		idMat3 elbowAxis;
		idVec3 elbowOrigin;
		animator->GetJointTransform( player->GetElbowJoint( i ), gameLocal.time, elbowOrigin, elbowAxis );

		idMat3 shoulderAxis;
		idVec3 shoulderOrigin;
		animator->GetJointTransform( player->GetShoulderJoint( i ), gameLocal.time, shoulderOrigin, shoulderAxis );

		idVec3 t1 = ( elbowOrigin - shoulderOrigin );
//		t1.Normalize();
		idVec3 t2 = ( elbowOrigin - handOrigin );
//		t2.Normalize();

		idVec3 dir = t1 + t2;
		dir.Normalize();

		// conversion from upper arm bone axis to should joint axis
		float upperArmLength				= idIK::GetBoneAxis( shoulderOrigin, elbowOrigin, dir, tempAxis );
		idMat3 upperArmToShoulderJoint		= shoulderAxis * tempAxis.Transpose();

		// conversion from lower arm bone axis to elbow joint axis
		float lowerArmLength				= idIK::GetBoneAxis( elbowOrigin, handOrigin, dir, tempAxis );
		idMat3 lowerArmToElbowJoint			= elbowAxis * tempAxis.Transpose();

		// get target
		idVec3 targetOrigin;
		target->GetWorldOriginAxis( armTargets[ i ].joint, targetOrigin, arms[ i ].targetHandAxis );

		idVec3 targetOriginLocal = targetOrigin - modelOrigin;
		targetOriginLocal *= transposeModelAxis;
		arms[ i ].targetHandAxis *= transposeModelAxis;
		
		// solve IK and calculate elbow position
		idIK::SolveTwoBones( shoulderOrigin, targetOriginLocal, dir, upperArmLength, lowerArmLength, elbowOrigin );

		if ( ik_debug.GetBool() ) {
			idVec3 shoulderWorld	= ( shoulderOrigin * modelAxis ) +  modelOrigin;
			idVec3 elbowWorld		= ( elbowOrigin * modelAxis ) +  modelOrigin;

			gameRenderWorld->DebugLine( colorCyan, shoulderWorld, elbowWorld );
			gameRenderWorld->DebugLine( colorRed, elbowWorld, targetOrigin );
			gameRenderWorld->DebugBox( colorYellow, idBox( targetOrigin, idVec3( 2, 2, 2 ), mat3_identity ) );
			gameRenderWorld->DebugLine( colorGreen, elbowWorld, elbowWorld + ( ( dir * modelAxis ) * 8 ) );
		}

		// get the axis for the shoulder joint
		idIK::GetBoneAxis( shoulderOrigin, elbowOrigin, dir, tempAxis );
		arms[ i ].targetShoulderAxis = upperArmToShoulderJoint * tempAxis;

		// get the axis for the elbow joint
		idIK::GetBoneAxis( elbowOrigin, targetOriginLocal, dir, tempAxis );
		arms[ i ].targetElbowAxis = lowerArmToElbowJoint * tempAxis;
	}

	for ( int i = 0; i < NUM_ARMS; i++ ) {
		if ( armTargets[ i ].joint == INVALID_JOINT ) {
			continue;
		}

		animator->SetJointAxis( player->GetShoulderJoint( i ), JOINTMOD_WORLD_OVERRIDE, arms[ i ].targetShoulderAxis );
		animator->SetJointAxis( player->GetElbowJoint( i ), JOINTMOD_WORLD_OVERRIDE, arms[ i ].targetElbowAxis );
		animator->SetJointAxis( player->GetHandJoint( i ), JOINTMOD_WORLD_OVERRIDE, arms[ i ].targetHandAxis );
	}
}
/*
============
idAASLocal::DrawEdge
============
*/
void idAASLocal::DrawEdge( int edgeNum, bool arrow ) const {
	const aasEdge_t *edge;
	idVec4 *color;

	if ( !file ) {
		return;
	}

	edge = &file->GetEdge( edgeNum );
	color = &colorRed;
	if ( arrow ) {
		gameRenderWorld->DebugArrow( *color, file->GetVertex( edge->vertexNum[0] ), file->GetVertex( edge->vertexNum[1] ), 1 );
	} else {
		gameRenderWorld->DebugLine( *color, file->GetVertex( edge->vertexNum[0] ), file->GetVertex( edge->vertexNum[1] ) );
	}

	if ( gameLocal.GetLocalPlayer() ) {
		gameRenderWorld->DrawText( va( "%d", edgeNum ), ( file->GetVertex( edge->vertexNum[0] ) + file->GetVertex( edge->vertexNum[1] ) ) * 0.5f + idVec3(0,0,4), 0.1f, colorRed, gameLocal.GetLocalPlayer()->viewAxis );
	}
}
Пример #28
0
/*
================
sdScriptedEntityHelper_LegIk::Update
================
*/
void sdScriptedEntityHelper_LegIk::Update( bool postThink ) {
	if ( !gameLocal.isNewFrame || postThink ) {
		return;
	}

	if ( gameLocal.time - startTime > lifetime ) {
		delete this;
		return;
	}

	idMat3 upperJointAxis,	middleJointAxis,	lowerJointAxis;
	idVec3 upperJointOrg,	middleJointOrg,		lowerJointOrg;

	ClearJointMods();

	idAnimator* animator = _owner->GetAnimator();

	if ( !animator->GetJointTransform( upperLegJoint, gameLocal.time, upperJointOrg, upperJointAxis ) ) {
		delete this;
		return;
	}
	if ( !animator->GetJointTransform( middleLegJoint, gameLocal.time, middleJointOrg, middleJointAxis ) ) {
		delete this;
		return;
	}
	if ( animator->GetJointTransform( lowerLegJoint, gameLocal.time, lowerJointOrg, lowerJointAxis ) ) {
		delete this;
		return;
	}

	{
		idVec3 traceOrg = _owner->GetRenderEntity()->origin + ( lowerJointOrg * _owner->GetRenderEntity()->axis );

		trace_t tr;
		gameLocal.clip.TracePoint( CLIP_DEBUG_PARMS tr, traceOrg + idVec3( 0, 0, maxUpTrace ), traceOrg - idVec3( 0, 0, maxDownTrace ), CONTENTS_SOLID, _owner );

/*		gameRenderWorld->DebugCircle( colorGreen, tr.endpos, idVec3( 0, 0, 1 ), 8, 16 );
		gameRenderWorld->DebugLine( colorRed, tr.endpos, tr.endpos + idVec3( 0.f, 0.f, currentGroundOffset ) );
		gameRenderWorld->DebugLine( colorBlue, tr.endpos, tr.endpos + idVec3( 0.f, 0.f, lowerJointOrg.z ) );*/

		currentGroundOffset = Lerp( currentGroundOffset, lowerJointOrg.z, blendRate * MS2SEC( gameLocal.msec ) );

		idVec3 jointPos = ( ( tr.endpos + idVec3( 0.f, 0.f, currentGroundOffset ) ) - _owner->GetRenderEntity()->origin ) * _owner->GetRenderEntity()->axis.Transpose();

		idVec3 endPos;
		idIK::SolveTwoBones( upperJointOrg, jointPos, -upDir, upperLength, lowerLength, endPos );

		idMat3 axis;
		idIK::GetBoneAxis( upperJointOrg, endPos, upDir, axis );
		idMat3 upperAxis = midToUpperJoint * axis;

		idIK::GetBoneAxis( endPos, jointPos, upDir, axis );
		idMat3 middleAxis = lowerToMidJoint * axis;

		animator->SetJointAxis( upperLegJoint, JOINTMOD_WORLD_OVERRIDE, upperAxis );
		animator->SetJointAxis( middleLegJoint, JOINTMOD_WORLD_OVERRIDE, middleAxis );		

/*		idVec3 worldOrg;
		_owner->GetWorldOrigin( upperLegJoint, worldOrg );

		gameRenderWorld->DebugLine( colorGreen, worldOrg, worldOrg + ( ( side * _owner->GetRenderEntity()->axis ) * 16 ) );
		gameRenderWorld->DebugLine( colorBlue, worldOrg, worldOrg + ( ( up * _owner->GetRenderEntity()->axis ) * 16 ) );
		gameRenderWorld->DebugLine( colorRed, worldOrg, worldOrg + ( ( temp * _owner->GetRenderEntity()->axis ) * 16 ) );*/
	}
}
Пример #29
0
/*
================
idThread::Event_VecToAngles
================
*/
void idThread::Event_VecToAngles( idVec3 &vec ) {
	idAngles ang = vec.ToAngles();
	ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
}
void InvestigateSpotTask::Init(idAI* owner, Subsystem& subsystem)
{
	// Just init the base class
	Task::Init(owner, subsystem);

	// Get a shortcut reference
	Memory& memory = owner->GetMemory();

	// Stop previous moves
	//owner->StopMove(MOVE_STATUS_DONE);

	if (memory.currentSearchSpot != idVec3(idMath::INFINITY, idMath::INFINITY, idMath::INFINITY))
	{
		// Set the goal position
		SetNewGoal(memory.currentSearchSpot);
		memory.hidingSpotInvestigationInProgress = true; // grayman #3857
		memory.stopHidingSpotInvestigation = false;
	}
	else
	{
		// Invalid hiding spot, terminate task
		subsystem.FinishTask();
	}

	// grayman #3857 - Only the first searcher in a search is allowed to investigate
	// the spot closely. Am I it?

	if (_investigateClosely)
	{
		Search* search = gameLocal.m_searchManager->GetSearch(owner->m_searchID);
		if (search)
		{
			if (search->_searcherCount > 0)
			{
				Assignment *assignment = &search->_assignments[0]; // first AI assigned to the search
				if (assignment->_searcher != owner)
				{
					_investigateClosely = false;
				}
			}
		}
	}

	if (owner->HasSeenEvidence())
	{
		// Draw weapon, if we haven't already
		if (!owner->GetAttackFlag(COMBAT_MELEE) && !owner->GetAttackFlag(COMBAT_RANGED))
		{
			if ( ( owner->GetNumRangedWeapons() > 0 ) && !owner->spawnArgs.GetBool("unarmed_ranged","0") )
			{
				owner->DrawWeapon(COMBAT_RANGED);
			}
			else if ( ( owner->GetNumMeleeWeapons() > 0 ) && !owner->spawnArgs.GetBool("unarmed_melee","0") )
			{
				owner->DrawWeapon(COMBAT_MELEE);
			}
		}
	}

	//_exitTime = 0; // grayman #3507
}