Exemple #1
0
void GM_StartGloat( void )
{
	NPCS.NPC->wait = 0;
	NPC_SetSurfaceOnOff( NPCS.NPC, "torso_galakface", TURN_ON );
	NPC_SetSurfaceOnOff( NPCS.NPC, "torso_galakhead", TURN_ON );
	NPC_SetSurfaceOnOff( NPCS.NPC, "torso_eyes_mouth", TURN_ON );
	NPC_SetSurfaceOnOff( NPCS.NPC, "torso_collar", TURN_ON );
	NPC_SetSurfaceOnOff( NPCS.NPC, "torso_galaktorso", TURN_ON );

	NPC_SetAnim( NPCS.NPC, SETANIM_BOTH, BOTH_STAND2TO1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
	NPCS.NPC->client->ps.legsTimer += 500;
	NPCS.NPC->client->ps.torsoTimer += 500;
}
/*
-------------------------
NPC_Mark2_Pain
- look at what was hit and see if it should be removed from the model.
-------------------------
*/
void NPC_Mark2_Pain(gentity_t *self, gentity_t *attacker, int damage)
{
	int newBolt,i;
	int hitLoc = gPainHitLoc;
	
	NPC_Pain( self, attacker, damage );

	for (i=0;i<3;i++)
	{
		if ((hitLoc==HL_GENERIC1+i) && (self->locationDamage[HL_GENERIC1+i] > AMMO_POD_HEALTH))	// Blow it up?
		{
			if (self->locationDamage[hitLoc] >= AMMO_POD_HEALTH)
			{			
				newBolt = trap_G2API_AddBolt( self->ghoul2, 0, va("torso_canister%d",(i+1)) );
				if ( newBolt != -1 )
				{
					NPC_Mark2_Part_Explode(self,newBolt);
				}
				NPC_SetSurfaceOnOff( self, va("torso_canister%d",(i+1)), TURN_OFF );
				break;
			}
		}
	}

	G_Sound( self, CHAN_AUTO, G_SoundIndex( "sound/chars/mark2/misc/mark2_pain" ));

	// If any pods were blown off, kill him
	if (self->count > 0)
	{
		G_Damage( self, NULL, NULL, NULL, NULL, self->health, DAMAGE_NO_PROTECTION, MOD_UNKNOWN );
	}
}
/*
-------------------------
Mark1_dying
-------------------------
*/
void Mark1_dying( gentity_t *self )
{
	int	num,newBolt;

	if (self->client->ps.torsoTimer>0)
	{
		if (TIMER_Done(self,"dyingExplosion"))
		{
			num = Q_irand( 1, 3);

			// Find place to generate explosion
			if (num == 1)
			{
				num = Q_irand( 8, 10);
				newBolt = trap_G2API_AddBolt( self->ghoul2, 0, va("*flash%d",num) );
				NPC_Mark1_Part_Explode(self,newBolt);
			}
			else
			{
				num = Q_irand( 1, 6);
				newBolt = trap_G2API_AddBolt( self->ghoul2, 0, va("*torso_tube%d",num) );
				NPC_Mark1_Part_Explode(self,newBolt);
				NPC_SetSurfaceOnOff( self, va("torso_tube%d",num), TURN_OFF );
			}

			TIMER_Set( self, "dyingExplosion", Q_irand( 300, 1000 ) );
		}


		// See which weapons are there
		// Randomly fire blaster
		if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm" ))	// Is the blaster still on the model?
		{
			if (Q_irand( 1, 5) == 1)
			{
				SaveNPCGlobals();
				SetNPCGlobals( self );
				Mark1Dead_FireBlaster();
				RestoreNPCGlobals();
			}
		}

		// Randomly fire rocket
		if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "r_arm" ))	// Is the rocket still on the model?
		{
			if (Q_irand( 1, 10) == 1)
			{
				SaveNPCGlobals();
				SetNPCGlobals( self );
				Mark1Dead_FireRocket();
				RestoreNPCGlobals();
			}
		}
	}

}
/*
-------------------------
NPC_Mark1_Pain
- look at what was hit and see if it should be removed from the model.
-------------------------
*/
void NPC_Mark1_Pain(gentity_t *self, gentity_t *attacker, int damage)
{
	int newBolt,i,chance;
	int hitLoc = gPainHitLoc;
	
	NPC_Pain( self, attacker, damage );

	G_Sound( self, CHAN_AUTO, G_SoundIndex("sound/chars/mark1/misc/mark1_pain"));

	// Hit in the CHEST???
	if (hitLoc==HL_CHEST)
	{
		chance = Q_irand( 1, 4);
	
		if ((chance == 1) && (damage > 5))
		{
			NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
		}
	}
	// Hit in the left arm?
	else if ((hitLoc==HL_ARM_LT) && (self->locationDamage[HL_ARM_LT] > LEFT_ARM_HEALTH))
	{
		if (self->locationDamage[hitLoc] >= LEFT_ARM_HEALTH)	// Blow it up?
		{
			newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*flash3" );
			if ( newBolt != -1 )
			{
				NPC_Mark1_Part_Explode(self,newBolt);
			}

			NPC_SetSurfaceOnOff( self, "l_arm", TURN_OFF );
		}
	}
	// Hit in the right arm?
	else if ((hitLoc==HL_ARM_RT) && (self->locationDamage[HL_ARM_RT] > RIGHT_ARM_HEALTH))	// Blow it up?
	{
		if (self->locationDamage[hitLoc] >= RIGHT_ARM_HEALTH)
		{			
			newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*flash4" );
			if ( newBolt != -1 )
			{
				NPC_Mark1_Part_Explode( self, newBolt );
			}

			NPC_SetSurfaceOnOff( self, "r_arm", TURN_OFF );
		}
	}
	// Check ammo pods
	else
	{
		for (i=0;i<6;i++)
		{
			if ((hitLoc==HL_GENERIC1+i) && (self->locationDamage[HL_GENERIC1+i] > AMMO_POD_HEALTH))	// Blow it up?
			{
				if (self->locationDamage[hitLoc] >= AMMO_POD_HEALTH)
				{			
					newBolt = trap_G2API_AddBolt( self->ghoul2, 0, va("*torso_tube%d",(i+1)) );
					if ( newBolt != -1 )
					{
						NPC_Mark1_Part_Explode(self,newBolt);
					}
					NPC_SetSurfaceOnOff( self, va("torso_tube%d",(i+1)), TURN_OFF );
					NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
					break;
				}
			}
		}
	}

	// Are both guns shot off?
	if ((trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm" )>0) &&
		(trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "r_arm" )>0))
	{
		G_Damage(self,NULL,NULL,NULL,NULL,self->health,0,MOD_UNKNOWN);
	}
}
/*
-------------------------
NPC_BSDroid_Pain
-------------------------
*/
void NPC_Droid_Pain(gentity_t *self, gentity_t *attacker, int damage)
{
	gentity_t *other = attacker;
	int		anim;
	int		mod = gPainMOD;
	float	pain_chance;

	VectorCopy( self->NPC->lastPathAngles, self->s.angles );

	if ( self->client->NPC_class == CLASS_R5D2 )
	{
		pain_chance = NPC_GetPainChance( self, damage );

		// Put it in pain
		if ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT || random() < pain_chance )	// Spin around in pain? Demp2 always does this
		{
			// Health is between 0-30 or was hit by a DEMP2 so pop his head
			if ( !self->s.m_iVehicleNum
				&& ( self->health < 30 || mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT ) )
			{
				if (!(self->spawnflags & 2))	// Doesn't have to ALWAYSDIE
				{
					if ((self->NPC->localState != LSTATE_SPINNING) && 
						(!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "head" )))
					{
						NPC_SetSurfaceOnOff( self, "head", TURN_OFF );

						if ( self->client->ps.m_iVehicleNum )
						{
							vec3_t	up;
							AngleVectors( self->r.currentAngles, NULL, NULL, up );
							G_PlayEffectID( G_EffectIndex("chunks/r5d2head_veh"), self->r.currentOrigin, up );
						}
						else
						{
							G_PlayEffectID( G_EffectIndex("small_chunks") , self->r.currentOrigin, vec3_origin );
							G_PlayEffectID( G_EffectIndex("chunks/r5d2head"), self->r.currentOrigin, vec3_origin );
						}

						//self->s.powerups |= ( 1 << PW_SHOCKED );
						//self->client->ps.powerups[PW_SHOCKED] = level.time + 3000;
						self->client->ps.electrifyTime = level.time + 3000;

						TIMER_Set( self, "droidsmoketotal", 5000);
						TIMER_Set( self, "droidspark", 100);
						self->NPC->localState = LSTATE_SPINNING;
					}
				}
			}
			// Just give him normal pain for a little while
			else
			{
				anim = self->client->ps.legsAnim;

				if ( anim == BOTH_STAND2 )	// On two legs?
				{
					anim = BOTH_PAIN1;
				}
				else						// On three legs
				{
					anim = BOTH_PAIN2;
				}

				NPC_SetAnim( self, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );

				// Spin around in pain
				self->NPC->localState = LSTATE_SPINNING;
				TIMER_Set( self, "roam", Q_irand(1000,2000));
			} 
		}
	}
	else if (self->client->NPC_class == CLASS_MOUSE)
	{
		if ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT )
		{
			self->NPC->localState = LSTATE_SPINNING;
			//self->s.powerups |= ( 1 << PW_SHOCKED );
			//self->client->ps.powerups[PW_SHOCKED] = level.time + 3000;
			self->client->ps.electrifyTime = level.time + 3000;
		}
		else
		{
			self->NPC->localState = LSTATE_BACKINGUP;
		}

		self->NPC->scriptFlags &= ~SCF_LOOK_FOR_ENEMIES;
	}
	else if (self->client->NPC_class == CLASS_R2D2)
	{

		pain_chance = NPC_GetPainChance( self, damage );

		if ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT || random() < pain_chance )	// Spin around in pain? Demp2 always does this
		{
			// Health is between 0-30 or was hit by a DEMP2 so pop his head
			if ( !self->s.m_iVehicleNum
				&& ( self->health < 30 || mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT ) )
			{
				if (!(self->spawnflags & 2))	// Doesn't have to ALWAYSDIE
				{
					if ((self->NPC->localState != LSTATE_SPINNING) && 
						(!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "head" )))
					{
						NPC_SetSurfaceOnOff( self, "head", TURN_OFF );

						if ( self->client->ps.m_iVehicleNum )
						{
							vec3_t	up;
							AngleVectors( self->r.currentAngles, NULL, NULL, up );
							G_PlayEffectID( G_EffectIndex("chunks/r2d2head_veh"), self->r.currentOrigin, up );
						}
						else
						{
							G_PlayEffectID( G_EffectIndex("small_chunks") , self->r.currentOrigin, vec3_origin );
							G_PlayEffectID( G_EffectIndex("chunks/r2d2head"), self->r.currentOrigin, vec3_origin );
						}

						//self->s.powerups |= ( 1 << PW_SHOCKED );
						//self->client->ps.powerups[PW_SHOCKED] = level.time + 3000;
						self->client->ps.electrifyTime = level.time + 3000;

						TIMER_Set( self, "droidsmoketotal", 5000);
						TIMER_Set( self, "droidspark", 100);
						self->NPC->localState = LSTATE_SPINNING;
					}
				}
			}
			// Just give him normal pain for a little while
			else
			{
				anim = self->client->ps.legsAnim;

				if ( anim == BOTH_STAND2 )	// On two legs?
				{
					anim = BOTH_PAIN1;
				}
				else						// On three legs
				{
					anim = BOTH_PAIN2;
				}

				NPC_SetAnim( self, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );

				// Spin around in pain
				self->NPC->localState = LSTATE_SPINNING;
				TIMER_Set( self, "roam", Q_irand(1000,2000));
			}
		} 
	}
	else if ( self->client->NPC_class == CLASS_INTERROGATOR && ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT ) && other )
	{
		vec3_t dir;

		VectorSubtract( self->r.currentOrigin, other->r.currentOrigin, dir );
		VectorNormalize( dir );

		VectorMA( self->client->ps.velocity, 550, dir, self->client->ps.velocity );
		self->client->ps.velocity[2] -= 127;
	}

	NPC_Pain( self, attacker, damage);
}
Exemple #6
0
void NPC_GalakMech_Init( gentity_t *ent )
{
	if (ent->NPC->behaviorState != BS_CINEMATIC)
	{
		ent->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH;
		ent->NPC->investigateCount = ent->NPC->investigateDebounceTime = 0;
		ent->flags |= FL_SHIELDED;//reflect normal shots
		//rwwFIXMEFIXME: Support PW_GALAK_SHIELD
		//ent->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect
		//ent->fx_time = level.time;
		VectorSet( ent->r.mins, -60, -60, -24 );
		VectorSet( ent->r.maxs, 60, 60, 80 );
		ent->flags |= FL_NO_KNOCKBACK;//don't get pushed
		TIMER_Set( ent, "attackDelay", 0 );	//FIXME: Slant for difficulty levels
		TIMER_Set( ent, "flee", 0 );
		TIMER_Set( ent, "smackTime", 0 );
		TIMER_Set( ent, "beamDelay", 0 );
		TIMER_Set( ent, "noLob", 0 );
		TIMER_Set( ent, "noRapid", 0 );
		TIMER_Set( ent, "talkDebounce", 0 );

		NPC_SetSurfaceOnOff( ent, "torso_shield", TURN_ON );
		NPC_SetSurfaceOnOff( ent, "torso_galakface", TURN_OFF );
		NPC_SetSurfaceOnOff( ent, "torso_galakhead", TURN_OFF );
		NPC_SetSurfaceOnOff( ent, "torso_eyes_mouth", TURN_OFF );
		NPC_SetSurfaceOnOff( ent, "torso_collar", TURN_OFF );
		NPC_SetSurfaceOnOff( ent, "torso_galaktorso", TURN_OFF );
	}
	else
	{
//		NPC_SetSurfaceOnOff( ent, "helmet", TURN_OFF );
		NPC_SetSurfaceOnOff( ent, "torso_shield", TURN_OFF );
		NPC_SetSurfaceOnOff( ent, "torso_galakface", TURN_ON );
		NPC_SetSurfaceOnOff( ent, "torso_galakhead", TURN_ON );
		NPC_SetSurfaceOnOff( ent, "torso_eyes_mouth", TURN_ON );
		NPC_SetSurfaceOnOff( ent, "torso_collar", TURN_ON );
		NPC_SetSurfaceOnOff( ent, "torso_galaktorso", TURN_ON );
	}

}
Exemple #7
0
void GM_Dying( gentity_t *self )
{
	if ( level.time - self->s.time < 4000 )
	{//FIXME: need a real effect
		//self->s.powerups |= ( 1 << PW_SHOCKED );
		//self->client->ps.powerups[PW_SHOCKED] = level.time + 1000;
		self->client->ps.electrifyTime = level.time + 1000;
		if ( TIMER_Done( self, "dyingExplosion" ) )
		{
			int	newBolt;
			switch ( Q_irand( 1, 14 ) )
			{
			// Find place to generate explosion
			case 1:
				if (!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "r_hand" ))
				{//r_hand still there
					GM_CreateExplosion( self, trap->G2API_AddBolt(self->ghoul2, 0, "*flasha"), qtrue );
					NPC_SetSurfaceOnOff( self, "r_hand", TURN_OFF );
				}
				else if (!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "r_arm_middle" ))
				{//r_arm_middle still there
					newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*r_arm_elbow" );
					NPC_SetSurfaceOnOff( self, "r_arm_middle", TURN_OFF );
				}
				break;
			case 2:
				//FIXME: do only once?
				if (!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_hand" ))
				{//l_hand still there
					GM_CreateExplosion( self, trap->G2API_AddBolt(self->ghoul2, 0, "*flashc"), qfalse );
					NPC_SetSurfaceOnOff( self, "l_hand", TURN_OFF );
				}
				else if (!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm_wrist" ))
				{//l_arm_wrist still there
					newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*l_arm_cap_l_hand" );
					NPC_SetSurfaceOnOff( self, "l_arm_wrist", TURN_OFF );
				}
				else if (!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm_middle" ))
				{//l_arm_middle still there
					newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*l_arm_cap_l_hand" );
					NPC_SetSurfaceOnOff( self, "l_arm_middle", TURN_OFF );
				}
				else if (!trap->G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm_augment" ))
				{//l_arm_augment still there
					newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*l_arm_elbow" );
					NPC_SetSurfaceOnOff( self, "l_arm_augment", TURN_OFF );
				}
				break;
			case 3:
			case 4:
				newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*hip_fr" );
				GM_CreateExplosion( self, newBolt, qfalse );
				break;
			case 5:
			case 6:
				newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*shldr_l" );
				GM_CreateExplosion( self, newBolt, qfalse );
				break;
			case 7:
			case 8:
				newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*uchest_r" );
				GM_CreateExplosion( self, newBolt, qfalse );
				break;
			case 9:
			case 10:
				GM_CreateExplosion( self, self->client->renderInfo.headBolt, qfalse );
				break;
			case 11:
				newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*l_leg_knee" );
				GM_CreateExplosion( self, newBolt, qtrue );
				break;
			case 12:
				newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*r_leg_knee" );
				GM_CreateExplosion( self, newBolt, qtrue );
				break;
			case 13:
				newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*l_leg_foot" );
				GM_CreateExplosion( self, newBolt, qtrue );
				break;
			case 14:
				newBolt = trap->G2API_AddBolt( self->ghoul2, 0, "*r_leg_foot" );
				GM_CreateExplosion( self, newBolt, qtrue );
				break;
			}

			TIMER_Set( self, "dyingExplosion", Q_irand( 300, 1100 ) );
		}
	}
	else
	{//one final, huge explosion
		G_PlayEffectID( G_EffectIndex("galak/explode"), self->r.currentOrigin, vec3_origin );
//		G_PlayEffect( "small_chunks", self->r.currentOrigin );
//		G_PlayEffect( "env/exp_trail_comp", self->r.currentOrigin, self->currentAngles );
		self->nextthink = level.time + FRAMETIME;
		self->think = G_FreeEntity;
	}
}
Exemple #8
0
void NPC_BSGM_Default( void )
{
	if( NPCS.NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
	{
		WeaponThink( qtrue );
	}

	if ( NPCS.NPC->client->ps.stats[STAT_ARMOR] <= 0 )
	{//armor gone
	//	if ( !NPCInfo->investigateDebounceTime )
		if (0)
		{//start regenerating the armor
			NPC_SetSurfaceOnOff( NPCS.NPC, "torso_shield", TURN_OFF );
			NPCS.NPC->flags &= ~FL_SHIELDED;//no more reflections
			VectorSet( NPCS.NPC->r.mins, -20, -20, -24 );
			VectorSet( NPCS.NPC->r.maxs, 20, 20, 64 );
			NPCS.NPC->client->ps.crouchheight = NPCS.NPC->client->ps.standheight = 64;
			if ( NPCS.NPC->locationDamage[HL_GENERIC1] < GENERATOR_HEALTH )
			{//still have the generator bolt-on
				if ( NPCS.NPCInfo->investigateCount < 12 )
				{
					NPCS.NPCInfo->investigateCount++;
				}
				NPCS.NPCInfo->investigateDebounceTime = level.time + (NPCS.NPCInfo->investigateCount * 5000);
			}
		}
		else if ( NPCS.NPCInfo->investigateDebounceTime < level.time )
		{//armor regenerated, turn shield back on
			//do a trace and make sure we can turn this back on?
			trace_t	tr;
			trap->Trace( &tr, NPCS.NPC->r.currentOrigin, shieldMins, shieldMaxs, NPCS.NPC->r.currentOrigin, NPCS.NPC->s.number, NPCS.NPC->clipmask, qfalse, 0, 0 );
			if ( !tr.startsolid )
			{
				VectorCopy( shieldMins, NPCS.NPC->r.mins );
				VectorCopy( shieldMaxs, NPCS.NPC->r.maxs );
				NPCS.NPC->client->ps.crouchheight = NPCS.NPC->client->ps.standheight = shieldMaxs[2];
				NPCS.NPC->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH;
				NPCS.NPCInfo->investigateDebounceTime = 0;
				NPCS.NPC->flags |= FL_SHIELDED;//reflect normal shots
			//	NPC->fx_time = level.time;
				NPC_SetSurfaceOnOff( NPCS.NPC, "torso_shield", TURN_ON );
			}
		}
	}
	/*
	if ( NPC->client->ps.stats[STAT_ARMOR] > 0 )
	{//armor present
		NPC->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect
		NPC_SetSurfaceOnOff( NPC, "torso_shield", TURN_ON );
	}
	else
	{
		NPC_SetSurfaceOnOff( NPC, "torso_shield", TURN_OFF );
	}
	*/
	//rwwFIXMEFIXME: Allow this stuff, and again, going to have to let the client know about it.
	//Maybe a surface-off bitflag of some sort in the entity state?

	if( !NPCS.NPC->enemy )
	{//don't have an enemy, look for one
		NPC_BSGM_Patrol();
	}
	else //if ( NPC->enemy )
	{//have an enemy
		NPC_BSGM_Attack();
	}
}
Exemple #9
0
void NPC_Touch(gentity_t *self, gentity_t *other, trace_t *trace) 
{
	if(!self->NPC)
		return;

	SaveNPCGlobals();
	SetNPCGlobals( self );

	if ( self->message && self->health <= 0 )
	{//I am dead and carrying a key
		//if ( other && player && player->health > 0 && other == player )
		if (other && other->client && other->s.number < MAX_CLIENTS)
		{//player touched me
			//[CoOp]
			char *text;
			qboolean	keyTaken;
			int sendnum = -1; // ensiform - added this
			//give him my key
			if ( Q_stricmp( "goodie", self->message ) == 0 )
			{//a goodie key
				if ( (keyTaken = INV_GoodieKeyGive( other )) == qtrue )
				{
					// ensiform TODO - Add name of 'other' (who picked up key) text = va("cp \"%s^7 %s\n\"", other->client->pers.netname, G_GetStringEdString("SP_INGAME", "TOOK_IMPERIAL_GOODIE_KEY2"));
					text = va("cp \"%s\n\"", G_GetStringEdString("SP_INGAME", "TOOK_IMPERIAL_GOODIE_KEY"));
					//text = "cp @SP_INGAME_TOOK_IMPERIAL_GOODIE_KEY";
					//G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_GOODIE_KEY )-bg_itemlist) );
				}
				else
				{
					sendnum = other->s.number;
					text = va("cp \"%s\n\"", G_GetStringEdString("SP_INGAME", "CANT_CARRY_GOODIE_KEY"));
					//text = "cp @SP_INGAME_CANT_CARRY_GOODIE_KEY";
				}
			}
			else
			{//a named security key
				if ( (keyTaken = INV_SecurityKeyGive( other, self->message )) == qtrue )
				{
					// ensiform TODO - Add name of 'other' (who picked up key) text = va("cp \"%s^7 %s\n\"", other->client->pers.netname, G_GetStringEdString("SP_INGAME", "TOOK_IMPERIAL_SECURITY_KEY2"));
					text = va("cp \"%s\n\"", G_GetStringEdString("SP_INGAME", "TOOK_IMPERIAL_SECURITY_KEY"));
					//text = "cp @SP_INGAME_TOOK_IMPERIAL_SECURITY_KEY";
					//G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_SECURITY_KEY )-bg_itemlist) );
				}
				else
				{
					sendnum = other->s.number;
					text = va("cp \"%s\n\"", G_GetStringEdString("SP_INGAME", "CANT_CARRY_SECURITY_KEY"));
					//text = "cp @SP_INGAME_CANT_CARRY_SECURITY_KEY";
				}
			}
			if ( keyTaken )
			{//remove my key
				NPC_SetSurfaceOnOff( self, "l_arm_key", TURN_OFF );
				//NPC_SetSurfaceOnOff( self, "l_arm_key", 0x00000002 );
				self->message = NULL;
				//FIXME: temp pickup sound
				G_Sound( other, CHAN_AUTO, G_SoundIndex( "sound/weapons/key_pkup.wav" ) );
				//FIXME: need some event to pass to cgame for sound/graphic/message?
			}
			//FIXME: temp message
			trap_SendServerCommand( sendnum, text );
			//trap_SendServerCommand( -1, text );
			//[/CoOp]
		}
	}

	if ( other->client ) 
	{//FIXME:  if pushing against another bot, both ucmd.rightmove = 127???
		//Except if not facing one another...
		if ( other->health > 0 ) 
		{
			NPCInfo->touchedByPlayer = other;
		}

		if ( other == NPCInfo->goalEntity ) 
		{
			NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
		}

		//[CoOp]
		//reenabling the IGNORE_ENEMIES flag
		if( /*!(self->svFlags&SVF_LOCKEDENEMY) && */!(self->NPC->scriptFlags&SCF_IGNORE_ENEMIES) && !(other->flags & FL_NOTARGET) )
		//if( /*!(self->svFlags&SVF_LOCKEDENEMY) && !(self->svFlags&SVF_IGNORE_ENEMIES) &&*/ !(other->flags & FL_NOTARGET) )
		//[/CoOp]
		{
			if ( self->client->enemyTeam )
			{//See if we bumped into an enemy
				if ( other->client->playerTeam == self->client->enemyTeam )
				{//bumped into an enemy
					if( NPCInfo->behaviorState != BS_HUNT_AND_KILL && !NPCInfo->tempBehavior )
					{//MCG - Begin: checking specific BS mode here, this is bad, a HACK
						//FIXME: not medics?
						if ( NPC->enemy != other )
						{//not already mad at them
							G_SetEnemy( NPC, other );
						}
		//				NPCInfo->tempBehavior = BS_HUNT_AND_KILL;
					}
				}
			}
		}

		//FIXME: do this if player is moving toward me and with a certain dist?
		/*
		if ( other->s.number == 0 && self->client->playerTeam == other->client->playerTeam )
		{
			VectorAdd( self->client->pushVec, other->client->ps.velocity, self->client->pushVec );
		}
		*/
	}
	else 
	{//FIXME: check for SVF_NONNPC_ENEMY flag here?
		if ( other->health > 0 ) 
		{
			//if ( NPC->enemy == other && (other->svFlags&SVF_NONNPC_ENEMY) )
			if (0) //rwwFIXMEFIXME: Can probably just check if num < MAX_CLIENTS for non-npc enemy stuff
			{
				NPCInfo->touchedByPlayer = other;
			}
		}

		if ( other == NPCInfo->goalEntity ) 
		{
			NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
		}
	}

	RestoreNPCGlobals();
	npc_push(self,other,trace);
}