Beispiel #1
0
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
"message"	text to print
"wait"		don't fire off again if triggered within this many milliseconds ago
If "private", only the activator gets the message.  If no checks, all clients get the message.
*/
void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator)
{
	if (!ent || !ent->inuse)
	{
		Com_Printf("ERROR: Bad ent in Use_Target_Print");
		return;
	}

	if (ent->wait)
	{
		if (ent->genericValue14 >= level.time)
		{
			return;
		}
		ent->genericValue14 = level.time + ent->wait;
	}

#ifndef FINAL_BUILD
	if (!ent || !ent->inuse)
	{
		Com_Error(ERR_DROP, "Bad ent in Use_Target_Print");
	}
	else if (!activator || !activator->inuse)
	{
		Com_Error(ERR_DROP, "Bad activator in Use_Target_Print");
	}

	if (ent->genericValue15 > level.time)
	{
		Com_Printf("TARGET PRINT ERRORS:\n");
		if (activator && activator->classname && activator->classname[0])
		{
			Com_Printf("activator classname: %s\n", activator->classname);
		}
		if (activator && activator->target && activator->target[0])
		{
			Com_Printf("activator target: %s\n", activator->target);
		}
		if (activator && activator->targetname && activator->targetname[0])
		{
			Com_Printf("activator targetname: %s\n", activator->targetname);
		}
		if (ent->targetname && ent->targetname[0])
		{
			Com_Printf("print targetname: %s\n", ent->targetname);
		}
		Com_Printf( "target_print used in quick succession, fix it! See the console for details." );
	}
	ent->genericValue15 = level.time + 5000;
#endif

	G_ActivateBehavior(ent,BSET_USE);
	if ( ( ent->spawnflags & 4 ) ) 
	{//private, to one client only
		if (!activator || !activator->inuse)
		{
			Com_Printf("ERROR: Bad activator in Use_Target_Print");
		}
		if ( activator && activator->client )
		{//make sure there's a valid client ent to send it to
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				trap_SendServerCommand( activator-g_entities, va("cps \"%s\"", ent->message ));
			}
			else
			{
				trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
			}
		}
		//NOTE: change in functionality - if there *is* no valid client ent, it won't send it to anyone at all
		return;
	}

	if ( ent->spawnflags & 3 ) {
		if ( ent->spawnflags & 1 ) {
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				G_TeamCommand( TEAM_RED, va("cps \"%s\"", ent->message) );
			}
			else
			{
				G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
			}
		}
		if ( ent->spawnflags & 2 ) {
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				G_TeamCommand( TEAM_BLUE, va("cps \"%s\"", ent->message) );
			}
			else
			{
				G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
			}
		}
		return;
	}

	if (ent->message[0] == '@' && ent->message[1] != '@')
	{
		trap_SendServerCommand( -1, va("cps \"%s\"", ent->message ));
	}
	else
	{
		trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
	}
}
Beispiel #2
0
void target_random_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
	int			t_count = 0, pick;
	gentity_t	*t = NULL;

	//gi.Printf("target_random %s used by %s (entnum %d)\n", self->targetname, activator->targetname, activator->s.number );
	G_ActivateBehavior(self,BSET_USE);

	if(self->spawnflags & 1)
	{
		self->e_UseFunc = useF_NULL;
	}

	while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
	{
		if (t != self)
		{
			t_count++;
		}
	}

	if(!t_count)
	{
		return;
	}

	if(t_count == 1)
	{
		G_UseTargets (self, activator);
		return;
	}

	//FIXME: need a seed
	pick = Q_irand(1, t_count);
	t_count = 0;
	while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
	{
		if (t != self)
		{
			t_count++;
		}
		else
		{
			continue;
		}

		if (t == self)
		{
//				gi.Printf ("WARNING: Entity used itself.\n");
		}
		else if(t_count == pick)
		{
			if (t->e_UseFunc != useF_NULL)	// check can be omitted
			{
				GEntity_UseFunc(t, self, activator);
				return;
			}
		}

		if (!self->inuse)
		{
			gi.Printf("entity was removed while using targets\n");
			return;
		}
	}
}
Beispiel #3
0
void scriptrunner_run (gentity_t *self)
{
	/*
	if (self->behaviorSet[BSET_USE])
	{
		char	newname[MAX_FILENAME_LENGTH];

		sprintf((char *) &newname, "%s/%s", Q3_SCRIPT_DIR, self->behaviorSet[BSET_USE] );

		ICARUS_RunScript( self, newname );
	}
	*/

	if ( self->count != -1 )
	{
		if ( self->count <= 0 )
		{
			self->e_UseFunc = useF_NULL;
			self->behaviorSet[BSET_USE] = NULL;
			return;
		}
		else
		{
			--self->count;
		}
	}

	if (self->behaviorSet[BSET_USE])
	{
		if ( self->spawnflags & 1 )
		{
			if ( !self->activator )
			{
				Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "target_scriptrunner tried to run on invalid entity!\n");
				return;
			}

			if ( self->activator->m_iIcarusID == IIcarusInterface::ICARUS_INVALID )
			{//Need to be initialized through ICARUS
				if ( !self->activator->script_targetname || !self->activator->script_targetname[0] )
				{
					//We don't have a script_targetname, so create a new one
					self->activator->script_targetname = va( "newICARUSEnt%d", numNewICARUSEnts++ );
				}

				if ( Quake3Game()->ValidEntity( self->activator ) )
				{
					Quake3Game()->InitEntity( self->activator );
				}
				else
				{
					Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "target_scriptrunner tried to run on invalid ICARUS activator!\n");
					return;
				}
			}

			Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_scriptrunner running %s on activator %s\n", self->behaviorSet[BSET_USE], self->activator->targetname );

			Quake3Game()->RunScript( self->activator, self->behaviorSet[BSET_USE] );
		}
		else
		{
			if ( self->activator )
			{
				Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_scriptrunner %s used by %s\n", self->targetname, self->activator->targetname );
			}
			G_ActivateBehavior( self, BSET_USE );
		}
	}

	if ( self->wait )
	{
		self->nextthink = level.time + self->wait;
	}
}
Beispiel #4
0
void trigger_entdist_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
	vec3_t		diff;
	gentity_t	*found = NULL;
	gentity_t	*owner = NULL;
	qboolean	useflag;
	const char	*token, *holdString;

	if ( self->svFlags & SVF_INACTIVE )	// Don't use INACTIVE
		return;

	G_ActivateBehavior(self,BSET_USE);

	if(self->ownername && self->ownername[0])
	{
		owner = G_Find(NULL, FOFS(targetname), self->ownername);
	}

	if(owner == NULL)
	{
		owner = self;
	}

	self->activator = activator;

	useflag = qfalse;

	self->svFlags |= SVF_INACTIVE;	// Make it inactive after one use

	if (self->spawnflags & ENTDIST_PLAYER)	// Look for player???
	{
		found = &g_entities[0];

		if (found)
		{	
			VectorSubtract(owner->currentOrigin, found->currentOrigin, diff);
			if(VectorLength(diff) < self->count)
			{
				useflag = qtrue;
			}
		}
	}

	if ((self->spawnflags & ENTDIST_NPC) && (!useflag))
	{
		holdString = self->NPC_target;

		while (holdString)
		{
			token = COM_Parse( &holdString);
			if ( !token ) // Nothing left to look at
			{
				break;
			}

			found = G_Find(found, FOFS(targetname), token);	// Look for the specified NPC
			if (found)	//Found???
			{	
				VectorSubtract(owner->currentOrigin, found->currentOrigin, diff);
				if(VectorLength(diff) < self->count)	// Within distance
				{
					useflag = qtrue;
					break;
				}
			}
		}
	}

	if (useflag)
	{
		G_UseTargets2 (self, self->activator, self->target);
	}
	else if (self->target2)
	{
		// This is the negative target
		G_UseTargets2 (self, self->activator, self->target2);
	}	


}
// the trigger was just activated
// ent->activator should be set to the activator so it can be held through a delay
// so wait for the delay time before firing
void multi_trigger_run( gentity_t *ent ) 
{
	ent->think = 0;

	G_ActivateBehavior( ent, BSET_USE );

	if ( ent->soundSet && ent->soundSet[0] )
	{
		trap->SetConfigstring( CS_GLOBAL_AMBIENT_SET, ent->soundSet );
	}

	if (ent->genericValue4)
	{ //we want to activate target3 for team1 or target4 for team2
		if (ent->genericValue4 == SIEGETEAM_TEAM1 &&
			ent->target3 && ent->target3[0])
		{
			G_UseTargets2(ent, ent->activator, ent->target3);
		}
		else if (ent->genericValue4 == SIEGETEAM_TEAM2 &&
			ent->target4 && ent->target4[0])
		{
			G_UseTargets2(ent, ent->activator, ent->target4);
		}

		ent->genericValue4 = 0;
	}

	G_UseTargets (ent, ent->activator);
	if ( ent->noise_index ) 
	{
		G_Sound( ent->activator, CHAN_AUTO, ent->noise_index );
	}

	if ( ent->target2 && ent->target2[0] && ent->wait >= 0 )
	{
		ent->think = trigger_cleared_fire;
		ent->nextthink = level.time + ent->speed;
	}
	else if ( ent->wait > 0 ) 
	{
		if ( ent->painDebounceTime != level.time )
		{//first ent to touch it this frame
			//ent->e_ThinkFunc = thinkF_multi_wait;
			ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
			ent->painDebounceTime = level.time;
		}
	} 
	else if ( ent->wait < 0 )
	{
		// we can't just remove (self) here, because this is a touch function
		// called while looping through area links...
		ent->r.contents &= ~CONTENTS_TRIGGER;//so the EntityContact trace doesn't have to be done against me
		ent->think = 0;
		ent->use = 0;
		//Don't remove, Icarus may barf?
		//ent->nextthink = level.time + FRAMETIME;
		//ent->think = G_FreeEntity;
	}
	if( ent->activator && ent->activator->client )
	{	// mark the trigger as being touched by the player
		ent->aimDebounceTime = level.time;
	}
}
Beispiel #6
0
void scriptrunner_run (gentity_t *self)
{
	if ( self->count != -1 )
	{
		if ( self->count <= 0 )
		{
			self->use = 0;
			self->behaviorSet[BSET_USE] = NULL;
			return;
		}
		else
		{
			--self->count;
		}
	}

	if (self->behaviorSet[BSET_USE])
	{
		if ( self->spawnflags & 1 )
		{
			if ( !self->activator )
			{
				if (g_developer.integer)
				{
					Com_Printf("target_scriptrunner tried to run on invalid entity!\n");
				}
				return;
			}

			//if ( !self->activator->sequencer || !self->activator->taskManager )
			if (!trap_ICARUS_IsInitialized(self->s.number))
			{//Need to be initialized through ICARUS
				if ( !self->activator->script_targetname || !self->activator->script_targetname[0] )
				{
					//We don't have a script_targetname, so create a new one
					self->activator->script_targetname = va( "newICARUSEnt%d", numNewICARUSEnts++ );
				}

				if ( trap_ICARUS_ValidEnt( self->activator ) )
				{
					trap_ICARUS_InitEnt( self->activator );
				}
				else
				{
					if (g_developer.integer)
					{
						Com_Printf("target_scriptrunner tried to run on invalid ICARUS activator!\n");
					}
					return;
				}
			}

			if (g_developer.integer)
			{
				Com_Printf( "target_scriptrunner running %s on activator %s\n", self->behaviorSet[BSET_USE], self->activator->targetname );
			}
			trap_ICARUS_RunScript( self->activator, va( "%s/%s", Q3_SCRIPT_DIR, self->behaviorSet[BSET_USE] ) );
		}
		else
		{
			if ( g_developer.integer && self->activator )
			{
				Com_Printf( "target_scriptrunner %s used by %s\n", self->targetname, self->activator->targetname );
			}
			G_ActivateBehavior( self, BSET_USE );
		}
	}

	if ( self->wait )
	{
		self->nextthink = level.time + self->wait;
	}
}
Beispiel #7
0
void target_level_change_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
	G_ActivateBehavior(self,BSET_USE);

	trap_SendConsoleCommand(EXEC_NOW, va("map %s", self->message));
}
Beispiel #8
0
/*
===============
NPC_ExecuteBState

  MCG

NPC Behavior state thinking

===============
*/
void NPC_ExecuteBState ( gentity_t *self)//, int msec ) 
{
	bState_t	bState;

	NPC_HandleAIFlags();

	//FIXME: these next three bits could be a function call, some sort of setup/cleanup func
	//Lookmode must be reset every think cycle
	if(NPC->delayScriptTime && NPC->delayScriptTime <= level.time)
	{
		G_ActivateBehavior( NPC, BSET_DELAYED);
		NPC->delayScriptTime = 0;
	}

	//Clear this and let bState set it itself, so it automatically handles changing bStates... but we need a set bState wrapper func
	NPCInfo->combatMove = qfalse;

	//Execute our bState
	if(NPCInfo->tempBehavior)
	{//Overrides normal behavior until cleared
		bState = NPCInfo->tempBehavior;
	}
	else
	{
		if(!NPCInfo->behaviorState)
			NPCInfo->behaviorState = NPCInfo->defaultBehavior;

		bState = NPCInfo->behaviorState;
	}

	//Pick the proper bstate for us and run it
	NPC_RunBehavior( self->client->playerTeam, bState );
	
	if ( NPC->enemy )
	{
		if ( !NPC->enemy->inuse )
		{//just in case bState doesn't catch this
			G_ClearEnemy( NPC );
		}
	}

	if ( NPC->client->ps.saberLockTime && NPC->client->ps.saberLockEnemy != ENTITYNUM_NONE )
	{
		NPC_SetLookTarget( NPC, NPC->client->ps.saberLockEnemy, level.time+1000 );
	}
	else if ( !NPC_CheckLookTarget( NPC ) )
	{
		if ( NPC->enemy )
		{
			NPC_SetLookTarget( NPC, NPC->enemy->s.number, 0 );
		}
	}

	if ( NPC->enemy )
	{
		if(NPC->enemy->flags & FL_DONT_SHOOT)
		{
			ucmd.buttons &= ~BUTTON_ATTACK;
			ucmd.buttons &= ~BUTTON_ALT_ATTACK;
		}
		else if ( NPC->client->playerTeam != NPCTEAM_ENEMY && NPC->enemy->NPC && (NPC->enemy->NPC->surrenderTime > level.time || (NPC->enemy->NPC->scriptFlags&SCF_FORCED_MARCH)) )
		{//don't shoot someone who's surrendering if you're a good guy
			ucmd.buttons &= ~BUTTON_ATTACK;
			ucmd.buttons &= ~BUTTON_ALT_ATTACK;
		}

		if(client->ps.weaponstate == WEAPON_IDLE)
		{
			client->ps.weaponstate = WEAPON_READY;
		}
	}
	else 
	{
		if(client->ps.weaponstate == WEAPON_READY)
		{
			client->ps.weaponstate = WEAPON_IDLE;
		}
	}

	if(!(ucmd.buttons & BUTTON_ATTACK) && NPC->attackDebounceTime > level.time)
	{//We just shot but aren't still shooting, so hold the gun up for a while
		if(client->ps.weapon == WP_SABER )
		{//One-handed
			NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY1,SETANIM_FLAG_NORMAL);
		}
		else if(client->ps.weapon == WP_BRYAR_PISTOL)
		{//Sniper pose
			NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY3,SETANIM_FLAG_NORMAL);
		}
		}
	else if ( !NPC->enemy )//HACK!
	{
		{
			if( NPC->s.torsoAnim == TORSO_WEAPONREADY1 || NPC->s.torsoAnim == TORSO_WEAPONREADY3 )
			{//we look ready for action, using one of the first 2 weapon, let's rest our weapon on our shoulder
				NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONIDLE3,SETANIM_FLAG_NORMAL);
			}
		}
	}

	NPC_CheckAttackHold();
	NPC_ApplyScriptFlags();
	
	//cliff and wall avoidance
	NPC_AvoidWallsAndCliffs();

	// run the bot through the server like it was a real client
//=== Save the ucmd for the second no-think Pmove ============================
	ucmd.serverTime = level.time - 50;
	memcpy( &NPCInfo->last_ucmd, &ucmd, sizeof( usercmd_t ) );
	if ( !NPCInfo->attackHoldTime )
	{
		NPCInfo->last_ucmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK);//so we don't fire twice in one think
	}
//============================================================================
	NPC_CheckAttackScript();
	NPC_KeepCurrentFacing();

	if ( !NPC->next_roff_time || NPC->next_roff_time < level.time )
	{//If we were following a roff, we don't do normal pmoves.
		ClientThink( NPC->s.number, &ucmd );
	}
	else
	{
		NPC_ApplyRoff();
	}

	// end of thinking cleanup
	NPCInfo->touchedByPlayer = NULL;

	NPC_CheckPlayerAim();
	NPC_CheckAllClear();
		}
Beispiel #9
0
/*
===============
NPC_ExecuteBState

  MCG

NPC Behavior state thinking

===============
*/
void NPC_ExecuteBState ( gentity_t *self)//, int msec ) 
{
	bState_t	bState;

	NPC_HandleAIFlags();

	//FIXME: these next three bits could be a function call, some sort of setup/cleanup func
	//Lookmode must be reset every think cycle
	if(NPC->aimDebounceTime < level.time)
	{
		NPCInfo->lookMode = LT_NONE;
	}

	if(NPC->delayScriptTime && NPC->delayScriptTime <= level.time)
	{
		G_ActivateBehavior( NPC, BSET_DELAYED);
		NPC->delayScriptTime = 0;
	}

	//Clear this and let bState set it itself, so it automatically handles changing bStates... but we need a set bState wrapper func
	NPCInfo->combatMove = qfalse;

	//Execute our bState
	if(NPCInfo->tempBehavior)
	{//Overrides normal behavior until cleared
		bState = NPCInfo->tempBehavior;
	}
	else
	{
		if(!NPCInfo->behaviorState)
			NPCInfo->behaviorState = NPCInfo->defaultBehavior;

		bState = NPCInfo->behaviorState;
	}

	//Pick the proper bstate for us and run it
	NPC_RunBehavior( self->client->playerTeam, bState );
	
	//FIXME: Make these a func call
	if(bState != BS_FORMATION)
	{//So we know to re-acquire our closest squadpath point
		self->NPC->lastSquadPoint = -1;
//		NPCInfo->aiFlags |= NPCAI_OFF_PATH;
	}

	if(bState != BS_POINT_COMBAT && NPCInfo->combatPoint != -1)
	{
		//level.combatPoints[NPCInfo->combatPoint].occupied = qfalse;
		//NPCInfo->combatPoint = -1;
	}

	//Here we need to see what the scripted stuff told us to do
//Only process snapshot if independant and in combat mode- this would pick enemies and go after needed items
//	ProcessSnapshot();

//Ignore my needs if I'm under script control- this would set needs for items
//	CheckSelf();

	//Back to normal?  All decisions made?
	
	//FIXME: don't walk off ledges unless we can get to our goal faster that way, or that's our goal's surface
	//NPCPredict();

	if ( NPC->enemy )
	{
		if ( !NPC->enemy->inuse )
		{//just in case bState doesn't catch this
			G_ClearEnemy( NPC );
		}
	}

	if ( !NPC_CheckLookTarget( NPC ) )
	{
		if ( NPC->enemy )
		{
			if ( NPC->client->ps.weapon != WP_IMPERIAL_BLADE && NPC->client->ps.weapon != WP_KLINGON_BLADE )
			{//looking right at enemy during melee looks odd
				NPC_SetLookTarget( NPC, NPC->enemy->s.number, 0 );
			}
		}
	}

	if ( NPC->enemy )
	{
		if(NPC->enemy->flags & FL_DONT_SHOOT)
		{
			ucmd.buttons &= ~BUTTON_ATTACK;
		}

		if(client->ps.weaponstate == WEAPON_IDLE)
		{
			client->ps.weaponstate = WEAPON_READY;
		}
	}
	else 
	{
		if(client->ps.weaponstate == WEAPON_READY)
		{
			client->ps.weaponstate = WEAPON_IDLE;
		}
	}

	if(!(ucmd.buttons & BUTTON_ATTACK) && NPC->attackDebounceTime > level.time)
	{//We just shot but aren't still shooting, so hold the gun up for a while
		if(client->ps.weapon == WP_PHASER )
		{//One-handed
			NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY1,SETANIM_FLAG_NORMAL);
		}
		else if(client->ps.weapon == WP_COMPRESSION_RIFLE)
		{//Sniper pose
			NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY2,SETANIM_FLAG_NORMAL);
		}
		/*//FIXME: What's the proper solution here?
		else
		{//heavy weapon
			NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY3,SETANIM_FLAG_NORMAL);
		}
		*/
	}
	else if (!NPC->enemy && bState != BS_FORMATION)//HACK!
	{
		if(client->ps.weapon != WP_TRICORDER)
		{
			if((NPC->s.torsoAnim&~ANIM_TOGGLEBIT) == TORSO_WEAPONREADY1 || (NPC->s.torsoAnim&~ANIM_TOGGLEBIT) == TORSO_WEAPONREADY2)
			{//we look ready for action, using one of the first 2 weapon, let's rest our weapon on our shoulder
				NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONIDLE1,SETANIM_FLAG_NORMAL);
			}
		}
	}

	NPC_CheckAttackHold();
	NPC_ApplyScriptFlags();
	
	//cliff and wall avoidance
	NPC_AvoidWallsAndCliffs();

	// run the bot through the server like it was a real client
//=== Save the ucmd for the second no-think Pmove ============================
	ucmd.serverTime = level.time - 50;
	NPCInfo->last_ucmd = ucmd;
	if ( !NPCInfo->attackHoldTime )
	{
		NPCInfo->last_ucmd.buttons &= ~BUTTON_ATTACK;//so we don't fire twice in one think
	}
//============================================================================
	NPC_CheckAttackScript();
	NPC_KeepCurrentFacing();

	if ( !NPC->next_roff_time || NPC->next_roff_time < level.time )
	{//If we were following a roff, we don't do normal pmoves.
		ClientThink( NPC->s.number, &ucmd );
	}
	else
	{
		NPC_ApplyRoff();
	}
	//Had to leave this in, some legacy code must still be using s.angles
	//Shouldn't interfere with interpolation of angles, should it?
	VectorCopy( client->ps.viewangles, NPC->currentAngles );

	// end of thinking cleanup
	NPCInfo->touchedByPlayer = NULL;

	NPC_CheckPlayerAim();
	NPC_CheckAllClear();
	
	/*if( ucmd.forwardmove || ucmd.rightmove )
	{
		int	i, la = -1, ta = -1;

		for(i = 0; i < MAX_ANIMATIONS; i++)
		{
			if((NPC->client->ps.legsAnim&~ANIM_TOGGLEBIT) == i)
			{
				la = i;
			}

			if((NPC->client->ps.torsoAnim&~ANIM_TOGGLEBIT) == i)
			{
				ta = i;
			}
			
			if(la != -1 && ta != -1)
			{
				break;
			}
		}

		if(la != -1 && ta != -1)
		{//FIXME: should never play same frame twice or restart an anim before finishing it
			gi.Printf("LegsAnim: %s(%d) TorsoAnim: %s(%d)\n", animTable[la].name, NPC->renderInfo.legsFrame, animTable[ta].name, NPC->client->renderInfo.torsoFrame);
		}
	}*/
}
Beispiel #10
0
//----------------------------------------------------------
void emplaced_gun_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
	vec3_t fwd1, fwd2;

	if ( self->health <= 0 )
	{
		// can't use a dead gun.
		return;
	}

	if ( self->svFlags & SVF_INACTIVE )
	{
		return; // can't use inactive gun
	}

	if ( !activator->client )
	{
		return; // only a client can use it.
	}

	if ( self->activator )
	{
		// someone is already in the gun.
		return;
	}

	if ( other && other->client && G_IsRidingVehicle( other ) )
	{//can't use eweb when on a vehicle
		return;
	}

	if ( activator && activator->client && G_IsRidingVehicle( activator ) )
	{//can't use eweb when on a vehicle
		return;
	}

	// We'll just let the designers duke this one out....I mean, as to whether they even want to limit such a thing.
	if ( self->spawnflags & EMPLACED_FACING )
	{
		// Let's get some direction vectors for the users
		AngleVectors( activator->client->ps.viewangles, fwd1, NULL, NULL );

		// Get the guns direction vector
		AngleVectors( self->pos1, fwd2, NULL, NULL );

		float dot = DotProduct( fwd1, fwd2 );

		// Must be reasonably facing the way the gun points ( 90 degrees or so ), otherwise we don't allow to use it.
		if ( dot < 0.0f )
		{
			return;
		}
	}

	// don't allow using it again for half a second
	if ( self->delay + 500 < level.time )
	{
		int	oldWeapon = activator->s.weapon;

		if ( oldWeapon == WP_SABER )
		{
			self->alt_fire = activator->client->ps.SaberActive();
		}

		// swap the users weapon with the emplaced gun and add the ammo the gun has to the player
		activator->client->ps.weapon = self->s.weapon;
		Add_Ammo( activator, WP_EMPLACED_GUN, self->count );
		activator->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_EMPLACED_GUN );

		// Allow us to point from one to the other
		activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
		self->activator = activator;

		G_RemoveWeaponModels( activator );

extern void ChangeWeapon( gentity_t *ent, int newWeapon );
		if ( activator->NPC )
		{
			ChangeWeapon( activator, WP_EMPLACED_GUN );
		}
		else if ( activator->s.number == 0 )
		{
			// we don't want for it to draw the weapon select stuff
			cg.weaponSelect = WP_EMPLACED_GUN;
			CG_CenterPrint( "@SP_INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 );
		}
		// Since we move the activator inside of the gun, we reserve a solid spot where they were standing in order to be able to get back out without being in solid
		if ( self->nextTrain )
		{//you never know
			G_FreeEntity( self->nextTrain );
		}
		self->nextTrain = G_Spawn();
		//self->nextTrain->classname = "emp_placeholder";
		self->nextTrain->contents = CONTENTS_MONSTERCLIP|CONTENTS_PLAYERCLIP;//hmm... playerclip too now that we're doing it for NPCs?
		G_SetOrigin( self->nextTrain, activator->client->ps.origin );
		VectorCopy( activator->mins, self->nextTrain->mins );
		VectorCopy( activator->maxs, self->nextTrain->maxs );
		gi.linkentity( self->nextTrain );

		//need to inflate the activator's mins/maxs since the gunsit anim puts them outside of their bbox
		VectorSet( activator->mins, -24, -24, -24 );
		VectorSet( activator->maxs, 24, 24, 40 );

		// Move the activator into the center of the gun.  For NPC's the only way the can get out of the gun is to die.
		VectorCopy( self->s.origin, activator->client->ps.origin );
		activator->client->ps.origin[2] += 30; // move them up so they aren't standing in the floor
		gi.linkentity( activator );

		// the gun will track which weapon we used to have
		self->s.weapon = oldWeapon;

		// Lock the player
		activator->client->ps.eFlags |= EF_LOCKED_TO_WEAPON;
		activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
		self->activator = activator;
		self->delay = level.time; // can't disconnect from the thing for half a second

		// Let the gun be considered an enemy
		//Ugh, so much AI code seems to assume enemies are clients, maybe this shouldn't be on, but it's too late in the game to change it now without knowing what side-effects this will have
		self->svFlags |= SVF_NONNPC_ENEMY;
		self->noDamageTeam = activator->client->playerTeam;

		// FIXME: don't do this, we'll try and actually put the player in this beast
		// move the player to the center of the gun
//		activator->contents = 0;
//		VectorCopy( self->currentOrigin, activator->client->ps.origin );

		SetClientViewAngle( activator, self->pos1 );

		//FIXME: should really wait a bit after spawn and get this just once?
		self->waypoint = NAV::GetNearestNode(self);
#ifdef _DEBUG
		if ( self->waypoint == -1 )
		{
			gi.Printf( S_COLOR_RED"ERROR: no waypoint for emplaced_gun %s at %s\n", self->targetname, vtos(self->currentOrigin) );
		}
#endif

		G_Sound( self, G_SoundIndex( "sound/weapons/emplaced/emplaced_mount.mp3" ));

		if ( !(self->spawnflags&EMPLACED_PLAYERUSE) || activator->s.number == 0 )
		{//player-only usescript or any usescript
			// Run use script
			G_ActivateBehavior( self, BSET_USE );
		}
	}
}
Beispiel #11
0
//----------------------------------------------------------
void emplaced_gun_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc )
{
	vec3_t org;

	// turn off any firing animations it may have been doing
	self->s.frame = self->startFrame = self->endFrame = 0;
	self->svFlags &= ~SVF_ANIMATING;
			
	self->health = 0;
//	self->s.weapon = WP_EMPLACED_GUN; // we need to be able to switch back to the old weapon

	self->takedamage = qfalse;
	self->lastEnemy = attacker;

	// we defer explosion so the player has time to get out
	if ( self->e_DieFunc )
	{
		self->e_ThinkFunc = thinkF_emplaced_blow;
		self->nextthink = level.time + 3000; // don't blow for a couple of seconds
		return;
	}

	if ( self->activator && self->activator->client )
	{
		if ( self->activator->NPC )
		{
			vec3_t right;

			// radius damage seems to throw them, but add an extra bit to throw them away from the weapon
			AngleVectors( self->currentAngles, NULL, right, NULL );
			VectorMA( self->activator->client->ps.velocity, 140, right, self->activator->client->ps.velocity );
			self->activator->client->ps.velocity[2] = -100;

			// kill them
			self->activator->health = 0;
			self->activator->client->ps.stats[STAT_HEALTH] = 0;
		}

		// kill the players emplaced ammo, cheesy way to keep the gun from firing
		self->activator->client->ps.ammo[weaponData[WP_EMPLACED_GUN].ammoIndex] = 0;
	}

	self->e_PainFunc = painF_NULL;
	self->e_ThinkFunc = thinkF_NULL;

	if ( self->target )
	{
		G_UseTargets( self, attacker );
	}

	G_RadiusDamage( self->currentOrigin, self, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN );

	// when the gun is dead, add some ugliness to it.
	vec3_t ugly;

	ugly[YAW] = 4;
	ugly[PITCH] = self->lastAngles[PITCH] * 0.8f + crandom() * 6;
	ugly[ROLL] = crandom() * 7;
	gi.G2API_SetBoneAnglesIndex( &self->ghoul2[self->playerModel], self->lowerLumbarBone, ugly, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, 0, 0 ); 

	VectorCopy( self->currentOrigin,  org );
	org[2] += 20;

	G_PlayEffect( "emplaced/explode", org );

	// create some persistent smoke by using a dynamically created fx runner
	gentity_t *ent = G_Spawn();

	if ( ent )
	{
		ent->delay = 200;
		ent->random = 100;

		ent->fxID = G_EffectIndex( "emplaced/dead_smoke" );

		ent->e_ThinkFunc = thinkF_fx_runner_think; 
		ent->nextthink = level.time + 50;

		// move up above the gun origin
		VectorCopy( self->currentOrigin, org );
		org[2] += 35;
		G_SetOrigin( ent, org );
		VectorCopy( org, ent->s.origin );

		VectorSet( ent->s.angles, -90, 0, 0 ); // up
		G_SetAngles( ent, ent->s.angles );

		gi.linkentity( ent );
	}

	G_ActivateBehavior( self, BSET_DEATH );
}
Beispiel #12
0
void eweb_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
	if ( !eweb_can_be_used( self, other, activator ) )
	{
		return;
	}

	int	oldWeapon = activator->s.weapon;

	if ( oldWeapon == WP_SABER )
	{
		self->alt_fire = activator->client->ps.SaberActive();
	}

	// swap the users weapon with the emplaced gun and add the ammo the gun has to the player
	activator->client->ps.weapon = self->s.weapon;
	Add_Ammo( activator, WP_EMPLACED_GUN, self->count );
	activator->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_EMPLACED_GUN );

	// Allow us to point from one to the other
	activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
	self->activator = activator;

	G_RemoveWeaponModels( activator );

extern void ChangeWeapon( gentity_t *ent, int newWeapon );
	if ( activator->NPC )
	{
		ChangeWeapon( activator, WP_EMPLACED_GUN );
	}
	else if ( activator->s.number == 0 )
	{
		// we don't want for it to draw the weapon select stuff
		cg.weaponSelect = WP_EMPLACED_GUN;
		CG_CenterPrint( "@SP_INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 );
	}

	VectorCopy( activator->currentOrigin, self->pos4 );//keep this around so we know when to make them play the strafe anim

	// the gun will track which weapon we used to have
	self->s.weapon = oldWeapon;

	// Lock the player
	activator->client->ps.eFlags |= EF_LOCKED_TO_WEAPON;
	activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
	self->activator = activator;
	self->delay = level.time; // can't disconnect from the thing for half a second

	// Let the gun be considered an enemy
	//Ugh, so much AI code seems to assume enemies are clients, maybe this shouldn't be on, but it's too late in the game to change it now without knowing what side-effects this will have
	self->svFlags |= SVF_NONNPC_ENEMY;
	self->noDamageTeam = activator->client->playerTeam;

	//FIXME: should really wait a bit after spawn and get this just once?
	self->waypoint = NAV::GetNearestNode(self);
#ifdef _DEBUG
	if ( self->waypoint == -1 )
	{
		gi.Printf( S_COLOR_RED"ERROR: no waypoint for emplaced_gun %s at %s\n", self->targetname, vtos(self->currentOrigin) );
	}
#endif

	G_Sound( self, G_SoundIndex( "sound/weapons/eweb/eweb_mount.mp3" ));

	if ( !(self->spawnflags&EMPLACED_PLAYERUSE) || activator->s.number == 0 )
	{//player-only usescript or any usescript
		// Run use script
		G_ActivateBehavior( self, BSET_USE );
	}
}
Beispiel #13
0
//----------------------------------------------------------
void eweb_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc )
{
	vec3_t org;

	// turn off any firing animations it may have been doing
	self->s.frame = self->startFrame = self->endFrame = 0;
	self->svFlags &= ~(SVF_ANIMATING|SVF_PLAYER_USABLE);
	
			
	self->health = 0;
//	self->s.weapon = WP_EMPLACED_GUN; // we need to be able to switch back to the old weapon

	self->takedamage = qfalse;
	self->lastEnemy = attacker;

	if ( self->activator && self->activator->client )
	{
		if ( self->activator->NPC )
		{
			vec3_t right;

			// radius damage seems to throw them, but add an extra bit to throw them away from the weapon
			AngleVectors( self->currentAngles, NULL, right, NULL );
			VectorMA( self->activator->client->ps.velocity, 140, right, self->activator->client->ps.velocity );
			self->activator->client->ps.velocity[2] = -100;

			// kill them
			self->activator->health = 0;
			self->activator->client->ps.stats[STAT_HEALTH] = 0;
		}

		// kill the players emplaced ammo, cheesy way to keep the gun from firing
		self->activator->client->ps.ammo[weaponData[WP_EMPLACED_GUN].ammoIndex] = 0;
	}

	self->e_PainFunc = painF_NULL;

	if ( self->target )
	{
		G_UseTargets( self, attacker );
	}

	G_RadiusDamage( self->currentOrigin, self, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN );

	VectorCopy( self->currentOrigin,  org );
	org[2] += 20;

	G_PlayEffect( "emplaced/explode", org );

	// Turn the top of the eweb off.
#define TURN_OFF			0x00000100//G2SURFACEFLAG_NODESCENDANTS
	gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "eweb_damage", TURN_OFF );

	// create some persistent smoke by using a dynamically created fx runner
	gentity_t *ent = G_Spawn();

	if ( ent )
	{
		ent->delay = 200;
		ent->random = 100;

		ent->fxID = G_EffectIndex( "emplaced/dead_smoke" );

		ent->e_ThinkFunc = thinkF_fx_runner_think; 
		ent->nextthink = level.time + 50;

		// move up above the gun origin
		VectorCopy( self->currentOrigin, org );
		org[2] += 35;
		G_SetOrigin( ent, org );
		VectorCopy( org, ent->s.origin );

		VectorSet( ent->s.angles, -90, 0, 0 ); // up
		G_SetAngles( ent, ent->s.angles );

		gi.linkentity( ent );
	}

	G_ActivateBehavior( self, BSET_DEATH );
}
Beispiel #14
0
/*
===================
G_SpawnGEntityFromSpawnVars

Spawn an entity and fill in all of the level fields from
level.spawnVars[], then call the class specfic spawn function
===================
*/
void G_SpawnGEntityFromSpawnVars( qboolean inSubBSP ) {
	int			i;
	gentity_t	*ent;
	char		*s, *value, *gametypeName;
	static char *gametypeNames[] = {"ffa", "holocron", "jedimaster", "duel", "powerduel", "single", "team", "siege", "ctf", "cty"};

	// get the next free entity
	ent = G_Spawn();

	for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
		G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
	}

	// check for "notsingle" flag
	if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
		G_SpawnInt( "notsingle", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	}
	// check for "notteam" flag (GT_FFA, GT_DUEL, GT_SINGLE_PLAYER)
	if ( g_gametype.integer >= GT_TEAM ) {
		G_SpawnInt( "notteam", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	} else {
		G_SpawnInt( "notfree", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	}

	if( G_SpawnString( "gametype", NULL, &value ) ) {
		if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
			gametypeName = gametypeNames[g_gametype.integer];

			s = strstr( value, gametypeName );
			if( !s ) {
				ADJUST_AREAPORTAL();
				G_FreeEntity( ent );
				return;
			}
		}
	}

	// move editor origin to pos
	VectorCopy( ent->s.origin, ent->s.pos.trBase );
	VectorCopy( ent->s.origin, ent->r.currentOrigin );

	// if we didn't get a classname, don't bother spawning anything
	if ( !G_CallSpawn( ent ) ) {
		G_FreeEntity( ent );
	}

	//Tag on the ICARUS scripting information only to valid recipients
	if ( trap_ICARUS_ValidEnt( ent ) )
	{
		trap_ICARUS_InitEnt( ent );

		if ( ent->classname && ent->classname[0] )
		{
			if ( Q_strncmp( "NPC_", ent->classname, 4 ) != 0 )
			{//Not an NPC_spawner (rww - probably don't even care for MP, but whatever)
				G_ActivateBehavior( ent, BSET_SPAWN );
			}
		}
	}
}
Beispiel #15
0
/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
Kills the activator.
*/
void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
	G_ActivateBehavior(self,BSET_USE);
	G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
}
Beispiel #16
0
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
"message"	text to print
"wait"		don't fire off again if triggered within this many milliseconds ago
If "private", only the activator gets the message.  If no checks, all clients get the message.
*/
void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator)
{
	if (!ent || !ent->inuse)
	{
		Com_Printf("ERROR: Bad ent in Use_Target_Print");
		return;
	}

	if (ent->wait)
	{
		if (ent->genericValue14 >= level.time)
		{
			return;
		}
		ent->genericValue14 = level.time + ent->wait;
	}

#ifndef FINAL_BUILD
	if (!ent || !ent->inuse)
	{
		Com_Error(ERR_DROP, "Bad ent in Use_Target_Print");
	}
	else if (!activator || !activator->inuse)
	{
		Com_Error(ERR_DROP, "Bad activator in Use_Target_Print");
	}
#endif

	G_ActivateBehavior(ent,BSET_USE);
	if ( ( ent->spawnflags & 4 ) ) 
	{//private, to one client only
		if (!activator || !activator->inuse)
		{
			Com_Printf("ERROR: Bad activator in Use_Target_Print");
		}
		if ( activator && activator->client )
		{//make sure there's a valid client ent to send it to
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				trap_SendServerCommand( activator-g_entities, va("cps \"%s\"", ent->message ));
			}
			else
			{
				trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
			}
		}
		//NOTE: change in functionality - if there *is* no valid client ent, it won't send it to anyone at all
		return;
	}

	if ( ent->spawnflags & 3 ) {
		if ( ent->spawnflags & 1 ) {
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				G_TeamCommand( TEAM_RED, va("cps \"%s\"", ent->message) );
			}
			else
			{
				G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
			}
		}
		if ( ent->spawnflags & 2 ) {
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				G_TeamCommand( TEAM_BLUE, va("cps \"%s\"", ent->message) );
			}
			else
			{
				G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
			}
		}
		return;
	}

	if (ent->message[0] == '@' && ent->message[1] != '@')
	{
		trap_SendServerCommand( -1, va("cps \"%s\"", ent->message ));
	}
	else
	{
		trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
	}
}
Beispiel #17
0
void target_random_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
	int			t_count = 0, pick;
	gentity_t	*t = NULL;

	G_ActivateBehavior(self,BSET_USE);

	if(self->spawnflags & 1)
	{
		self->use = 0;
	}

	while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
	{
		if (t != self)
		{
			t_count++;
		}
	}

	if(!t_count)
	{
		return;
	}

	if(t_count == 1)
	{
		G_UseTargets (self, activator);
		return;
	}

	//FIXME: need a seed
	pick = Q_irand(1, t_count);
	t_count = 0;
	while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
	{
		if (t != self)
		{
			t_count++;
		}
		else
		{
			continue;
		}
		
		if (t == self)
		{
		}
		else if(t_count == pick)
		{
			if (t->use != NULL)	// check can be omitted
			{
				GlobalUse(t, self, activator);
				return;
			}
		}

		if (!self->inuse)
		{
			Com_Printf("entity was removed while using targets\n");
			return;
		}
	}
}
Beispiel #18
0
/*
===============
NPC_Pain
===============
*/
void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod, int hitLoc ) 
{
	team_t otherTeam = TEAM_FREE;
	int		voiceEvent = -1;

	if ( self->NPC == NULL ) 
		return;

	if ( other == NULL ) 
		return;

	//or just remove ->pain in player_die?
	if ( self->client->ps.pm_type == PM_DEAD )
		return;

	if ( other == self ) 
		return;

	other = G_CheckControlledTurretEnemy(self, other, qfalse);
	if (!other)
	{
		return;
	}

	//MCG: Ignore damage from your own team for now
	if ( other->client )
	{
		otherTeam = other->client->playerTeam;
	//	if ( otherTeam == TEAM_DISGUISE )
	//	{
	//		otherTeam = TEAM_PLAYER;
	//	}
	}

	if ( self->client->playerTeam 
		&& other->client 
		&& otherTeam == self->client->playerTeam 
		&& (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity)) 
	{//hit by a teammate
		if ( other != self->enemy && self != other->enemy )
		{//we weren't already enemies
			if ( self->enemy || other->enemy 
				|| (other->s.number&&other->s.number!=player->client->ps.viewEntity) 
				/*|| (!other->s.number&&Q_irand( 0, 3 ))*/ )
			{//if one of us actually has an enemy already, it's okay, just an accident OR wasn't hit by player or someone controlled by player OR player hit ally and didn't get 25% chance of getting mad (FIXME:accumulate anger+base on diff?)
				//FIXME: player should have to do a certain amount of damage to ally or hit them several times to make them mad
				//Still run pain and flee scripts
				if ( self->client && self->NPC )
				{//Run any pain instructions
					if ( self->health <= (self->max_health/3) && G_ActivateBehavior(self, BSET_FLEE) )
					{
						
					}
					else// if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
					{
						G_ActivateBehavior(self, BSET_PAIN);
					}
				}
				if ( damage != -1 )
				{//-1 == don't play pain anim
					//Set our proper pain animation
					if ( Q_irand( 0, 1 ) )
					{
						NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
					}
					else
					{
						NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc );
					}
				}
				return;
			}
			else if ( self->NPC && !other->s.number )//should be assumed, but...
			{//dammit, stop that!
				if ( self->NPC->charmedTime > level.time )
				{//mindtricked
					return;
				}
				else if ( self->NPC->ffireCount < 3+((2-g_spskill->integer)*2) )
				{//not mad enough yet
					//Com_Printf( "chck: %d < %d\n", self->NPC->ffireCount, 3+((2-g_spskill->integer)*2) );
					if ( damage != -1 )
					{//-1 == don't play pain anim
						//Set our proper pain animation
						if ( Q_irand( 0, 1 ) )
						{
							NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
						}
						else
						{
							NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc );
						}
					}
					return;
				}
				else if ( G_ActivateBehavior( self, BSET_FFIRE ) )
				{//we have a specific script to run, so do that instead
					return;
				}
				else
				{//okay, we're going to turn on our ally, we need to set and lock our enemy and put ourselves in a bstate that lets us attack him (and clear any flags that would stop us)
					self->NPC->blockedSpeechDebounceTime = 0;
					voiceEvent = EV_FFTURN;
					self->NPC->behaviorState = self->NPC->tempBehavior = self->NPC->defaultBehavior = BS_DEFAULT;
					other->flags &= ~FL_NOTARGET;
					self->svFlags &= ~(SVF_IGNORE_ENEMIES|SVF_ICARUS_FREEZE|SVF_NO_COMBAT_SOUNDS);
					G_SetEnemy( self, other );
					self->svFlags |= SVF_LOCKEDENEMY;
					self->NPC->scriptFlags &= ~(SCF_DONT_FIRE|SCF_CROUCHED|SCF_WALKING|SCF_NO_COMBAT_TALK|SCF_FORCED_MARCH);
					self->NPC->scriptFlags |= (SCF_CHASE_ENEMIES|SCF_NO_MIND_TRICK);
					//NOTE: we also stop ICARUS altogether
					stop_icarus = qtrue;
					if ( !killPlayerTimer )
					{
						killPlayerTimer = level.time + 10000;
					}
				}
			}
		}
	}

	SaveNPCGlobals();
	SetNPCGlobals( self );

	//Do extra bits
	if ( NPCInfo->ignorePain == qfalse )
	{
		NPCInfo->confusionTime = 0;//clear any charm or confusion, regardless
		if ( NPC->ghoul2.size() && NPC->headBolt != -1 )
		{
			G_StopEffect("force/confusion", NPC->playerModel, NPC->headBolt, NPC->s.number );
		}
		if ( damage != -1 )
		{//-1 == don't play pain anim
			//Set our proper pain animation
			NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, voiceEvent );
		}
		//Check to take a new enemy
		if ( NPC->enemy != other && NPC != other )
		{//not already mad at them
			//if it's an eweb or emplaced gun, get mad at the owner, not the gun
			NPC_CheckAttacker( other, mod );
		}
	}

	//Attempt to run any pain instructions
	if ( self->client && self->NPC )
	{
		//FIXME: This needs better heuristics perhaps
		if(self->health <= (self->max_health/3) && G_ActivateBehavior(self, BSET_FLEE) )
		{
		}
		else //if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
		{
			G_ActivateBehavior(self, BSET_PAIN);
		}
	}

	//Attempt to fire any paintargets we might have
	if( self->paintarget && self->paintarget[0] )
	{
		G_UseTargets2(self, other, self->paintarget);
	}

	if (self->client && self->client->NPC_class==CLASS_BOBAFETT)
	{
		Boba_Pain( self, inflictor, damage, mod);
	}


	RestoreNPCGlobals();
}
Beispiel #19
0
void target_deactivate_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
	G_ActivateBehavior(self,BSET_USE);

	G_SetActiveState(self->target, ACT_INACTIVE);
}
Beispiel #20
0
void func_usable_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{//Toggle on and off
	if ( other == activator )
	{//directly used by use button trace
		if ( (self->spawnflags&32) )
		{//only usable by NPCs
			if ( activator->NPC == NULL )
			{//Not an NPC
				return;
			}
		}
	}

	G_ActivateBehavior( self, BSET_USE );
	if ( self->s.eFlags & EF_SHADER_ANIM )
	{//animate shader when used
		self->s.frame++;//inc frame
		if ( self->s.frame > self->endFrame )
		{//wrap around
			self->s.frame = 0;
		}
		if ( self->target && self->target[0] )
		{
			G_UseTargets( self, activator );
		}
	}
	else if ( self->spawnflags & 8 )
	{//ALWAYS_ON
		//Remove the ability to use the entity directly
		self->svFlags &= ~SVF_PLAYER_USABLE;
		//also remove ability to call any use func at all!
		self->e_UseFunc = useF_NULL;
		
		if(self->target && self->target[0])
		{
			G_UseTargets(self, activator);
		}
		
		if ( self->wait )
		{
			self->e_ThinkFunc = thinkF_func_usable_think;
			self->nextthink = level.time + ( self->wait * 1000 );
		}

		return;
	}
	else if ( !self->count )
	{//become solid again
		self->count = 1;
		self->activator = activator;
		func_wait_return_solid( self );
	}
	else
	{
		//NOTE: MUST do this BEFORE clearing contents, or you may not open the area portal!!!
		if ( !(self->spawnflags&1) )
		{//START_OFF doesn't effect area portals
			gi.AdjustAreaPortalState( self, qtrue );
		}
		self->s.solid = 0;
		self->contents = 0;
		self->clipmask = 0;
		self->svFlags |= SVF_NOCLIENT;
		self->s.eFlags |= EF_NODRAW;
		self->count = 0;

		if(self->target && self->target[0])
		{
			G_UseTargets(self, activator);
		}
		self->e_ThinkFunc = thinkF_NULL;
		self->nextthink = -1;
	}
}
Beispiel #21
0
void target_play_music_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
	G_ActivateBehavior(self,BSET_USE);
	trap_SetConfigstring( CS_MUSIC, self->message );
}
Beispiel #22
0
/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
"count" number of points to add, default 1

The activator is given this many points.
*/
void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator)
{
	G_ActivateBehavior(ent,BSET_USE);

	AddScore( activator, ent->count );
}
Beispiel #23
0
void misc_model_breakable_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath,int dFlags,int hitLoc ) 
{
	int		numChunks;
	float	size = 0, scale;
	vec3_t	dir, up, dis;

	//NOTE: Stop any scripts that are currently running (FLUSH)... ?
	//Turn off animation
	self->s.frame = self->startFrame = self->endFrame = 0;
	self->svFlags &= ~SVF_ANIMATING;
			
	self->health = 0;

	//Throw some chunks
	AngleVectors( self->s.apos.trBase, dir, NULL, NULL );
	VectorNormalize( dir );

	numChunks = random() * 6 + 20;

	VectorSubtract( self->absmax, self->absmin, dis );

	// This formula really has no logical basis other than the fact that it seemed to be the closest to yielding the results that I wanted.
	// Volume is length * width * height...then break that volume down based on how many chunks we have
	scale = sqrt( sqrt( dis[0] * dis[1] * dis[2] )) * 1.75f;

	if ( scale > 48 )
	{
		size = 2;
	}
	else if ( scale > 24 )
	{
		size = 1;
	}

	scale = scale / numChunks;

	if ( self->radius > 0.0f )
	{
		// designer wants to scale number of chunks, helpful because the above scale code is far from perfect
		//	I do this after the scale calculation because it seems that the chunk size generally seems to be very close, it's just the number of chunks is a bit weak
		numChunks *= self->radius;
	}

	VectorAdd( self->absmax, self->absmin, dis );
	VectorScale( dis, 0.5f, dis );

	CG_Chunks( self->s.number, dis, dir, self->absmin, self->absmax, 300, numChunks, self->material, self->s.modelindex3, scale );

	self->e_PainFunc = painF_NULL;
	self->e_DieFunc  = dieF_NULL;
//	self->e_UseFunc  = useF_NULL;

	self->takedamage = qfalse;

	if ( !(self->spawnflags & 4) )
	{//We don't want to stay solid
		self->s.solid = 0;
		self->contents = 0;
		self->clipmask = 0;
		gi.linkentity(self);
	}

	VectorSet(up, 0, 0, 1);

	if(self->target)
	{
		G_UseTargets(self, attacker);
	}

	if(inflictor->client)
	{
		VectorSubtract( self->currentOrigin, inflictor->currentOrigin, dir );
		VectorNormalize( dir );
	}
	else
	{
		VectorCopy(up, dir);
	}

	if ( !(self->spawnflags & 2048) ) // NO_EXPLOSION
	{
		// Ok, we are allowed to explode, so do it now!
		if(self->splashDamage > 0 && self->splashRadius > 0)
		{//explode
			vec3_t org;
			AddSightEvent( attacker, self->currentOrigin, 256, AEL_DISCOVERED, 100 );
			AddSoundEvent( attacker, self->currentOrigin, 128, AEL_DISCOVERED );
			//FIXME: specify type of explosion?  (barrel, electrical, etc.)  Also, maybe just use the explosion effect below since it's
			//				a bit better?
			// up the origin a little for the damage check, because several models have their origin on the ground, so they don't alwasy do damage, not the optimal solution...
			VectorCopy( self->currentOrigin, org );
			if ( self->mins[2] > -4 )
			{//origin is going to be below it or very very low in the model
				//center the origin
				org[2] = self->currentOrigin[2] + self->mins[2] + (self->maxs[2] - self->mins[2])/2.0f;
			}
			G_RadiusDamage( org, self, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN );

			if ( self->model && Q_stricmp( "models/map_objects/ships/tie_fighter.md3", self->model ) == 0 )
			{//TEMP HACK for Tie Fighters- they're HUGE
				G_PlayEffect( "fighter_explosion2", self->currentOrigin );
				G_Sound( self, G_SoundIndex( "sound/weapons/tie_fighter/TIEexplode.wav" ) );
			}
			else
			{
				CG_MiscModelExplosion( self->absmin, self->absmax, size, self->material );
				G_Sound( self, G_SoundIndex("sound/weapons/explosions/cargoexplode.wav") );
			}
		}
		else
		{//just break
			AddSightEvent( attacker, self->currentOrigin, 128, AEL_DISCOVERED );
			AddSoundEvent( attacker, self->currentOrigin, 64, AEL_SUSPICIOUS );
			// This is the default explosion
			CG_MiscModelExplosion( self->absmin, self->absmax, size, self->material );
			G_Sound(self, G_SoundIndex("sound/weapons/explosions/cargoexplode.wav"));
		}
	}

	self->e_ThinkFunc = thinkF_NULL;
	self->nextthink = -1;

	if(self->s.modelindex2 != -1 && !(self->spawnflags & 8))
	{//FIXME: modelindex doesn't get set to -1 if the damage model doesn't exist
		self->svFlags |= SVF_BROKEN;
		self->s.modelindex = self->s.modelindex2;
		G_ActivateBehavior( self, BSET_DEATH );
	}
	else
	{
		G_FreeEntity( self );
	}
}
/*
===============
NPC_Pain
===============
*/
void NPC_Pain( gentity_t *self, gentity_t *other, int damage ) 
{
	team_t otherTeam = TEAM_FREE;

	if ( self->NPC == NULL ) 
		return;

	if ( other == NULL ) 
		return;

	//or just remove ->pain in player_die?
	if ( self->client->ps.pm_type == PM_DEAD )
		return;

	if ( other == self ) 
		return;

	//MCG: Ignore damage from your own team for now
	if ( other->client )
	{
		otherTeam = other->client->playerTeam;
		if ( otherTeam == TEAM_DISGUISE )
		{
			otherTeam = TEAM_STARFLEET;
		}
	}

	if ( other != self->enemy && self->client->playerTeam && other->client && otherTeam == self->client->playerTeam ) 
	{//Still run pain and flee scripts
		if ( self->client && self->NPC )
		{//Run any pain instructions
			if ( self->health <= (self->max_health/3) && ( VALIDSTRING( self->behaviorSet[BSET_FLEE] ) ) )
			{
				G_ActivateBehavior(self, BSET_FLEE);
			}
			else if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
			{
				G_ActivateBehavior(self, BSET_PAIN);
			}
		}
		return;
	}

	//Hirogen boss with shield
	if ( ( self->client->playerTeam == TEAM_HIROGEN ) ) 
	{
		if ( ( Q_stricmp( self->NPC_type, "hirogenalpha" ) == 0 ) && ( self->s.powerups & ( 1 << PW_HIROGEN_SHIELD ) ) )
			return;
	}

	SaveNPCGlobals();
	SetNPCGlobals( self );

	//Do extra bits
	if ( NPCInfo->ignorePain == qfalse )
	{
		//Check to take a new enemy
		NPC_CheckAttacker( other );

		if ( damage != -1 )
		{//don't play pain anim
			//Set our proper pain animation
			NPC_ChoosePainAnimation( self, damage );
		}
	}

	//Attempt to run any pain instructions
	if(self->client && self->NPC)
	{
		//FIXME: This needs better heuristics perhaps
		if(self->health <= (self->max_health/3) && ( VALIDSTRING( self->behaviorSet[BSET_FLEE] ) ) )
		{
			G_ActivateBehavior(self, BSET_FLEE);
		}
		else if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
		{
			G_ActivateBehavior(self, BSET_PAIN);
		}
	}

	//Attempt to fire any paintargets we might have
	if( self->paintarget && self->paintarget[0] )
	{
		G_UseTargets2(self, other, self->paintarget);
	}

	RestoreNPCGlobals();
}