bool hhCenturion::AttackMelee( const char *meleeDefName ) {
	const idDict *meleeDef;
	idActor *enemyEnt = enemy.GetEntity();
	const char *p;
	const idSoundShader *shader;

	meleeDef = gameLocal.FindEntityDefDict( meleeDefName, false );
	if ( !meleeDef ) {
		gameLocal.Error( "Unknown melee '%s'", meleeDefName );
	}

	if ( !enemyEnt ) {
		p = meleeDef->GetString( "snd_miss" );
		if ( p && *p ) {
			shader = declManager->FindSound( p );
			StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
		}
		return false;
	}

	// make sure the trace can actually hit the enemy
	if ( !TestMelee() ) {
		// missed
		p = meleeDef->GetString( "snd_miss" );
		if ( p && *p ) {
			shader = declManager->FindSound( p );
			StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
		}
		return false;
	}

	//
	// do the damage
	//
	p = meleeDef->GetString( "snd_hit" );
	if ( p && *p ) {
		shader = declManager->FindSound( p );
		StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
	}

	idVec3	kickDir;
	meleeDef->GetVector( "kickDir", "0 0 0", kickDir );

	idVec3	globalKickDir;
	globalKickDir = ( viewAxis * physicsObj.GetGravityAxis() ) * kickDir;

	enemyEnt->Damage( this, this, globalKickDir, meleeDefName, 1.0f, INVALID_JOINT );
	if ( enemyEnt->IsActiveAF() && !enemyEnt->IsType( idPlayer::Type ) ) {
		PostEventMS( &AI_BackhandImpulse, 0, enemyEnt );
	}

	lastAttackTime = gameLocal.time;

	return true;
}
END_CLASS

/*
================
idTarget_EndLevel::Event_Activate
================
*/
void idTarget_EndLevel::Event_Activate( idEntity *activator ) {
	if ( thinkFlags & TH_THINK ) {
		BecomeInactive( TH_THINK );
	} else {
		// always allow during cinematics
		cinematic = true;
		BecomeActive( TH_THINK );
	}

	idPlayer* player;
	player = gameLocal.GetLocalPlayer();
	player->SetInfluenceLevel( 2 );
	player->endLevelTime = gameLocal.time;	// sikk - End Level time
	player->doEndLevel = true;				// sikk - End Level Flag
	if ( !player->scoreBoardOpen ) {
		player->ToggleScoreboard();
	}
	StartSoundShader( declManager->FindSound( "music_endLevel" ), SND_CHANNEL_ANY, 0, false, NULL );
}
Exemple #3
0
/*
================
idSound::DoSound
================
*/
void idSound::DoSound( bool play ) {
	if ( play ) {
		StartSoundShader( refSound.shader, SND_CHANNEL_ANY, refSound.parms.soundShaderFlags, true, &playingUntilTime );
		playingUntilTime += gameLocal.time;
	} else {
		StopSound( SND_CHANNEL_ANY, true );
		playingUntilTime = 0;
	}
}
Exemple #4
0
/*
================
idLight::On
================
*/
void idLight::On( void ) {
	currentLevel = levels;
	// offset the start time of the shader to sync it to the game time
	renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
	if ( ( soundWasPlaying || refSound.waitfortrigger ) && refSound.shader ) {
		StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
		soundWasPlaying = false;
	}
	SetLightLevel();
	BecomeActive( TH_UPDATEVISUALS );
}
Exemple #5
0
/*
================
idLight::UpdateChangeableSpawnArgs
================
*/
void idLight::UpdateChangeableSpawnArgs( const idDict *source ) {
	idEntity::UpdateChangeableSpawnArgs( source );
	if( source ) {
		source->Print();
	}
	FreeSoundEmitter( true );
	gameEdit->ParseSpawnArgsToRefSound( source ? source : &spawnArgs, &refSound );
	if( refSound.shader && !refSound.waitfortrigger ) {
		StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
	}
	gameEdit->ParseSpawnArgsToRenderLight( source ? source : &spawnArgs, &renderLight );
	UpdateVisuals();
}
/*
================
rvClientMoveable::Collide
================
*/
bool rvClientMoveable::Collide ( const trace_t &collision, const idVec3 &velocity ) {	
	if (mPlayBounceSoundOnce && mHasBounced)
	{
		return false;
	}
	if ( bounceSoundShader && gameLocal.time > bounceSoundTime ) {
		float speed;
		speed = velocity.LengthFast ( );
		if ( speed > BOUNCE_SOUND_MIN_VELOCITY ) {
			StartSoundShader ( bounceSoundShader, SND_CHANNEL_BODY, 0 );
			bounceSoundTime = BOUNCE_SOUND_DELAY;
			mHasBounced = true;
		}
	}	
		
	return false;
}
void hhCenturion::Event_CenturionLaunch( const idList<idStr>* parmList ) {
	const idDict* projDef = NULL;
	const idSoundShader* soundShader = NULL;

	// parms: joint, projectileDef, sound, fx
	if( !parmList || parmList->Num() != 5 ) {
		gameLocal.Warning( "Incorrect paramater number" );
		return;
	}
//Rbarrel_A projectile_centurion_autocannon snd_fire fx_muzzleFlash
	const char* jointName = (*parmList)[ 0 ].c_str();
	const char* projectileDefName = (*parmList)[ 1 ].c_str();
	const char* soundName = (*parmList)[ 2 ].c_str();
	const char* fxName = (*parmList)[ 3 ].c_str();
	int autoAim = atoi( (*parmList)[ 4 ].c_str() );

	if( AI_CENTURION_ARM_MISSING ) {	//skip firing if joint is on the severed arm
		if( !idStr::Icmp(jointName, spawnArgs.GetString("severed_jointA", "")) || !idStr::Icmp(jointName, spawnArgs.GetString("severed_jointB", "")) ) {
			return;
		}
	}

	projDef = gameLocal.FindEntityDefDict( projectileDefName, false );
	HH_ASSERT( !shootTarget.IsValid() );
	// If autoAim is true and we're not blending, and we're facing the enemy, auto-aim
	if ( ( autoAim == 1 || ( autoAim == 2 && gameLocal.random.RandomInt(100) < 50 ) ) && torsoAnim.animBlendFrames == 0 && FacingEnemy( 5.0f ) ) {
		AimedAttackMissile( jointName, projDef );
	} else { // Otherwise do a normal missile attack
		Event_AttackMissile( jointName, projDef, 1 );
	}

	if(idStr::Cmpn( soundName, "snd_", 4)) {
		soundShader = declManager->FindSound( soundName );
		if( soundShader->GetState() == DS_DEFAULTED ) {
			gameLocal.Warning( "Sound '%s' not found", soundName );
		}
		StartSoundShader( soundShader, SND_CHANNEL_WEAPON, 0, false, NULL );
	}
	else {
		if( !StartSound(soundName, SND_CHANNEL_WEAPON, 0, false, NULL) ) {
			gameLocal.Warning( "Framecommand 'centurionFire' on entity '%s' could not find sound '%s'", GetName(), soundName );
		}
	}
	BroadcastFxInfoAlongBone( spawnArgs.GetString(fxName), jointName );
}
END_CLASS

/***********************************************************************

	Events

***********************************************************************/

/*
=====================
idActor::Event_EnableEyeFocus
=====================
*/
void idActor::PlayFootStepSound()
{
	const char* sound = NULL;
	const idMaterial* material;
	
	if( !GetPhysics()->HasGroundContacts() )
	{
		return;
	}
	
	// start footstep sound based on material type
	material = GetPhysics()->GetContact( 0 ).material;
	if( material != NULL )
	{
		sound = spawnArgs.GetString( va( "snd_footstep_%s", gameLocal.sufaceTypeNames[ material->GetSurfaceType() ] ) );
	}
	if( sound != NULL && *sound == '\0' )
	{
		sound = spawnArgs.GetString( "snd_footstep" );
	}
	if( sound != NULL && *sound != '\0' )
	{
		StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
	}
}
Exemple #9
0
/*
================
rvClientMoveable::Collide
================
*/
bool rvClientMoveable::Collide ( const trace_t &collision, const idVec3 &velocity ) {	
	if ( firstBounce ) {
		// first bounce, play effect
		const char* bounceEffectName = "fx_firstbounce";
		if ( effectSet != 0 ) {
			bounceEffectName = va( "fx_firstbounce_%i", effectSet );
		}
		const idVec3& origin = physicsObj.GetOrigin();
		idMat3 axis = ( idVec3( 0.0f, 0.0f, 1.0f ) ).ToMat3();
		gameLocal.PlayEffect( *spawnArgs, colorWhite.ToVec3(), bounceEffectName, NULL, origin, axis );
		firstBounce = false;
	}

	if ( bounceSoundShader && gameLocal.time > bounceSoundTime ) {
		float speed;
		speed = velocity.LengthFast ( );
		if ( speed > BOUNCE_SOUND_MIN_VELOCITY ) {
			StartSoundShader ( bounceSoundShader, SND_ANY, 0 );
			bounceSoundTime = BOUNCE_SOUND_DELAY;
		}
	}	
		
	return false;
}
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;
}
Exemple #11
0
/*
================
idBrittleFracture::ProjectDecal
================
*/
void idBrittleFracture::ProjectDecal( const idVec3 &point, const idVec3 &dir, const int time, const char *damageDefName ) {
	int i, j, bits, clipBits;
	float a, c, s;
	idVec2 st[MAX_POINTS_ON_WINDING];
	idVec3 origin;
	idMat3 axis, axistemp;
	idPlane textureAxis[2];

	if ( gameLocal.isServer ) {
		idBitMsg	msg;
		byte		msgBuf[MAX_EVENT_PARAM_SIZE];

		msg.Init( msgBuf, sizeof( msgBuf ) );
		msg.BeginWriting();
		msg.WriteFloat( point[0] );
		msg.WriteFloat( point[1] );
		msg.WriteFloat( point[2] );
		msg.WriteFloat( dir[0] );
		msg.WriteFloat( dir[1] );
		msg.WriteFloat( dir[2] );
		ServerSendEvent( EVENT_PROJECT_DECAL, &msg, true, -1 );
	}

	if ( time >= gameLocal.time ) {
		// try to get the sound from the damage def
		const idDeclEntityDef *damageDef = NULL;
		const idSoundShader *sndShader = NULL;
		if ( damageDefName ) {
			damageDef = gameLocal.FindEntityDef( damageDefName, false );
			if ( damageDef ) {
				sndShader = declManager->FindSound( damageDef->dict.GetString( "snd_shatter", "" ) );
			}
		}

		if ( sndShader ) {
			StartSoundShader( sndShader, SND_CHANNEL_ANY, 0, false, NULL );
		} else {
			StartSound( "snd_bullethole", SND_CHANNEL_ANY, 0, false, NULL );
		}
	}

	a = gameLocal.random.RandomFloat() * idMath::TWO_PI;
	c = cos( a );
	s = -sin( a );

	axis[2] = -dir;
	axis[2].Normalize();
	axis[2].NormalVectors( axistemp[0], axistemp[1] );
	axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * s;
	axis[1] = axistemp[ 0 ] * s + axistemp[ 1 ] * -c;

	textureAxis[0] = axis[0] * ( 1.0f / decalSize );
	textureAxis[0][3] = -( point * textureAxis[0].Normal() ) + 0.5f;

	textureAxis[1] = axis[1] * ( 1.0f / decalSize );
	textureAxis[1][3] = -( point * textureAxis[1].Normal() ) + 0.5f;

	for ( i = 0; i < shards.Num(); i++ ) {
		idFixedWinding &winding = shards[i]->winding;
		origin = shards[i]->clipModel->GetOrigin();
		axis = shards[i]->clipModel->GetAxis();
		float d0, d1;

		clipBits = -1;
		for ( j = 0; j < winding.GetNumPoints(); j++ ) {
			idVec3 p = origin + winding[j].ToVec3() * axis;

			st[j].x = d0 = textureAxis[0].Distance( p );
			st[j].y = d1 = textureAxis[1].Distance( p );

			bits = FLOATSIGNBITSET( d0 );
			d0 = 1.0f - d0;
			bits |= FLOATSIGNBITSET( d1 ) << 2;
			d1 = 1.0f - d1;
			bits |= FLOATSIGNBITSET( d0 ) << 1;
			bits |= FLOATSIGNBITSET( d1 ) << 3;

			clipBits &= bits;
		}

		if ( clipBits ) {
			continue;
		}

		idFixedWinding *decal = new idFixedWinding;
		shards[i]->decals.Append( decal );

		decal->SetNumPoints( winding.GetNumPoints() );
		for ( j = 0; j < winding.GetNumPoints(); j++ ) {
			(*decal)[j].ToVec3() = winding[j].ToVec3();
			(*decal)[j].s = st[j].x;
			(*decal)[j].t = st[j].y;
		}
	}

	BecomeActive( TH_UPDATEVISUALS );
}
Exemple #12
0
void CMeleeWeapon::TestParry( CMeleeWeapon *other, idVec3 dir, trace_t *trace )
{
	CMeleeStatus *pStatus = &m_Owner.GetEntity()->m_MeleeStatus;
	CMeleeStatus *pOthStatus = &other->GetOwner()->m_MeleeStatus;

	EMeleeType otherType = other->GetMeleeType();
	if( !(m_MeleeType == MELEETYPE_UNBLOCKABLE)
			&& (otherType == MELEETYPE_BLOCKALL || otherType == m_MeleeType ) )
	{
		// parry was succesful
		// TODO: Play bounce animation or reverse attack animation?

		// message the attacking AI
		pStatus->m_ActionResult = MELEERESULT_AT_PARRIED;
		pStatus->m_ActionPhase = MELEEPHASE_RECOVERING;
		DeactivateAttack();

		// Hack: Play metal sound for now
		const idSoundShader *snd = declManager->FindSound( "sword_hit_metal" );
		StartSoundShader( snd, SND_CHANNEL_BODY2, 0, true, NULL );
		// TODO: Propagate sound to AI
		DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("Parry was successful\r");

		// update the AI that parried
		// TODO: What happens if they decide to keep parrying, should result
		// change back to IN_PROGRESS?
		pOthStatus->m_ActionResult = MELEERESULT_PAR_BLOCKED;

		if (other->m_bParryStopOnSuccess)
			other->DeactivateParry();

		// Parrying an attack can cause flat-footedness in AI
		if( other->GetOwner()->IsType(idAI::Type) )
		{
			idAI *otherAI = static_cast<idAI *>(other->GetOwner());
			
			if( otherAI->m_bCanBeFlatFooted )
			{
				int num = otherAI->m_FlatFootParryNum;
				int max = otherAI->m_FlatFootParryMax;

				// Only the first few parries induce flatness, then a timer kicks in
				bool bCanAdd = num < max;
				bool bTimerDone = (gameLocal.time - otherAI->m_FlatFootParryTimer) > otherAI->m_FlatFootParryTime;

				if( bCanAdd )
				{
					otherAI->m_bFlatFooted = true;
					otherAI->m_FlatFootedTimer = gameLocal.time;

					otherAI->m_FlatFootParryNum++;
				}
				else if( bTimerDone )
				{
					otherAI->m_bFlatFooted = true;
					otherAI->m_FlatFootedTimer = gameLocal.time;

					// reset to flat-footed parry #1 again
					otherAI->m_FlatFootParryNum = 1;
				}

				// Each successful parry after the max number resets the timer
				// This is a gameplay tweak so the player can't just spam attack
				// They must wait until the AI hasn't parried in a while and 'surprise' them again
				if( otherAI->m_FlatFootParryNum == max )
				{
					otherAI->m_FlatFootParryTimer = gameLocal.time;
				}
			}
		}
	}
	else
	{
		// Parry failed

		DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("Parry failed, attack type was %d, parry type was %d\r", m_MeleeType, other->GetMeleeType() );

		pOthStatus->m_ActionResult = MELEERESULT_PAR_FAILED;
		// Try disabling this parry now that it has failed
		other->DeactivateParry();
		// May run into problems later when multiple opponents are attacking,
		// if one grazes the parry (but no the player), it would deactivate the parry
		// rendering it unable to block a matching attack from another AI
		// this is probably not that important, 
		// and could be seen as the other AI beating the blade away

		// TODO: Make the player weapon auto-stop the parry in this case
	}
}
Exemple #13
0
void CMeleeWeapon::MeleeCollision( idEntity *other, idVec3 dir, trace_t *tr, int location )
{
	const char *DamageDefName;
	const idDict *DmgDef;
	float push(0.0f), DmgScale(1.0f);
	idVec3 impulse(vec3_zero);
	idStr hitSound, sndName, surfType;

	DamageDefName = spawnArgs.GetString( va("def_damage_%s", m_ActionName.c_str()) );
	DmgDef = gameLocal.FindEntityDefDict( DamageDefName, false );

	if( !DmgDef )
	{
		DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeWeapon: Did not find damage def %s\r", DamageDefName);
		return;
	}

	// Apply physical impulse
	push = DmgDef->GetFloat( "push" );
	impulse = -push * tr->c.normal;
	// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Applying impulse\r");
	other->ApplyImpulse( this, tr->c.id, tr->c.point, impulse );
	// uncomment for physics debugging
	// gameRenderWorld->DebugArrow( colorBlue, tr->c.point, tr->c.point + impulse, 3, 1000 );

	// get type of material hit (armor, etc)
	int type;
	if( tr->c.material != NULL )
	{
		type = tr->c.material->GetSurfaceType();
	}
	else
	{
		type = SURFTYPE_NONE;
	}

	if ( type == SURFTYPE_NONE )
	{
		// use a default surface type if we are unable to detect one
		surfType = DmgDef->GetString("default_surface_inanimate");
	}
	else
		g_Global.GetSurfName( tr->c.material, surfType );

	// scale the damage by owner's ability and surface type hit
	DmgScale *= m_Owner.GetEntity()->m_MeleeDamageMult;
	DmgScale *= DmgDef->GetFloat( va("damage_mult_%s",surfType.c_str()), "1.0" );

	// Damage
	// Check for reroute entity (can happen with attachments to AI)
	if( other->IsType(idAFEntity_Base::Type) )
	{
		idAFEntity_Base *otherAF = static_cast<idAFEntity_Base *>(other);
		int bodID = otherAF->BodyForClipModelId( tr->c.id );
		idAFBody* StruckBody = otherAF->GetAFPhysics()->GetBody( bodID );

		if( StruckBody != NULL )
		{
			idEntity* reroute = StruckBody->GetRerouteEnt();
			if (reroute != NULL) 
			{
				// joint and clipmodel id's become invalid if we reroute, but that's okay
				other = reroute;
			}
		}
	}

	idActor *otherAct = NULL;
	if( other->IsType(idActor::Type) )
	{
		otherAct = static_cast<idActor *>(other);
	}
	else if( other->IsType(idAFAttachment::Type) )
	{
		otherAct = (idActor *) static_cast<idAFAttachment *>(other)->GetBody();
	}
	// actor-specific stuff
	if( otherAct != NULL )
	{
		// update melee status
		CMeleeStatus *pOthMeleeStatus = &otherAct->m_MeleeStatus;
		pOthMeleeStatus->m_LastHitByType = m_MeleeType;

		// switch the default surface type to that for actors
		if ( type == SURFTYPE_NONE )
		{
			// use a default surface type if we are unable to detect one
			surfType = DmgDef->GetString("default_surface_actor");
		}
	}

	if ( other->fl.takedamage )
	{
		DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeWeapon: Applying damage at clipmodel id %d, joint handle %d\r", tr->c.id, location );
		// TODO: Damage scaling - on the weapon * melee proficiency on the actor
		other->Damage
		(
			this, m_Owner.GetEntity(), 
			dir, DamageDefName,
			DmgScale, location, tr 
		);
	}

	// apply a LARGE tactile alert to AI (this must be done AFTER damage, otherwise sneak attacks are broken)
	if( other->IsType(idAI::Type) )
	{
		idAI *otherAI = static_cast<idAI *>(other);
		otherAI->TactileAlert( GetOwner(), 100 );

		// being hit always causes flat-footedness
		if( otherAI->m_bCanBeFlatFooted )
		{
			otherAI->m_bFlatFooted = true;
			otherAI->m_FlatFootedTimer = gameLocal.time;
		}
	}

	// Moved impact_damage_effect to DmgDef instead of weapon ent spawnargs
	// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Applying impact damage FX\r");
	if ( DmgDef->GetBool( "impact_damage_effect" ) ) 
	{
		// ishtvan: Rewrote this to get rid of old D3 code
		// that played the sounds in AddDamageEffect for bleeders, that doesn't make sense
		if ( other->spawnArgs.GetBool( "bleed" ) ) 
		{
			// stuff that bleeds handle smoke and decal in AddDamageEffect
			other->AddDamageEffect( *tr, impulse, DmgDef->GetString( "classname" ) );
		}

		// Handle smoke (particles), and decals
		// NOTE: AddDamageEffect above will handle all wound particles and decals (smoke_wound_*, mtr_wound_*)
		// So we only have to worry armour and other non-wounding strikes here (smoke_strike_* and mtr_strike_*)

		// Uncomment for surface type debugging
		// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Surface hit was %s\r", tr->c.material->GetName() );
		// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Material type name was %s\r", surfType.c_str() );

		// start impact sound based on material type
		// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Playing hit sound\r");
		sndName = va( "snd_%s", surfType.c_str() );
		hitSound = DmgDef->GetString( sndName );

		if ( hitSound.IsEmpty() ) 
		{
			// snd_hit is the default sound
			sndName = "snd_hit";
			hitSound = DmgDef->GetString( sndName );
		}

		// project decal 
		// ishtvan: got rid of min time between decals, let it be up to anim
		// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Displaying decal\r");
		// TODO: Make this read the surface type like smoke_strike_* ?
		const char *decal;
		decal = DmgDef->GetString( "mtr_strike" );
		if ( decal && *decal ) 
		{
			gameLocal.ProjectDecal( tr->c.point, -tr->c.normal, 8.0f, true, 6.0, decal, 0.0f, other, true );
		}

		// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Launching smoke\r");
		// Strike particle FX (sparks.. blood is handled in AddDamageEffect)
		const char *smokeName = DmgDef->GetString( va("smoke_strike_%s", surfType.c_str()) );

		if ( m_ParticlesMade < cv_melee_max_particles.GetInteger() && 
				smokeName && *smokeName != '\0' )
		{
			const idDeclParticle *smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
			float chance = DmgDef->GetFloat( va("smoke_chance_%s", surfType.c_str()), "1.0" );
			if( gameLocal.random.RandomFloat() > chance )
				smoke = NULL;

			if( smoke )
			{
				gameLocal.smokeParticles->EmitSmoke
					( 
						smoke, gameLocal.time, 
						gameLocal.random.RandomFloat(), 
						tr->c.point, -tr->endAxis
					);
				m_ParticlesMade++;
			}
		}
	}

	// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Sound playback\r");
	if ( !hitSound.IsEmpty() ) 
	{
		const idSoundShader *snd = declManager->FindSound( hitSound.c_str() );
		StartSoundShader( snd, SND_CHANNEL_BODY2, 0, true, NULL );
			
		// Propagate the sound to AI, must find global sound first because it's on a different dict
		sndName.StripLeading("snd_");
		sndName = DmgDef->GetString( va("sprS_%s", sndName.c_str()) );
		if( !sndName.IsEmpty() )
		{
			// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Propagating AI sound %s\r", sndName.c_str());
			PropSoundDirect( sndName.c_str(), false, false, 0.0f, 0 ); // grayman #3355
		}
	}
	// DM_LOG(LC_WEAPON,LT_DEBUG)LOGSTRING("MeleeCollision: Done!\r");

	return;
}
Exemple #14
0
/*
================
idEntityFx::Run
================
*/
void idEntityFx::Run( int time )
{
	int ieff, j;
	idEntity *ent = NULL;
	const idDict *projectileDef = NULL;
	idProjectile *projectile = NULL;
	
	if( !fxEffect )
	{
		return;
	}
	
	for( ieff = 0; ieff < fxEffect->events.Num(); ieff++ )
	{
		const idFXSingleAction &fxaction = fxEffect->events[ieff];
		idFXLocalAction &laction = actions[ieff];
		
		//
		// if we're currently done with this one
		//
		if( laction.start == -1 )
		{
			continue;
		}
		
		//
		// see if it's delayed
		//
		if( laction.delay )
		{
			if( laction.start + ( time - laction.start ) < laction.start + ( laction.delay * 1000 ) )
			{
				continue;
			}
		}
		
		//
		// each event can have it's own delay and restart
		//
		int actualStart = laction.delay ? laction.start + ( int )( laction.delay * 1000 ) : laction.start;
		float pct = ( float )( time - actualStart ) / ( 1000 * fxaction.duration );
		if( pct >= 1.0f )
		{
			laction.start = -1;
			float totalDelay = 0.0f;
			if( fxaction.restart )
			{
				if( fxaction.random1 || fxaction.random2 )
				{
					totalDelay = fxaction.random1 + gameLocal.random.RandomFloat() * ( fxaction.random2 - fxaction.random1 );
				}
				else
				{
					totalDelay = fxaction.delay;
				}
				laction.delay = totalDelay;
				laction.start = time;
			}
			continue;
		}
		
		if( fxaction.fire.Length() )
		{
			for( j = 0; j < fxEffect->events.Num(); j++ )
			{
				if( fxEffect->events[j].name.Icmp( fxaction.fire ) == 0 )
				{
					actions[j].delay = 0;
				}
			}
		}
		
		idFXLocalAction *useAction;
		if( fxaction.sibling == -1 )
		{
			useAction = &laction;
		}
		else
		{
			useAction = &actions[fxaction.sibling];
		}
		assert( useAction );
		
		switch( fxaction.type )
		{
			case FX_ATTACHLIGHT:
			case FX_LIGHT:
			{
				if( useAction->lightDefHandle == -1 )
				{
					if( fxaction.type == FX_LIGHT )
					{
						memset( &useAction->renderLight, 0, sizeof( renderLight_t ) );
						useAction->renderLight.origin = GetPhysics()->GetOrigin() + fxaction.offset;
						useAction->renderLight.axis = GetPhysics()->GetAxis();
						useAction->renderLight.lightRadius[0] = fxaction.lightRadius;
						useAction->renderLight.lightRadius[1] = fxaction.lightRadius;
						useAction->renderLight.lightRadius[2] = fxaction.lightRadius;
						useAction->renderLight.shader = declManager->FindMaterial( fxaction.data, false );
						useAction->renderLight.shaderParms[ SHADERPARM_RED ]	= fxaction.lightColor.x;
						useAction->renderLight.shaderParms[ SHADERPARM_GREEN ]	= fxaction.lightColor.y;
						useAction->renderLight.shaderParms[ SHADERPARM_BLUE ]	= fxaction.lightColor.z;
						useAction->renderLight.shaderParms[ SHADERPARM_TIMESCALE ]	= 1.0f;
						useAction->renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time );
						useAction->renderLight.referenceSound = refSound.referenceSound;
						useAction->renderLight.pointLight = true;
						if( fxaction.noshadows )
						{
							useAction->renderLight.noShadows = true;
						}
						useAction->lightDefHandle = gameRenderWorld->AddLightDef( &useAction->renderLight );
					}
					if( fxaction.noshadows )
					{
						for( j = 0; j < fxEffect->events.Num(); j++ )
						{
							idFXLocalAction &laction2 = actions[j];
							if( laction2.modelDefHandle != -1 )
							{
								laction2.renderEntity.noShadow = true;
							}
						}
					}
				}
				ApplyFade( fxaction, *useAction, time, actualStart );
				break;
			}
			case FX_SOUND:
			{
				if( !useAction->soundStarted )
				{
					useAction->soundStarted = true;
					const idSoundShader *shader = declManager->FindSound( fxaction.data );
					StartSoundShader( shader, SND_CHANNEL_ANY, 0, false, NULL );
					for( j = 0; j < fxEffect->events.Num(); j++ )
					{
						idFXLocalAction &laction2 = actions[j];
						if( laction2.lightDefHandle != -1 )
						{
							laction2.renderLight.referenceSound = refSound.referenceSound;
							gameRenderWorld->UpdateLightDef( laction2.lightDefHandle, &laction2.renderLight );
						}
					}
				}
				break;
			}
			case FX_DECAL:
			{
				if( !useAction->decalDropped )
				{
					useAction->decalDropped = true;
					gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetGravity(), 8.0f, true, fxaction.size, fxaction.data );
				}
				break;
			}
			case FX_SHAKE:
			{
				if( !useAction->shakeStarted )
				{
					idDict args;
					args.Clear();
					args.SetFloat( "kick_time", fxaction.shakeTime );
					args.SetFloat( "kick_amplitude", fxaction.shakeAmplitude );
					for( j = 0; j < gameLocal.numClients; j++ )
					{
						idPlayer *player = gameLocal.GetClientByNum( j );
						if( player && ( player->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).LengthSqr() < Square( fxaction.shakeDistance ) )
						{
							if( !gameLocal.isMultiplayer || !fxaction.shakeIgnoreMaster || GetBindMaster() != player )
							{
								player->playerView.DamageImpulse( fxaction.offset, &args );
							}
						}
					}
					if( fxaction.shakeImpulse != 0.0f && fxaction.shakeDistance != 0.0f )
					{
						idEntity *ignore_ent = NULL;
						if( gameLocal.isMultiplayer )
						{
							ignore_ent = this;
							if( fxaction.shakeIgnoreMaster )
							{
								ignore_ent = GetBindMaster();
							}
						}
						// lookup the ent we are bound to?
						gameLocal.RadiusPush( GetPhysics()->GetOrigin(), fxaction.shakeDistance, fxaction.shakeImpulse, this, ignore_ent, 1.0f, true );
					}
					useAction->shakeStarted = true;
				}
				break;
			}
			case FX_ATTACHENTITY:
			case FX_PARTICLE:
			case FX_MODEL:
			{
				if( useAction->modelDefHandle == -1 )
				{
					memset( &useAction->renderEntity, 0, sizeof( renderEntity_t ) );
					useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset;
					useAction->renderEntity.axis = ( fxaction.explicitAxis ) ? fxaction.axis : GetPhysics()->GetAxis();
					useAction->renderEntity.hModel = renderModelManager->FindModel( fxaction.data );
					useAction->renderEntity.shaderParms[ SHADERPARM_RED ]		= 1.0f;
					useAction->renderEntity.shaderParms[ SHADERPARM_GREEN ]		= 1.0f;
					useAction->renderEntity.shaderParms[ SHADERPARM_BLUE ]		= 1.0f;
					useAction->renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time );
					useAction->renderEntity.shaderParms[3] = 1.0f;
					useAction->renderEntity.shaderParms[5] = 0.0f;
					if( useAction->renderEntity.hModel )
					{
						useAction->renderEntity.bounds = useAction->renderEntity.hModel->Bounds( &useAction->renderEntity );
					}
					useAction->modelDefHandle = gameRenderWorld->AddEntityDef( &useAction->renderEntity );
				}
				else if( fxaction.trackOrigin )
				{
					useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset;
					useAction->renderEntity.axis = fxaction.explicitAxis ? fxaction.axis : GetPhysics()->GetAxis();
#ifdef _D3XP
					gameRenderWorld->UpdateEntityDef( useAction->modelDefHandle, &useAction->renderEntity );
#endif
				}
				ApplyFade( fxaction, *useAction, time, actualStart );
				break;
			}
			case FX_LAUNCH:
			{
				if( gameLocal.isClient )
				{
					// client never spawns entities outside of ClientReadSnapshot
					useAction->launched = true;
					break;
				}
				if( !useAction->launched )
				{
					useAction->launched = true;
					projectile = NULL;
					// FIXME: may need to cache this if it is slow
					projectileDef = gameLocal.FindEntityDefDict( fxaction.data, false );
					if( !projectileDef )
					{
						gameLocal.Warning( "projectile \'%s\' not found", fxaction.data.c_str() );
					}
					else
					{
						gameLocal.SpawnEntityDef( *projectileDef, &ent, false );
						if( ent && ent->IsType( idProjectile::Type ) )
						{
							projectile = ( idProjectile * )ent;
							projectile->Create( this, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0] );
							projectile->Launch( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0], vec3_origin );
						}
					}
				}
				break;
			}
#ifdef _D3XP
			case FX_SHOCKWAVE:
			{
				if( gameLocal.isClient )
				{
					useAction->shakeStarted = true;
					break;
				}
				if( !useAction->shakeStarted )
				{
					idStr	shockDefName;
					useAction->shakeStarted = true;
					
					shockDefName = fxaction.data;
					if( !shockDefName.Length() )
					{
						shockDefName = "func_shockwave";
					}
					
					projectileDef = gameLocal.FindEntityDefDict( shockDefName, false );
					if( !projectileDef )
					{
						gameLocal.Warning( "shockwave \'%s\' not found", shockDefName.c_str() );
					}
					else
					{
						gameLocal.SpawnEntityDef( *projectileDef, &ent );
						ent->SetOrigin( GetPhysics()->GetOrigin() + fxaction.offset );
						ent->PostEventMS( &EV_Remove, ent->spawnArgs.GetInt( "duration" ) );
					}
				}
				break;
			}
#endif
		}
	}
}