void camera_cam_use( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
	gentity_t *player;

	player = AICast_FindEntityForName( "player" );

	if ( !player ) {
		return;
	}

	if ( !( ent->spawnflags & 1 ) ) {
		ent->think = camera_cam_think;
		ent->nextthink = level.time + ( FRAMETIME / 2 );
		ent->spawnflags |= 1;
		{
			player->client->ps.persistant[PERS_HWEAPON_USE] = 1;
			player->client->ps.viewlocked = 4;
			player->client->ps.viewlocked_entNum = ent->s.number;
		}
	} else
	{
		ent->spawnflags &= ~1;
		ent->think = 0;
		{
			player->client->ps.persistant[PERS_HWEAPON_USE] = 0;
			player->client->ps.viewlocked = 0;
			player->client->ps.viewlocked_entNum = 0;
		}
	}

}
// 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 AICast_trigger_trigger(gentity_t *ent, gentity_t *activator)
{
	if(ent->nextthink)
	{
		return;     // can't retrigger until the wait is over
	}

	ent->activator = AICast_FindEntityForName(ent->aiName);

	if(ent->activator)      // they might be dead
	{
		// trigger the script event
		AICast_ScriptEvent(AICast_GetCastState(ent->activator->s.number), "trigger", ent->target);
	}

	if(ent->wait > 0)
	{
		ent->think = AICast_trigger_wait;
		ent->nextthink = level.time + (ent->wait + ent->random * crandom()) * 1000;
	}
	else
	{
		// we can't just remove (self) here, because this is a touch function
		// called while looping through area links...
		ent->touch = 0;
		ent->nextthink = level.time + FRAMETIME;
		ent->think = G_FreeEntity;
	}
}
void reset_players_pos( gentity_t *ent, gentity_t *other, gentity_t *activator ) {

	gentity_t *player;

	player = AICast_FindEntityForName( "player" );

	if ( !player ) {
		return;
	}

	trap_UnlinkEntity( player );

	VectorCopy( ent->s.origin2, player->client->ps.origin );

	// save results of pmove
	BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );

	// use the precise origin for linking
	VectorCopy( player->client->ps.origin, player->r.currentOrigin );

	SetClientViewAngle( player, ent->s.angles2 );

	player->client->ps.persistant[PERS_HWEAPON_USE] = 0;
	player->client->ps.viewlocked = 0;
	player->client->ps.viewlocked_entNum = 0;

	trap_LinkEntity( player );

}
/*
==============
AIFunc_FlameZombie_Portal
==============
*/
const char *AIFunc_FlameZombie_Portal( cast_state_t *cs ) {
	gentity_t *ent = &g_entities[cs->entityNum];
	//
	if ( cs->thinkFuncChangeTime < level.time - PORTAL_ZOMBIE_SPAWNTIME ) {
		// HACK, make them aware of the player
		AICast_UpdateVisibility( &g_entities[cs->entityNum], AICast_FindEntityForName( "player" ), qfalse, qtrue );
		ent->s.time2 = 0;   // turn spawning effect off
		return AIFunc_DefaultStart( cs );
	}
	//
	return NULL;
}
void camera_cam_think( gentity_t *ent ) {
	gentity_t *player;

	player = AICast_FindEntityForName( "player" );

	if ( !player ) {
		return;
	}

	if ( ent->spawnflags & 2 ) { // tracking
		vec3_t point;

		trap_UnlinkEntity( player );

		// VectorCopy ( self->r.currentOrigin, other->client->ps.origin );
		VectorCopy( ent->r.currentOrigin, point );
		point[2] = player->client->ps.origin[2];
		VectorCopy( point, player->client->ps.origin );

		// save results of pmove
		BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );

		// use the precise origin for linking
		VectorCopy( player->client->ps.origin, player->r.currentOrigin );

		// tracking
		{
			gentity_t   *target = NULL;
			vec3_t dang;
			vec3_t vec;

			if ( ent->track ) {
				target = G_Find( NULL, FOFS( targetname ), ent->track );
			}

			if ( target ) {
				VectorSubtract( target->r.currentOrigin, ent->r.currentOrigin, vec );
				vectoangles( vec, dang );
				SetClientViewAngle( player, dang );

				VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
				VectorCopy( dang, ent->s.apos.trBase );

				trap_LinkEntity( ent );
			}
		}

		trap_LinkEntity( player );
	}

	ent->nextthink = level.time + ( FRAMETIME / 2 );
}
void mark_players_pos( gentity_t *ent, gentity_t *other, trace_t *trace ) {
	gentity_t   *player;

	player = AICast_FindEntityForName( "player" );

	if ( player == other ) {
		VectorCopy( player->r.currentOrigin, ent->s.origin2 );
		VectorCopy( player->r.currentAngles, ent->s.angles2 );

		G_UseTargets( ent, NULL );
	}

}
Exemple #7
0
/*
==============
Concussive_think
==============
*/
void Concussive_think( gentity_t *ent ) {
	gentity_t *player;
	vec3_t dir;
	vec3_t kvel;
	float grav = 24;
	vec3_t vec;
	float len;

	if ( level.time > ent->delay ) {
		ent->think = G_FreeEntity;
	}

	ent->nextthink = level.time + FRAMETIME;

	if ( g_gametype.integer == GT_SINGLE_PLAYER ) { // JPW NERVE -- in multiplayer this should be handled by ground_shaker
		player = AICast_FindEntityForName( "player" );

		if ( !player ) {
			return;
		}

		VectorSubtract( player->r.currentOrigin, ent->s.origin, vec );
		len = VectorLength( vec );

//	G_Printf ("len = %5.3f\n", len);

		if ( len > 512 ) {
			return;
		}

		VectorSet( dir, 0, 0, 1 );
		VectorScale( dir, grav, kvel );
		VectorAdd( player->client->ps.velocity, kvel, player->client->ps.velocity );

		if ( !player->client->ps.pm_time ) {
			int t;

			t = grav * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			player->client->ps.pm_time = t;
			player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}

	}
}
/*
=================
G_ScriptAction_MissionSuccess

  syntax: missionsuccess <mission_level>
=================
*/
qboolean G_ScriptAction_MissionSuccess( gentity_t *ent, const char* params ) {
	gentity_t   *player;
	vmCvar_t cvar;
	int lvl;
    const char* pString;
    char* token;

	pString = params;

	token = COM_ParseExt( &pString, qfalse );
	if ( !token[0] ) {
		G_Error( "AI Scripting: missionsuccess requires a mission_level identifier\n" );
	}

	player = AICast_FindEntityForName( "player" );
	// double check that they are still alive
	if ( player->health <= 0 ) {
		return qfalse;  // hold the script here

	}
	lvl = atoi( token );

// if you've already got it, just return.  don't need to set 'yougotmail'
	if ( player->missionObjectives & ( 1 << ( lvl - 1 ) ) ) {
		return qtrue;
	}

	player->missionObjectives |= ( 1 << ( lvl - 1 ) );  // make this bitwise

	//set g_objective<n> cvar
	trap_Cvar_Register( &cvar, va( "g_objective%i", lvl ), "1", CVAR_ROM );
	// set it to make sure
	trap_Cvar_Set( va( "g_objective%i", lvl ), "1" );

	token = COM_ParseExt( &pString, qfalse );
	if ( token[0] ) {
		if ( Q_strcasecmp( token,"nodisplay" ) ) {   // unknown command
			G_Error( "AI Scripting: missionsuccess with unknown parameter: %s\n", token );
		}
	} else {    // show on-screen information
		trap_Cvar_Set( "cg_youGotMail", "2" ); // set flag to draw icon
	}

	return qtrue;
}
Exemple #9
0
/*QUAKED target_script_trigger (1 .7 .2) (-8 -8 -8) (8 8 8)
must have an aiName
must have a target

when used it will fire its targets 
*/
void target_script_trigger_use (gentity_t *ent, gentity_t *other, gentity_t *activator )
{
	gentity_t	*player;

	if (ent->aiName) {
		player = AICast_FindEntityForName("player");
		if (player)
			AICast_ScriptEvent( AICast_GetCastState(player->s.number), "trigger", ent->target );
	}

	// DHM - Nerve :: In multiplayer, we use the brush scripting only
	if ( g_gametype.integer >= GT_WOLF && ent->scriptName ) {
		G_Script_ScriptEvent( ent, "trigger", ent->target );
	}

	G_UseTargets ( ent, other);	

}
Exemple #10
0
/*
=================
G_ScriptAction_Trigger

  syntax: trigger <aiName/scriptName> <trigger>

  Calls the specified trigger for the given ai character or script entity
=================
*/
qboolean G_ScriptAction_Trigger( gentity_t *ent, const char* params ) {
	gentity_t *trent;
    const char* pString;
    char* token;
    char name[MAX_QPATH];
    char trigger[MAX_QPATH];
	int oldId;

	// get the cast name
	pString = params;
	token = COM_ParseExt( &pString, qfalse );
	Q_strncpyz( name, token, sizeof( name ) );
	if ( !name[0] ) {
		G_Error( "G_Scripting: trigger must have a name and an identifier\n" );
	}

	token = COM_ParseExt( &pString, qfalse );
	Q_strncpyz( trigger, token, sizeof( trigger ) );
	if ( !trigger[0] ) {
		G_Error( "G_Scripting: trigger must have a name and an identifier\n" );
	}

	trent = AICast_FindEntityForName( name );
	if ( trent ) { // we are triggering an AI
				  //oldId = trent->scriptStatus.scriptId;
		AICast_ScriptEvent( AICast_GetCastState( trent->s.number ), "trigger", trigger );
		return qtrue;
	}

	// look for an entity
	trent = G_Find( &g_entities[MAX_CLIENTS], FOFS( scriptName ), name );
	if ( trent ) {
		oldId = trent->scriptStatus.scriptId;
		G_Script_ScriptEvent( trent, "trigger", trigger );
		// if the script changed, return false so we don't muck with it's variables
		return ( ( trent != ent ) || ( oldId == trent->scriptStatus.scriptId ) );
	}

	G_Error( "G_Scripting: trigger has unknown name: %s\n", name );
	return qfalse;  // shutup the compiler
}
/*
============
SP_ai_effect
============
*/
void ai_effect_think( gentity_t *ent ) {
	gentity_t *targ;

	// find the client number that uses this entity
	targ = AICast_FindEntityForName( ent->aiName );
	if ( !targ ) {
		// keep waiting until they enter, if they never do, then we have no purpose, therefore no harm can be done
		ent->think = ai_effect_think;
		ent->nextthink = level.time + 200;
		return;
		//G_Error( "ai_effect with invalid aiName at %s\n", vtos(ent->s.origin) );
	}

	// make sure the clients can use this association
	ent->s.otherEntityNum = targ->s.number;

	ent->s.eType = ET_AI_EFFECT;
	G_SetOrigin( ent, ent->s.origin );
	trap_LinkEntity( ent );
	ent->r.svFlags |= SVF_BROADCAST;    // make sure all clients are aware of this entity
}
/*
===================
G_ScriptAction_StartCam

  syntax: startcam <camera filename>
===================
*/
qboolean G_ScriptAction_StartCam( gentity_t *ent, char *params ) {
    char *pString, *token;
    gentity_t *player;

    pString = params;
    token = COM_Parse( &pString );
    if ( !token[0] ) {
        G_Error( "G_ScriptAction_Cam: filename parameter required\n" );
    }

    // turn off noclient flag
    ent->r.svFlags &= ~SVF_NOCLIENT;

    // issue a start camera command to the client
    player = AICast_FindEntityForName( "player" );
    if ( !player ) {
        G_Error( "player not found, perhaps you should give them more time to spawn in" );
    }
    trap_SendServerCommand( player->s.number, va( "startCam %s", token ) );

    return qtrue;
}
/*QUAKED truck_cam (.7 .3 .1) ? START_ON TOGGLE - -
*/
void truck_cam_touch( gentity_t *self, gentity_t *other, trace_t *trace ) {
	gentity_t *player;

	player = AICast_FindEntityForName( "player" );

	if ( player && player != other ) {
		// G_Printf ("other: %s\n", other->aiName);
		return;
	}

	if ( !self->nextTrain ) {
		self->touch = 0;
		return;
	}

	// lock the player to the moving truck
	{
		vec3_t point;

		trap_UnlinkEntity( other );

		// VectorCopy ( self->r.currentOrigin, other->client->ps.origin );
		VectorCopy( self->r.currentOrigin, point );
		point[2] = other->client->ps.origin[2];
		VectorCopy( point, other->client->ps.origin );

		// save results of pmove
		BG_PlayerStateToEntityState( &other->client->ps, &other->s, qtrue );

		// use the precise origin for linking
		VectorCopy( other->client->ps.origin, other->r.currentOrigin );

		other->client->ps.persistant[PERS_HWEAPON_USE] = 1;

		trap_LinkEntity( other );
	}

}
Exemple #14
0
/*
==================
AICast_CheckLoadGame

  at the start of a level, the game is either saved, or loaded

  we must wait for all AI to spawn themselves, and a real client to connect
==================
*/
void AICast_CheckLoadGame(void)
{
	char loading[4];
	gentity_t *ent;
	qboolean ready;

	// have we already done the save or load?
	if (!saveGamePending)
		return;

	// tell the cgame NOT to render the scene while we are waiting for things to settle
	trap_Cvar_Set( "cg_norender", "1" );

	trap_Cvar_VariableStringBuffer( "savegame_loading", loading, sizeof(loading) );

	// screen should be black if we are at this stage
	trap_SetConfigstring( CS_SCREENFADE, va("1 %i 1", level.time - 10 ) );
	reloading = qtrue;

	if (strlen( loading ) > 0 && atoi(loading) != 0)
	{
		if (!reloading && atoi(loading) == 2) {
			reloading = qtrue;	// this gets reset at the Map_Restart() since the server unloads the game dll
		}

		ready = qtrue;
		if (numSpawningCast != numcast)
			ready = qfalse;
		else if (!(ent = AICast_FindEntityForName("player")))
			ready = qfalse;
		else if (!ent->client || ent->client->pers.connected != CON_CONNECTED)
			ready = qfalse;

		if (ready) {
			trap_Cvar_Set( "cg_norender", "0" );
			saveGamePending = qfalse;

			// wait for the clients to return from faded screen
			// trap_SetConfigstring( CS_SCREENFADE, va("0 %i 1500", level.time + 500) );
			trap_SetConfigstring( CS_SCREENFADE, va("0 %i 750", level.time + 500) );
			level.reloadPauseTime = level.time + 1100;

			AICast_CastScriptThink();
		}
	} else {

		ready = qtrue;
		if (numSpawningCast != numcast)
			ready = qfalse;
		else if (!(ent = AICast_FindEntityForName("player")))
			ready = qfalse;
		else if (!ent->client || ent->client->pers.connected != CON_CONNECTED)
			ready = qfalse;

		// not loading a game, we must be in a new level, so look for some persistant data to read in, then save the game
		if (ready) {
			trap_Cvar_Set( "cg_norender", "0" );
			saveGamePending = qfalse;

			// wait for the clients to return from faded screen
			// trap_SetConfigstring( CS_SCREENFADE, va("0 %i 1500", level.time + 500) );
			trap_SetConfigstring( CS_SCREENFADE, va("0 %i 750", level.time + 500) );
			level.reloadPauseTime = level.time + 1100;

			AICast_CastScriptThink();
		}
	}
}
void Enable_Trigger_Touch( gentity_t *ent ) {
	gentity_t *targ;
	gentity_t *daent;
	trace_t tr;
	int mask = MASK_SHOT;
	int targTemp1, targTemp2;
	int entTemp1, entTemp2;
	vec3_t dir, forward, kvel;
	float angle;
	qboolean thisone = qfalse;


	// ent->touch = Touch_Multi;


	// find the client number that uses this entity
	targ = AICast_FindEntityForName( ent->aiName );
	if ( !targ ) {
		return;
	} else
	{
		// bail if GIBFLAG and targ has been jibbed
		if ( targ->health <= GIB_HEALTH  && ( ent->spawnflags & 2 ) ) {
			return;
		}

		// need to make the ent solid since it is a trigger

		entTemp1 = ent->clipmask;
		entTemp2 = ent->r.contents;

		ent->clipmask   = CONTENTS_SOLID;
		ent->r.contents = CONTENTS_SOLID;

		trap_LinkEntity( ent );

		// same with targ cause targ is dead

		targTemp1 = targ->clipmask;
		targTemp2 = targ->r.contents;

		targ->clipmask   = CONTENTS_SOLID;
		targ->r.contents = CONTENTS_SOLID;

		trap_LinkEntity( targ );

		trap_Trace( &tr, targ->client->ps.origin, targ->r.mins, targ->r.maxs, targ->client->ps.origin, targ->s.number, mask );

		if ( tr.startsolid ) {
			daent = &g_entities[ tr.entityNum ];

			if ( daent == ent ) { // wooo hooo
				multi_trigger( ent, targ );
				thisone = qtrue;
			}
		}

		// ok were done set it contents back

		ent->clipmask = entTemp1;
		ent->r.contents = entTemp2;

		trap_LinkEntity( ent );

		targ->clipmask = targTemp1;
		targ->r.contents = targTemp2;

		trap_LinkEntity( targ );

		if ( ent->s.angles2[YAW] && thisone ) {
			angle = ent->s.angles2[YAW];

			VectorClear( dir );
			VectorClear( targ->client->ps.velocity );

			dir[YAW] = angle;
			AngleVectors( dir, forward, NULL, NULL );

			VectorScale( forward, 32, kvel );
			VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );
		}
	}

}
Exemple #16
0
/*
==================
AICast_CheckLoadGame

  at the start of a level, the game is either saved, or loaded

  we must wait for all AI to spawn themselves, and a real client to connect
==================
*/
void AICast_CheckLoadGame( void ) {
    char loading[4];
    gentity_t *ent = NULL; // TTimo: VC6 'may be used without having been init'
    qboolean ready;
    cast_state_t *pcs;

    // have we already done the save or load?
    if ( !saveGamePending ) {
        return;
    }

    // tell the cgame NOT to render the scene while we are waiting for things to settle
    trap_Cvar_Set( "cg_norender", "1" );

    trap_Cvar_VariableStringBuffer( "savegame_loading", loading, sizeof( loading ) );

//	reloading = qtrue;
    trap_Cvar_Set( "g_reloading", "1" );

    if ( strlen( loading ) > 0 && atoi( loading ) != 0 ) {
        // screen should be black if we are at this stage
        trap_SetConfigstring( CS_SCREENFADE, va( "1 %i 1", level.time - 10 ) );

//		if (!reloading && atoi(loading) == 2) {
        if ( !( g_reloading.integer ) && atoi( loading ) == 2 ) {
            // (SA) hmm, this seems redundant when it sets it above...
//			reloading = qtrue;	// this gets reset at the Map_Restart() since the server unloads the game dll
            trap_Cvar_Set( "g_reloading", "1" );
        }

        ready = qtrue;
        if ( numSpawningCast != numcast ) {
            ready = qfalse;
        } else if ( !( ent = AICast_FindEntityForName( "player" ) ) ) {
            ready = qfalse;
        } else if ( !ent->client || ent->client->pers.connected != CON_CONNECTED ) {
            ready = qfalse;
        }

        if ( ready ) {
            trap_Cvar_Set( "savegame_loading", "0" ); // in-case it aborts
            saveGamePending = qfalse;
            G_LoadGame( NULL );     // always load the "current" savegame

            // RF, spawn a thinker that will enable rendering after the client has had time to process the entities and setup the display
            //trap_Cvar_Set( "cg_norender", "0" );
            ent = G_Spawn();
            ent->nextthink = level.time + 200;
            ent->think = AICast_EnableRenderingThink;

            // wait for the clients to return from faded screen
            //trap_SetConfigstring( CS_SCREENFADE, va("0 %i 1500", level.time + 500) );
            trap_SetConfigstring( CS_SCREENFADE, va( "0 %i 750", level.time + 500 ) );
            level.reloadPauseTime = level.time + 1100;

            // make sure sound fades up
            trap_SendServerCommand( -1, va( "snd_fade 1 %d", 2000 ) );  //----(SA)	added

            AICast_CastScriptThink();
        }
    } else {

        ready = qtrue;
        if ( numSpawningCast != numcast ) {
            ready = qfalse;
        } else if ( !( ent = AICast_FindEntityForName( "player" ) ) ) {
            ready = qfalse;
        } else if ( !ent->client || ent->client->pers.connected != CON_CONNECTED ) {
            ready = qfalse;
        }

        // not loading a game, we must be in a new level, so look for some persistant data to read in, then save the game
        if ( ready ) {
            G_LoadPersistant();     // make sure we save the game after we have brought across the items

            trap_Cvar_Set( "g_totalPlayTime", "0" );  // reset play time
            trap_Cvar_Set( "g_attempts", "0" );
            pcs = AICast_GetCastState( ent->s.number );
            pcs->totalPlayTime = 0;
            pcs->lastLoadTime = 0;
            pcs->attempts = 0;

            // RF, disabled, since the pregame menu turns this off after the button is pressed, this isn't
            // required here
            // RF, spawn a thinker that will enable rendering after the client has had time to process the entities and setup the display
            //trap_Cvar_Set( "cg_norender", "0" );
            //ent = G_Spawn();
            //ent->nextthink = level.time + 200;
            //ent->think = AICast_EnableRenderingThink;

            saveGamePending = qfalse;

            // wait for the clients to return from faded screen
//			trap_SetConfigstring( CS_SCREENFADE, va("0 %i 1500", level.time + 500) );
//			trap_SetConfigstring( CS_SCREENFADE, va("0 %i 750", level.time + 500) );
            // (SA) send a command that will be interpreted for both the screenfade and any other effects (music cues, pregame menu, etc)

// briefing menu will handle transition, just set a cvar for it to check for drawing the 'continue' button
            trap_SendServerCommand( -1, "rockandroll\n" );

            level.reloadPauseTime = level.time + 1100;

            AICast_CastScriptThink();
        }
    }
}
Exemple #17
0
/*
================
G_ExplodeMissile

Explode a missile without an impact
================
*/
void G_ExplodeMissile( gentity_t *ent ) {
	vec3_t dir;
	vec3_t origin;
	qboolean small = qfalse;
	qboolean zombiespit = qfalse;
	int etype;

	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
	SnapVector( origin );
	G_SetOrigin( ent, origin );

	// we don't have a valid direction, so just point straight up
	dir[0] = dir[1] = 0;
	dir[2] = 1;

	etype = ent->s.eType;

	ent->s.eType = ET_GENERAL;

	if ( !Q_stricmp( ent->classname, "props_explosion" ) ) {
		G_AddEvent( ent, EV_MISSILE_MISS_SMALL, DirToByte( dir ) );
		small = qtrue;
	}
// JPW NERVE
	else if ( !Q_stricmp( ent->classname, "air strike" ) ) {
		G_AddEvent( ent, EV_MISSILE_MISS_LARGE, DirToByte( dir ) );
		small = qfalse;
	}
// jpw
	else if ( !Q_stricmp( ent->classname, "props_explosion_large" ) ) {
		G_AddEvent( ent, EV_MISSILE_MISS_LARGE, DirToByte( dir ) );
		small = qfalse;
	} else if ( !Q_stricmp( ent->classname, "zombiespit" ) )      {
		G_AddEvent( ent, EV_SPIT_MISS, DirToByte( dir ) );
		zombiespit = qtrue;
	} else if ( !Q_stricmp( ent->classname, "flamebarrel" ) )      {
		ent->freeAfterEvent = qtrue;
		trap_LinkEntity( ent );
		return;
	} else {
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
	}

	ent->freeAfterEvent = qtrue;

	// splash damage
	if ( ent->splashDamage ) {
		if ( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, ent->splashMethodOfDeath ) ) {    //----(SA)
			if ( g_entities[ent->r.ownerNum].client ) {
				g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++;
			}
		}
	}

	trap_LinkEntity( ent );

	if ( etype == ET_MISSILE ) {
		// DHM - Nerve :: ... in single player anyway
		if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
			if ( ent->s.weapon == WP_VENOM_FULL ) { // no default impact smoke
				zombiespit = qtrue;
			} else if ( ent->s.weapon == WP_DYNAMITE || ent->s.weapon == WP_DYNAMITE2 ) {
//				// shot heard round the world...
				gentity_t *player;
				player = AICast_FindEntityForName( "player" );
				Concussive_fx( player->r.currentOrigin );
			}
		}
// JPW NERVE -- big nasty dynamite scoring section
		else {
			if ( g_gametype.integer >= GT_WOLF ) {
				if ( ent->s.weapon == WP_DYNAMITE ) { // do some scoring
// check if dynamite is in trigger_objective_info field
					vec3_t mins, maxs;
					//static vec3_t	range = { 18, 18, 18 }; // NOTE can use this to massage throw distance outside trigger field // TTimo unused
					int i,num,touch[MAX_GENTITIES];
					gentity_t   *hit;

					// NERVE - SMF - made this the actual bounding box of dynamite instead of range
					VectorAdd( ent->r.currentOrigin, ent->r.mins, mins );
					VectorAdd( ent->r.currentOrigin, ent->r.maxs, maxs );
					num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
					VectorAdd( ent->r.currentOrigin, ent->r.mins, mins );
					VectorAdd( ent->r.currentOrigin, ent->r.maxs, maxs );

					for ( i = 0 ; i < num ; i++ ) {
						hit = &g_entities[touch[i]];
						if ( !hit->target ) {
							continue;
						}

						if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) {
							continue;
						}
						if ( !strcmp( hit->classname,"trigger_objective_info" ) ) {
							if ( !( hit->spawnflags & ( AXIS_OBJECTIVE | ALLIED_OBJECTIVE ) ) ) {
								continue;
							}

							if ( ( ( hit->spawnflags & AXIS_OBJECTIVE ) && ( ent->s.teamNum == TEAM_BLUE ) ) ||
								 ( ( hit->spawnflags & ALLIED_OBJECTIVE ) && ( ent->s.teamNum == TEAM_RED ) ) ) {
								G_UseTargets( hit,ent );
								hit->think = G_FreeEntity;
								hit->nextthink = level.time + FRAMETIME;

								if ( ent->parent->client ) {
									if ( ent->s.teamNum == ent->parent->client->sess.sessionTeam ) { // make sure player hasn't changed teams -- per atvi req
										AddScore( ent->parent, hit->accuracy ); // set from map, see g_trigger
									}
								}
							}
						}
					}
				}
			}
			// give big weapons the shakey shakey
			if ( ent->s.weapon == WP_DYNAMITE || ent->s.weapon == WP_PANZERFAUST || ent->s.weapon == WP_GRENADE_LAUNCHER ||
				 ent->s.weapon == WP_GRENADE_PINEAPPLE || ent->s.weapon == WP_ROCKET_LAUNCHER || ent->s.weapon == WP_MORTAR ||
				 ent->s.weapon == WP_ARTY ) {
				Ground_Shaker( ent->r.currentOrigin, ent->splashDamage * 4 );
			}
			return;
		}
// jpw
	}


	if ( !zombiespit ) {
		gentity_t *Msmoke;

		Msmoke = G_Spawn();
		VectorCopy( ent->r.currentOrigin, Msmoke->s.origin );
		if ( small ) {
			Msmoke->s.density = 1;
		}
		Msmoke->think = M_think;
		Msmoke->nextthink = level.time + FRAMETIME;

		if ( ent->parent && !Q_stricmp( ent->parent->classname, "props_flamebarrel" ) ) {
			Msmoke->health = 10;
		} else {
			Msmoke->health = 5;
		}

		Concussive_fx( Msmoke->s.origin );
	}
}
void props_me109_think( gentity_t *self ) {

	qboolean in_PVS = qfalse;

	{
		gentity_t *player;

		player = AICast_FindEntityForName( "player" );

		if ( player ) {
			in_PVS = trap_InPVS( player->r.currentOrigin, self->s.pos.trBase );

			if ( in_PVS ) {
				self->melee->s.eType = ET_GENERAL;

				{
					float len;
					vec3_t vec;
					vec3_t forward;
					vec3_t dir;
					vec3_t point;

					VectorCopy( player->r.currentOrigin, point );
					VectorSubtract( player->r.currentOrigin, self->r.currentOrigin, vec );
					len = VectorLength( vec );
					vectoangles( vec, dir );
					AngleVectors( dir, forward, NULL, NULL );
					VectorMA( point, len * 0.1, forward, point );

					G_SetOrigin( self->melee, point );
				}
			} else
			{
				self->melee->s.eType = ET_GENERAL;
			}

			trap_LinkEntity( self->melee );
		}
	}

	Plane_Attack( self, in_PVS );

	Calc_Roll( self );

	if ( self->health < 250 ) {
		gentity_t *tent;
		vec3_t point;

		VectorCopy( self->r.currentOrigin, point );
		tent = G_TempEntity( point, EV_SMOKE );
		VectorCopy( point, tent->s.origin );
		tent->s.time = 2000;
		tent->s.time2 = 1000;
		tent->s.density = 4;
		tent->s.angles2[0] = 16;
		tent->s.angles2[1] = 48;
		tent->s.angles2[2] = 10;

		self->props_frame_state = plane_choke;
		self->health--;
	}

	if ( self->health > 0 ) {
		self->nextthink = level.time + 50;

		if ( self->props_frame_state == plane_choke ) {
			self->melee->s.loopSound = self->melee->noise_index = fpchoke_snd;
		} else if ( self->props_frame_state == plane_startup )     {
			self->melee->s.loopSound = self->melee->noise_index = fpstartup_snd;
		} else if ( self->props_frame_state == plane_idle )     {
			self->melee->s.loopSound = self->melee->noise_index = fpidle_snd;
		} else if ( self->props_frame_state == plane_flyby1 )     {
			self->melee->s.loopSound = self->melee->noise_index = fpflyby1_snd;
		} else if ( self->props_frame_state == plane_flyby2 )     {
			self->melee->s.loopSound = self->melee->noise_index = fpflyby2_snd;
		}
	} else
	{
		propExplosionLarge( self );
		self->melee->s.loopSound = self->melee->noise_index = 0;

		ExplodePlaneSndFx( self );
		G_FreeEntity( self->melee );
		G_FreeEntity( self );


	}

}
void ExplodePlaneSndFx( gentity_t *self ) {
	gentity_t   *temp;
	vec3_t dir;
	gentity_t   *part;
	int i;
	vec3_t start;

	temp = G_Spawn();

	if ( !temp ) {
		return;
	}

	G_SetOrigin( temp, self->melee->s.pos.trBase );
	G_AddEvent( temp, EV_GLOBAL_SOUND, fpexpdebris_snd );
	temp->think = G_FreeEntity;
	temp->nextthink = level.time + 10000;
	trap_LinkEntity( temp );

	// added this because plane may be parked on runway
	// we may want to add some exotic deaths to parked aircraft
	if ( self->nextTrain && self->nextTrain->spawnflags & 4 ) { // explode the plane
		// spawn the wing at the player
		gentity_t   *player;
		vec3_t vec, ang;

		player = AICast_FindEntityForName( "player" );

		if ( !player ) {
			return;
		}

		VectorSubtract( player->s.origin, self->r.currentOrigin, vec );
		vectoangles( vec, ang );
		AngleVectors( ang, dir, NULL, NULL );

		dir[2] = 1;

		VectorCopy( self->r.currentOrigin, start );

		part = fire_flamebarrel( temp, start, dir );

		if ( !part ) {
			G_Printf( "ExplodePlaneSndFx Failed to spawn part\n" );
			return;
		}

		part->s.eType = ET_FP_PARTS;

		part->s.modelindex = wing_part;

		return;
	}

	AngleVectors( self->r.currentAngles, dir, NULL, NULL );

	for ( i = 0; i < 4; i++ )
	{
		VectorCopy( self->r.currentOrigin, start );

		start[0] += crandom() * 64;
		start[1] += crandom() * 64;
		start[2] += crandom() * 32;

		part = fire_flamebarrel( temp, start, dir );

		if ( !part ) {
			continue;
		}

		part->s.eType = ET_FP_PARTS;

		if ( i == 0 ) {
			part->s.modelindex = fuse_part;
		} else if ( i == 1 ) {
			part->s.modelindex = wing_part;
		} else if ( i == 2 ) {
			part->s.modelindex = tail_part;
		} else {
			part->s.modelindex = nose_part;
		}
	}
}