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 ); } }
/* ============== 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; }
/*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); }
/* ================= 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 ); } }
/* ================== 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 ); } } }
/* ================== 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(); } } }
/* ================ 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; } } }