void G_Gametype_GENERIC_ClientRespawn( edict_t *self, int old_team, int new_team ) { int i; gclient_t *client = self->r.client; gs_weapon_definition_t *weapondef; if( G_ISGHOSTING( self ) ) return; //give default items if( self->s.team != TEAM_SPECTATOR ) { if( GS_Instagib() ) { client->ps.inventory[WEAP_INSTAGUN] = 1; client->ps.inventory[AMMO_INSTAS] = 1; client->ps.inventory[AMMO_WEAK_INSTAS] = 1; } else { if( GS_MatchState() <= MATCH_STATE_WARMUP ) { for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ ) { if( i == WEAP_INSTAGUN ) // dont add instagun... continue; weapondef = GS_GetWeaponDef( i ); client->ps.inventory[i] = 1; if( weapondef->firedef_weak.ammo_id ) client->ps.inventory[weapondef->firedef_weak.ammo_id] = weapondef->firedef_weak.ammo_max; if( weapondef->firedef.ammo_id ) client->ps.inventory[weapondef->firedef.ammo_id] = weapondef->firedef.ammo_max; } client->resp.armor = GS_Armor_MaxCountForTag( ARMOR_YA ); } else { weapondef = GS_GetWeaponDef( WEAP_GUNBLADE ); client->ps.inventory[WEAP_GUNBLADE] = 1; client->ps.inventory[AMMO_GUNBLADE] = weapondef->firedef.ammo_max;; client->ps.inventory[AMMO_WEAK_GUNBLADE] = 0; } } } // select rocket launcher if available if( GS_CheckAmmoInWeapon( &client->ps, WEAP_ROCKETLAUNCHER ) ) client->ps.stats[STAT_PENDING_WEAPON] = WEAP_ROCKETLAUNCHER; else client->ps.stats[STAT_PENDING_WEAPON] = GS_SelectBestWeapon( &client->ps ); // add a teleportation effect if( self->r.solid != SOLID_NOT ) G_RespawnEffect( self ); }
bool BotTacticalSpotsCache::FindCloseRangeTacticalSpot( const Vec3 &origin, const Vec3 &enemyOrigin, vec3_t result ) { TacticalSpotsRegistry::AdvantageProblemParams problemParams( enemyOrigin.Data() ); float meleeRange = GS_GetWeaponDef( WEAP_GUNBLADE )->firedef_weak.timeout; problemParams.SetMinSpotDistanceToEntity( meleeRange ); problemParams.SetMaxSpotDistanceToEntity( WorldState::CLOSE_RANGE_MAX ); problemParams.SetOriginDistanceInfluence( 0.0f ); problemParams.SetEntityDistanceInfluence( 0.7f ); problemParams.SetEntityWeightFalloffDistanceRatio( 0.8f ); problemParams.SetTravelTimeInfluence( 0.0f ); problemParams.SetMinHeightAdvantageOverOrigin( -16.0f ); problemParams.SetMinHeightAdvantageOverEntity( -16.0f ); problemParams.SetHeightOverOriginInfluence( 0.4f ); problemParams.SetHeightOverEntityInfluence( 0.9f ); // Bot should be able to retreat from close combat problemParams.SetCheckToAndBackReachability( true ); float searchRadius = WorldState::CLOSE_RANGE_MAX * 2; float distanceToEnemy = ( origin - enemyOrigin ).LengthFast(); if( distanceToEnemy > WorldState::CLOSE_RANGE_MAX ) { searchRadius += distanceToEnemy - WorldState::CLOSE_RANGE_MAX; // On this range retreating to an old position makes little sense if( distanceToEnemy > 0.5f * WorldState::MIDDLE_RANGE_MAX ) { problemParams.SetCheckToAndBackReachability( false ); } } return FindForOrigin( problemParams, origin, searchRadius, result ); }
/* * CG_OverrideWeapondef * * Compares name and tag against the itemlist to make sure cgame and game lists match */ void CG_OverrideWeapondef( int index, const char *cstring ) { int weapon, i; int firemode = FIRE_MODE_WEAK; gs_weapon_definition_t *weapondef; firedef_t *firedef; weapon = index; if( index >= (MAX_WEAPONDEFS / 2) ) { weapon -= (MAX_WEAPONDEFS / 2); firemode = FIRE_MODE_STRONG; } weapondef = GS_GetWeaponDef( weapon ); if( !weapondef ) CG_Error( "CG_OverrideWeapondef: Invalid weapon index\n" ); firedef = ( firemode == FIRE_MODE_STRONG ) ? &weapondef->firedef : &weapondef->firedef_weak; i = sscanf( cstring, "%7i %7i %7u %7u %7u %7u %7u %7i %7i", &firedef->usage_count, &firedef->projectile_count, &firedef->weaponup_time, &firedef->weapondown_time, &firedef->reload_time, &firedef->cooldown_time, &firedef->timeout, &firedef->speed, &firedef->spread ); if( i != 9 ) CG_Error( "CG_OverrideWeapondef: Bad configstring: %s \"%s\" (%i)\n", weapondef->name, cstring, i ); }
static qboolean GS_CheckBladeAutoAttack( player_state_t *playerState, int timeDelta ) { vec3_t origin, dir, end; trace_t trace; entity_state_t *targ, *player; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( WEAP_GUNBLADE ); if( playerState->POVnum <= 0 || (int)playerState->POVnum > gs.maxclients ) return qfalse; if( !( playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_GUNBLADEAUTOATTACK ) ) return qfalse; VectorCopy( playerState->pmove.origin, origin ); origin[2] += playerState->viewheight; AngleVectors( playerState->viewangles, dir, NULL, NULL ); VectorMA( origin, weapondef->firedef_weak.timeout, dir, end ); // check for a player to touch module_Trace( &trace, origin, vec3_origin, vec3_origin, end, playerState->POVnum, CONTENTS_BODY, timeDelta ); if( trace.ent <= 0 || trace.ent > gs.maxclients ) return qfalse; player = module_GetEntityState( playerState->POVnum, 0 ); targ = module_GetEntityState( trace.ent, 0 ); if( !( targ->effects & EF_TAKEDAMAGE ) || targ->type != ET_PLAYER ) return qfalse; if( GS_TeamBasedGametype() && ( targ->team == player->team ) ) return qfalse; return qtrue; }
void GS_TraceCurveLaserBeam( trace_t *trace, vec3_t origin, vec3_t angles, vec3_t blendPoint, int ignore, int timeDelta, void ( *impact )( trace_t *tr, vec3_t dir ) ) { float frac, subdivisions = CURVELASERBEAM_SUBDIVISIONS; float range = (float)GS_GetWeaponDef( WEAP_LASERGUN )->firedef_weak.timeout; vec3_t from, dir, end; int passthrough = ignore; int i, j; vec3_t tmpangles, blendAngles; assert( trace ); VectorCopy( origin, from ); VectorSubtract( blendPoint, origin, dir ); VecToAngles( dir, blendAngles ); for( i = 1; i <= (int)subdivisions; i++ ) { frac = ( ( range/subdivisions )*(float)i ) / (float)range; for( j = 0; j < 3; j++ ) tmpangles[j] = LerpAngle( angles[j], blendAngles[j], frac ); AngleVectors( tmpangles, dir, NULL, NULL ); VectorMA( origin, range * frac, dir, end ); GS_TraceLaserBeam( trace, from, tmpangles, DistanceFast( from, end ), passthrough, timeDelta, impact ); if( trace->fraction != 1.0f ) break; passthrough = trace->ent; VectorCopy( end, from ); } }
/* * CG_Event_FireRiotgun */ static void CG_Event_FireRiotgun( vec3_t origin, vec3_t dir, int weapon, int firemode, int seed, int owner ) { trace_t trace; vec3_t end; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( weapon ); firedef_t *firedef = ( firemode ) ? &weapondef->firedef : &weapondef->firedef_weak; CG_Fire_SpiralPattern( origin, dir, &seed, owner, firedef->projectile_count, firedef->spread, firedef->timeout, CG_BulletImpact ); // spawn a single sound at the impact VectorMA( origin, firedef->timeout, dir, end ); CG_Trace( &trace, origin, vec3_origin, vec3_origin, end, owner, MASK_SHOT ); if( trace.ent != -1 && !( trace.surfFlags & SURF_NOIMPACT ) ) { if( firedef->fire_mode == FIRE_MODE_STRONG ) { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRiotgunStrongHit ), trace.endpos, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); } else { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRiotgunWeakHit ), trace.endpos, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); } } }
/* * Pickup_Weapon */ bool Pickup_Weapon( edict_t *other, const gsitem_t *item, int flags, int ammo_count ) { int ammo_tag; gs_weapon_definition_t *weapondef; weapondef = GS_GetWeaponDef( item->tag ); other->r.client->ps.inventory[item->tag]++; // never allow the player to carry more than 2 copies of the same weapon if( other->r.client->ps.inventory[item->tag] > item->inventory_max ) other->r.client->ps.inventory[item->tag] = item->inventory_max; if( !(flags & DROPPED_ITEM) ) { // give them some ammo with it ammo_tag = item->ammo_tag; if( ammo_tag ) Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), weapondef->firedef.weapon_pickup, true ); } else { // it's a dropped weapon ammo_tag = item->ammo_tag; if( ammo_count && ammo_tag ) Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), ammo_count, true ); } return true; }
/* * GS_InitWeapons */ void GS_InitWeapons( void ) { int i; gsitem_t *item; gs_weapon_definition_t *weapondef; for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ ) { item = GS_FindItemByTag( i ); weapondef = GS_GetWeaponDef( i ); assert( item && weapondef ); // hack : use the firedef pickup counts on items if( item->weakammo_tag && GS_FindItemByTag( item->weakammo_tag ) ) { GS_FindItemByTag( item->weakammo_tag )->quantity = weapondef->firedef_weak.ammo_pickup; GS_FindItemByTag( item->weakammo_tag )->inventory_max = weapondef->firedef_weak.ammo_max; } if( item->ammo_tag && GS_FindItemByTag( item->ammo_tag ) ) { GS_FindItemByTag( item->ammo_tag )->quantity = weapondef->firedef.ammo_pickup; GS_FindItemByTag( item->ammo_tag )->inventory_max = weapondef->firedef.ammo_max; } } }
/* * CG_Event_WeaponBeam */ static void CG_Event_WeaponBeam( vec3_t origin, vec3_t dir, int ownerNum, int weapon, int firemode ) { gs_weapon_definition_t *weapondef; int range; vec3_t end; trace_t trace; switch( weapon ) { case WEAP_ELECTROBOLT: weapondef = GS_GetWeaponDef( WEAP_ELECTROBOLT ); range = ELECTROBOLT_RANGE; break; case WEAP_INSTAGUN: weapondef = GS_GetWeaponDef( WEAP_INSTAGUN ); range = weapondef->firedef.timeout; break; default: return; } VectorNormalizeFast( dir ); VectorMA( origin, range, dir, end ); // retrace to spawn wall impact CG_Trace( &trace, origin, vec3_origin, vec3_origin, end, cg.view.POVent, MASK_SOLID ); if( trace.ent != -1 && !(trace.surfFlags & (SURF_SKY|SURF_NOMARKS|SURF_NOIMPACT)) ) { if( weapondef->weapon_id == WEAP_ELECTROBOLT ) CG_BoltExplosionMode( trace.endpos, trace.plane.normal, FIRE_MODE_STRONG ); else if( weapondef->weapon_id == WEAP_INSTAGUN ) CG_InstaExplosionMode( trace.endpos, trace.plane.normal, FIRE_MODE_STRONG ); } // when it's predicted we have to delay the drawing until the view weapon is calculated cg_entities[ownerNum].localEffects[LOCALEFFECT_EV_WEAPONBEAM] = weapon; VectorCopy( origin, cg_entities[ownerNum].laserOrigin ); VectorCopy( trace.endpos, cg_entities[ownerNum].laserPoint ); }
/* * GS_FiredefForPlayerState */ firedef_t *GS_FiredefForPlayerState( player_state_t *playerState, int checkweapon ) { gs_weapon_definition_t *weapondef; weapondef = GS_GetWeaponDef( checkweapon ); //find out our current fire mode if( playerState->inventory[weapondef->firedef.ammo_id] >= weapondef->firedef.usage_count ) return &weapondef->firedef; return &weapondef->firedef_weak; }
void CG_Event_LaserBeam( int entNum, int weapon, int fireMode ) { centity_t *cent = &cg_entities[entNum]; unsigned int timeout; vec3_t dir; if( !cg_predictLaserBeam->integer ) return; // lasergun's smooth refire if( fireMode == FIRE_MODE_STRONG ) { cent->laserCurved = qfalse; timeout = GS_GetWeaponDef( WEAP_LASERGUN )->firedef.reload_time + 10; // find destiny point VectorCopy( cg.predictedPlayerState.pmove.origin, cent->laserOrigin ); cent->laserOrigin[2] += cg.predictedPlayerState.viewheight; AngleVectors( cg.predictedPlayerState.viewangles, dir, NULL, NULL ); VectorMA( cent->laserOrigin, GS_GetWeaponDef( WEAP_LASERGUN )->firedef.timeout, dir, cent->laserPoint ); } else { cent->laserCurved = qtrue; timeout = GS_GetWeaponDef( WEAP_LASERGUN )->firedef_weak.reload_time + 10; // find destiny point VectorCopy( cg.predictedPlayerState.pmove.origin, cent->laserOrigin ); cent->laserOrigin[2] += cg.predictedPlayerState.viewheight; if( !G_GetLaserbeamPoint( &cg.weaklaserTrail, &cg.predictedPlayerState, cg.predictingTimeStamp, cent->laserPoint ) ) { AngleVectors( cg.predictedPlayerState.viewangles, dir, NULL, NULL ); VectorMA( cent->laserOrigin, GS_GetWeaponDef( WEAP_LASERGUN )->firedef.timeout, dir, cent->laserPoint ); } } VectorCopy( cent->laserOrigin, cent->laserOriginOld ); VectorCopy( cent->laserPoint, cent->laserPointOld ); cent->localEffects[LOCALEFFECT_LASERBEAM] = cg.time + timeout; }
/* * SetItemNames * * Called by worldspawn */ void G_PrecacheItems( void ) { int i; gsitem_t *item; // precache item names and weapondefs for( i = 1; ( item = GS_FindItemByTag( i ) ) != NULL; i++ ) { trap_ConfigString( CS_ITEMS + i, item->name ); if( item->type & IT_WEAPON && GS_GetWeaponDef( item->tag ) ) { G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef ); G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef_weak ); } } // precache items if( GS_Instagib() ) { item = GS_FindItemByTag( WEAP_INSTAGUN ); PrecacheItem( item ); } else { for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ ) { item = GS_FindItemByTag( i ); PrecacheItem( item ); } } // Vic: precache ammo pack if it's droppable item = GS_FindItemByClassname( "item_ammopack" ); if( item && G_Gametype_CanDropItem( item, qtrue ) ) { PrecacheItem( item ); } }
/* * GS_SelectBestWeapon */ int GS_SelectBestWeapon( player_state_t *playerState ) { int weap, weap_chosen = WEAP_NONE; gs_weapon_definition_t *weapondef; //find with strong ammos for( weap = WEAP_TOTAL-1; weap > WEAP_GUNBLADE; weap-- ) { if( !playerState->inventory[weap] ) continue; weapondef = GS_GetWeaponDef( weap ); if( !weapondef->firedef.usage_count || playerState->inventory[weapondef->firedef.ammo_id] >= weapondef->firedef.usage_count ) { weap_chosen = weap; goto found; } } //repeat find with weak ammos for( weap = WEAP_TOTAL-1; weap >= WEAP_NONE; weap-- ) { if( !playerState->inventory[weap] ) continue; weapondef = GS_GetWeaponDef( weap ); if( !weapondef->firedef_weak.usage_count || playerState->inventory[weapondef->firedef_weak.ammo_id] >= weapondef->firedef_weak.usage_count ) { weap_chosen = weap; goto found; } } found: return weap_chosen; }
/* * Use_Weapon */ void Use_Weapon( edict_t *ent, const gsitem_t *item ) { int ammocount, weakammocount; gs_weapon_definition_t *weapondef; //invalid weapon item if( item->tag < WEAP_NONE || item->tag >= WEAP_TOTAL ) return; // see if we're already changing to it if( ent->r.client->ps.stats[STAT_PENDING_WEAPON] == item->tag ) return; weapondef = GS_GetWeaponDef( item->tag ); if( !g_select_empty->integer && !( item->type & IT_AMMO ) ) { if( weapondef->firedef.usage_count ) { if( weapondef->firedef.ammo_id ) ammocount = ent->r.client->ps.inventory[weapondef->firedef.ammo_id]; else ammocount = weapondef->firedef.usage_count; } else ammocount = 1; // can change weapon if( weapondef->firedef_weak.usage_count ) { if( weapondef->firedef_weak.ammo_id ) weakammocount = ent->r.client->ps.inventory[weapondef->firedef_weak.ammo_id]; else weakammocount = weapondef->firedef_weak.usage_count; } else weakammocount = 1; // can change weapon if( ammocount < weapondef->firedef.usage_count && weakammocount < weapondef->firedef_weak.usage_count ) { return; } } // change to this weapon when down ent->r.client->ps.stats[STAT_PENDING_WEAPON] = item->tag; }
static void WeaponString( edict_t *who, int weapon, char *buf, int buflen, const char *current_color ) { int strong_ammo, weak_ammo; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( weapon ); Q_snprintfz( buf, buflen, "%s%s%s", ( GS_FindItemByTag( weapon )->color ? GS_FindItemByTag( weapon )->color : "" ), GS_FindItemByTag( weapon )->shortname, current_color ); strong_ammo = who->r.client->ps.inventory[weapondef->firedef.ammo_id]; weak_ammo = who->r.client->ps.inventory[weapondef->firedef_weak.ammo_id]; if( weapon == WEAP_GUNBLADE ) Q_strncatz( buf, va( ":%i", strong_ammo ), buflen ); else if( strong_ammo > 0 ) Q_strncatz( buf, va( ":%i/%i", strong_ammo, weak_ammo ), buflen ); else Q_strncatz( buf, va( ":%i", weak_ammo ), buflen ); }
void GS_AddLaserbeamPoint( gs_laserbeamtrail_t *trail, player_state_t *playerState, unsigned int timeStamp ) { vec3_t origin, dir; int range = GS_GetWeaponDef( WEAP_LASERGUN )->firedef_weak.timeout; if( !timeStamp ) return; origin[0] = playerState->pmove.origin[0]; origin[1] = playerState->pmove.origin[1]; origin[2] = playerState->pmove.origin[2] + playerState->viewheight; AngleVectors( playerState->viewangles, dir, NULL, NULL ); VectorMA( origin, range, dir, trail->origins[trail->head & LASERGUN_WEAK_TRAIL_MASK] ); trail->timeStamps[trail->head & LASERGUN_WEAK_TRAIL_MASK] = timeStamp; trail->teleported[trail->head & LASERGUN_WEAK_TRAIL_MASK] = ( playerState->pmove.pm_flags & PMF_TIME_TELEPORT ) ? qtrue : qfalse; trail->head++; }
static void CG_Event_FireMachinegun( vec3_t origin, vec3_t dir, int weapon, int firemode, int seed, int owner ) { float r, u; double alpha, s; trace_t trace, *water_trace; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( weapon ); firedef_t *firedef = ( firemode ) ? &weapondef->firedef : &weapondef->firedef_weak; int range = firedef->timeout, spread = firedef->spread; // circle shape alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI] s = fabs( Q_crandom( &seed ) ); // [0..1] r = s * cos( alpha ) * spread; u = s * sin( alpha ) * spread; water_trace = GS_TraceBullet( &trace, origin, dir, r, u, range, owner, 0 ); if( water_trace ) { if( !VectorCompare( water_trace->endpos, origin ) ) CG_LeadWaterSplash( water_trace ); } if( trace.ent != -1 && !( trace.surfFlags & SURF_NOIMPACT ) ) { CG_BulletImpact( &trace ); if( !water_trace ) { if( trace.surfFlags & SURF_FLESH || ( trace.ent > 0 && cg_entities[trace.ent].current.type == ET_PLAYER ) || ( trace.ent > 0 && cg_entities[trace.ent].current.type == ET_CORPSE ) ) { // flesh impact sound } else trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRic[ rand()&2 ] ), trace.endpos, CHAN_AUTO, cg_volume_effects->value, ATTN_STATIC ); } } if( water_trace ) CG_LeadBubbleTrail( &trace, water_trace->endpos ); }
/* * GS_ThinkPlayerWeapon */ int GS_ThinkPlayerWeapon( player_state_t *playerState, int buttons, int msecs, int timeDelta ) { firedef_t *firedef; qboolean refire = qfalse; assert( playerState->stats[STAT_PENDING_WEAPON] >= 0 && playerState->stats[STAT_PENDING_WEAPON] < WEAP_TOTAL ); if( GS_MatchPaused() ) return playerState->stats[STAT_WEAPON]; if( playerState->pmove.pm_type != PM_NORMAL ) { playerState->weaponState = WEAPON_STATE_READY; playerState->stats[STAT_PENDING_WEAPON] = playerState->stats[STAT_WEAPON] = WEAP_NONE; playerState->stats[STAT_WEAPON_TIME] = 0; return playerState->stats[STAT_WEAPON]; } if( playerState->pmove.stats[PM_STAT_NOUSERCONTROL] > 0 ) buttons = 0; if( !msecs ) goto done; if( playerState->stats[STAT_WEAPON_TIME] > 0 ) playerState->stats[STAT_WEAPON_TIME] -= msecs; else playerState->stats[STAT_WEAPON_TIME] = 0; firedef = GS_FiredefForPlayerState( playerState, playerState->stats[STAT_WEAPON] ); // during cool-down time it can shoot again or go into reload time if( playerState->weaponState == WEAPON_STATE_REFIRE || playerState->weaponState == WEAPON_STATE_REFIRESTRONG ) { int last_firemode; if( playerState->stats[STAT_WEAPON_TIME] > 0 ) goto done; last_firemode = ( playerState->weaponState == WEAPON_STATE_REFIRESTRONG ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; if( last_firemode == firedef->fire_mode ) refire = qtrue; playerState->weaponState = WEAPON_STATE_READY; } // nothing can be done during reload time if( playerState->weaponState == WEAPON_STATE_RELOADING ) { if( playerState->stats[STAT_WEAPON_TIME] > 0 ) goto done; playerState->weaponState = WEAPON_STATE_READY; } if( playerState->weaponState == WEAPON_STATE_NOAMMOCLICK ) { if( playerState->stats[STAT_WEAPON_TIME] > 0 ) goto done; if( playerState->stats[STAT_WEAPON] != playerState->stats[STAT_PENDING_WEAPON] ) playerState->weaponState = WEAPON_STATE_READY; } // there is a weapon to be changed if( playerState->stats[STAT_WEAPON] != playerState->stats[STAT_PENDING_WEAPON] ) { if( ( playerState->weaponState == WEAPON_STATE_READY ) || ( playerState->weaponState == WEAPON_STATE_DROPPING ) || ( playerState->weaponState == WEAPON_STATE_ACTIVATING ) ) { if( playerState->weaponState != WEAPON_STATE_DROPPING ) { playerState->weaponState = WEAPON_STATE_DROPPING; playerState->stats[STAT_WEAPON_TIME] += firedef->weapondown_time; if( firedef->weapondown_time ) module_PredictedEvent( playerState->POVnum, EV_WEAPONDROP, 0 ); } } } // do the change if( playerState->weaponState == WEAPON_STATE_DROPPING ) { if( playerState->stats[STAT_WEAPON_TIME] > 0 ) goto done; playerState->stats[STAT_WEAPON] = playerState->stats[STAT_PENDING_WEAPON]; // update the firedef firedef = GS_FiredefForPlayerState( playerState, playerState->stats[STAT_WEAPON] ); playerState->weaponState = WEAPON_STATE_ACTIVATING; playerState->stats[STAT_WEAPON_TIME] += firedef->weaponup_time; module_PredictedEvent( playerState->POVnum, EV_WEAPONACTIVATE, playerState->stats[STAT_WEAPON] ); } if( playerState->weaponState == WEAPON_STATE_ACTIVATING ) { if( playerState->stats[STAT_WEAPON_TIME] > 0 ) goto done; playerState->weaponState = WEAPON_STATE_READY; } if( ( playerState->weaponState == WEAPON_STATE_READY ) || ( playerState->weaponState == WEAPON_STATE_NOAMMOCLICK ) ) { if( playerState->stats[STAT_WEAPON_TIME] > 0 ) goto done; if( !GS_ShootingDisabled() ) { if( buttons & BUTTON_ATTACK ) { if( GS_CheckAmmoInWeapon( playerState, playerState->stats[STAT_WEAPON] ) ) { playerState->weaponState = WEAPON_STATE_FIRING; } else { // player has no ammo nor clips if( playerState->weaponState == WEAPON_STATE_NOAMMOCLICK ) { playerState->weaponState = WEAPON_STATE_RELOADING; playerState->stats[STAT_WEAPON_TIME] += NOAMMOCLICK_AUTOSWITCH; if( playerState->stats[STAT_PENDING_WEAPON] == playerState->stats[STAT_WEAPON] ) playerState->stats[STAT_PENDING_WEAPON] = GS_SelectBestWeapon( playerState ); } else { playerState->weaponState = WEAPON_STATE_NOAMMOCLICK; playerState->stats[STAT_WEAPON_TIME] += NOAMMOCLICK_PENALTY; module_PredictedEvent( playerState->POVnum, EV_NOAMMOCLICK, 0 ); goto done; } } } // gunblade auto attack is special else if( playerState->stats[STAT_WEAPON] == WEAP_GUNBLADE && playerState->pmove.stats[PM_STAT_NOUSERCONTROL] <= 0 && playerState->pmove.stats[PM_STAT_NOAUTOATTACK] <= 0 && GS_CheckBladeAutoAttack( playerState, timeDelta ) ) { firedef = &GS_GetWeaponDef( WEAP_GUNBLADE )->firedef_weak; playerState->weaponState = WEAPON_STATE_FIRING; } } } if( playerState->weaponState == WEAPON_STATE_FIRING ) { int parm = playerState->stats[STAT_WEAPON]; if( firedef->fire_mode == FIRE_MODE_STRONG ) parm |= EV_INVERSE; playerState->stats[STAT_WEAPON_TIME] += firedef->reload_time; if( firedef->fire_mode == FIRE_MODE_STRONG ) playerState->weaponState = WEAPON_STATE_REFIRESTRONG; else playerState->weaponState = WEAPON_STATE_REFIRE; if( refire && firedef->smooth_refire ) module_PredictedEvent( playerState->POVnum, EV_SMOOTHREFIREWEAPON, parm ); else module_PredictedEvent( playerState->POVnum, EV_FIREWEAPON, parm ); // waste ammo if( !GS_InfiniteAmmo() ) { if( firedef->ammo_id != AMMO_NONE && firedef->usage_count ) playerState->inventory[firedef->ammo_id] -= firedef->usage_count; } } done: return playerState->stats[STAT_WEAPON]; }
/* * G_FireWeapon */ void G_FireWeapon( edict_t *ent, int parm ) { gs_weapon_definition_t *weapondef; firedef_t *firedef; edict_t *projectile; vec3_t origin, angles; vec3_t viewoffset = { 0, 0, 0 }; int ucmdSeed; weapondef = GS_GetWeaponDef( ( parm & ~EV_INVERSE ) ); firedef = ( parm & EV_INVERSE ) ? &weapondef->firedef : &weapondef->firedef_weak; // find this shot projection source if( ent->r.client ) { viewoffset[2] += ent->r.client->ps.viewheight; VectorCopy( ent->r.client->ps.viewangles, angles ); is_quad = ( ent->r.client->ps.inventory[POWERUP_QUAD] > 0 ) ? true : false; ucmdSeed = ent->r.client->ucmd.serverTimeStamp & 255; } else { VectorCopy( ent->s.angles, angles ); is_quad = false; ucmdSeed = rand() & 255; } VectorAdd( ent->s.origin, viewoffset, origin ); // shoot projectile = NULL; switch( weapondef->weapon_id ) { default: case WEAP_NONE: break; case WEAP_GUNBLADE: if( firedef->fire_mode == FIRE_MODE_STRONG ) projectile = G_Fire_Gunblade_Blast( origin, angles, firedef, ent, ucmdSeed ); else projectile = G_Fire_Gunblade_Knife( origin, angles, firedef, ent ); break; case WEAP_MACHINEGUN: projectile = G_Fire_Machinegun( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_RIOTGUN: projectile = G_Fire_Riotgun( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_GRENADELAUNCHER: projectile = G_Fire_Grenade( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_ROCKETLAUNCHER: projectile = G_Fire_Rocket( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_PLASMAGUN: projectile = G_Fire_Plasma( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_LASERGUN: projectile = G_Fire_Lasergun( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_ELECTROBOLT: projectile = G_Fire_StrongBolt( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_INSTAGUN: projectile = G_Fire_Instagun( origin, angles, firedef, ent, ucmdSeed ); break; } // add stats if( ent->r.client && weapondef->weapon_id != WEAP_NONE ) ent->r.client->level.stats.accuracy_shots[firedef->ammo_id - AMMO_GUNBLADE] += firedef->projectile_count; if( projectile ) { //if( projectile->s.linearProjectile ) // convert distance to time for linear projectiles // G_ProjectileTimePrestep( projectile, 1000.0f * ( g_projectile_prestep->value / VectorLengthFast( projectile->velocity ) ) ); //else G_ProjectileDistancePrestep( projectile, g_projectile_prestep->value ); } #ifdef NO_ROCKET_ANTILAG // hack for disabling antilag on rockets if( projectile && projectile->s.type == ET_ROCKET ) { int timeOffset; timeOffset = -projectile->timeDelta; projectile->timeDelta = 0; if( projectile->s.linearProjectile ) projectile->s.modelindex2 = 0; G_ProjectileTimePrestep( projectile, timeOffset ); } #endif }
/* * GS_Cmd_UseItem */ gsitem_t *GS_Cmd_UseItem( player_state_t *playerState, const char *string, int typeMask ) { gsitem_t *item = NULL; assert( playerState ); if( playerState->pmove.pm_type >= PM_SPECTATOR ) return NULL; if( !string || !string[0] ) return NULL; if( Q_isdigit( string ) ) { int tag = atoi( string ); item = GS_FindItemByTag( tag ); } else item = GS_FindItemByName( string ); if( !item ) return NULL; if( typeMask && !( item->type & typeMask ) ) return NULL; // we don't have this item in the inventory if( !playerState->inventory[item->tag] ) { if( gs.module == GS_MODULE_CGAME && !( item->type & IT_WEAPON ) ) module_Printf( "Item %s is not in inventory\n", item->name ); return NULL; } // see if we can use it if( !(item->flags & ITFLAG_USABLE) ) return NULL; if( item->type & IT_WEAPON ) { if( !( playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_WEAPONSWITCH ) ) return NULL; if( item->tag == playerState->stats[STAT_PENDING_WEAPON] ) // it's already being loaded return NULL; // check for need of any kind of ammo/fuel/whatever if( item->ammo_tag != AMMO_NONE && item->weakammo_tag != AMMO_NONE ) { gs_weapon_definition_t *weapondef = GS_GetWeaponDef( item->tag ); if( weapondef ) { // do we have any of these ammos ? if( playerState->inventory[item->weakammo_tag] >= weapondef->firedef_weak.usage_count ) return item; if( playerState->inventory[item->ammo_tag] >= weapondef->firedef.usage_count ) return item; } return NULL; } return item; // one of the weapon modes doesn't require ammo to be fired } if( item->type & IT_AMMO ) return item; if( item->type & IT_HEALTH ) return item; if( item->type & IT_POWERUP ) return item; return NULL; }
/* * W_Fire_Electrobolt_Combined */ void W_Fire_Electrobolt_Combined( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, float maxknockback, float minknockback, int stun, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; int fireMode; #ifdef ELECTROBOLT_TEST fireMode = FIRE_MODE_WEAK; #else fireMode = FIRE_MODE_STRONG; #endif if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback; frac = DistanceFast( tr.endpos, start ) / (float)range; clamp( frac, 0.0f, 1.0f ); damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = fireMode; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = fireMode; if( !GS_Instagib() && tr.ent == -1 ) // didn't touch anything, not even a wall { edict_t *bolt; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( self->s.weapon ); // fire a weak EB from the end position bolt = W_Fire_Electrobolt_Weak( self, end, angles, weapondef->firedef_weak.speed, mindamage, minknockback, minknockback, stun, weapondef->firedef_weak.timeout, mod, timeDelta ); bolt->enemy = damaged; } }
void CG_LaserBeamEffect( centity_t *cent ) { struct sfx_s *sound = NULL; float range; trace_t trace; orientation_t projectsource; vec4_t color; vec3_t laserOrigin, laserAngles, laserPoint; int i, j; if( cent->localEffects[LOCALEFFECT_LASERBEAM] <= cg.time ) return; laserOwner = cent; if( cg_teamColoredBeams->integer && ( cent->current.team == TEAM_ALPHA || cent->current.team == TEAM_BETA ) ) CG_TeamColor( cent->current.team, color ); else Vector4Set( color, 1, 1, 1, 1 ); // interpolate the positions if( ISVIEWERENTITY( cent->current.number ) && !cg.view.thirdperson ) { VectorCopy( cg.predictedPlayerState.pmove.origin, laserOrigin ); laserOrigin[2] += cg.predictedPlayerState.viewheight; VectorCopy( cg.predictedPlayerState.viewangles, laserAngles ); VectorLerp( cent->laserPointOld, cg.lerpfrac, cent->laserPoint, laserPoint ); } else { VectorLerp( cent->laserOriginOld, cg.lerpfrac, cent->laserOrigin, laserOrigin ); VectorLerp( cent->laserPointOld, cg.lerpfrac, cent->laserPoint, laserPoint ); if( !cent->laserCurved ) { vec3_t dir; // make up the angles from the start and end points (s->angles is not so precise) VectorSubtract( laserPoint, laserOrigin, dir ); VecToAngles( dir, laserAngles ); } else // use player entity angles { for( i = 0; i < 3; i++ ) laserAngles[i] = LerpAngle( cent->prev.angles[i], cent->current.angles[i], cg.lerpfrac ); } } if( !cent->laserCurved ) { range = GS_GetWeaponDef( WEAP_LASERGUN )->firedef.timeout; if( cent->current.effects & EF_QUAD ) sound = CG_MediaSfx( cgs.media.sfxLasergunStrongQuadHum ); else sound = CG_MediaSfx( cgs.media.sfxLasergunStrongHum ); // trace the beam: for tracing we use the real beam origin GS_TraceLaserBeam( &trace, laserOrigin, laserAngles, range, cent->current.number, 0, _LaserImpact ); // draw the beam: for drawing we use the weapon projection source (already handles the case of viewer entity) if( !CG_PModel_GetProjectionSource( cent->current.number, &projectsource ) ) VectorCopy( laserOrigin, projectsource.origin ); CG_KillPolyBeamsByTag( cent->current.number ); CG_LaserGunPolyBeam( projectsource.origin, trace.endpos, color, cent->current.number ); } else { float frac, subdivisions = cg_laserBeamSubdivisions->integer; vec3_t from, dir, end, blendPoint; int passthrough = cent->current.number; vec3_t tmpangles, blendAngles; range = GS_GetWeaponDef( WEAP_LASERGUN )->firedef_weak.timeout; if( cent->current.effects & EF_QUAD ) sound = CG_MediaSfx( cgs.media.sfxLasergunWeakQuadHum ); else sound = CG_MediaSfx( cgs.media.sfxLasergunWeakHum ); // trace the beam: for tracing we use the real beam origin GS_TraceCurveLaserBeam( &trace, laserOrigin, laserAngles, laserPoint, cent->current.number, 0, _LaserImpact ); // draw the beam: for drawing we use the weapon projection source (already handles the case of viewer entity) if( !CG_PModel_GetProjectionSource( cent->current.number, &projectsource ) ) VectorCopy( laserOrigin, projectsource.origin ); if( subdivisions < CURVELASERBEAM_SUBDIVISIONS ) subdivisions = CURVELASERBEAM_SUBDIVISIONS; CG_KillPolyBeamsByTag( cent->current.number ); // we redraw the full beam again, and trace each segment for stop dead impact VectorCopy( laserPoint, blendPoint ); VectorCopy( projectsource.origin, from ); VectorSubtract( blendPoint, projectsource.origin, dir ); VecToAngles( dir, blendAngles ); for( i = 1; i <= (int)subdivisions; i++ ) { frac = ( ( range/subdivisions )*(float)i ) / (float)range; for( j = 0; j < 3; j++ ) tmpangles[j] = LerpAngle( laserAngles[j], blendAngles[j], frac ); AngleVectors( tmpangles, dir, NULL, NULL ); VectorMA( projectsource.origin, range * frac, dir, end ); GS_TraceLaserBeam( &trace, from, tmpangles, DistanceFast( from, end ), passthrough, 0, NULL ); CG_LaserGunPolyBeam( from, trace.endpos, color, cent->current.number ); if( trace.fraction != 1.0f ) break; passthrough = trace.ent; VectorCopy( trace.endpos, from ); } } // enable continuous flash on the weapon owner if( cg_weaponFlashes->integer ) cg_entPModels[cent->current.number].flash_time = cg.time + CG_GetWeaponInfo( WEAP_LASERGUN )->flashTime; if( sound ) { if( ISVIEWERENTITY( cent->current.number ) ) trap_S_AddLoopSound( sound, cent->current.number, 1.0, ATTN_NONE ); else trap_S_AddLoopSound( sound, cent->current.number, 1.0, ATTN_STATIC ); } laserOwner = NULL; }
/* * G_RadiusDamage */ void G_RadiusDamage( edict_t *inflictor, edict_t *attacker, cplane_t *plane, edict_t *ignore, int mod ) { edict_t *ent = NULL; float dmgFrac, kickFrac, damage, knockback, stun; vec3_t pushDir; int timeDelta; float maxdamage, mindamage, maxknockback, minknockback, maxstun, minstun, radius; assert( inflictor ); maxdamage = inflictor->projectileInfo.maxDamage; mindamage = inflictor->projectileInfo.minDamage; maxknockback = inflictor->projectileInfo.maxKnockback; minknockback = inflictor->projectileInfo.minKnockback; maxstun = inflictor->projectileInfo.stun; minstun = 1; radius = inflictor->projectileInfo.radius; if( radius <= 1.0f || ( maxdamage <= 0.0f && maxknockback <= 0.0f ) ) return; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); clamp_high( minstun, maxstun ); while( ( ent = GClip_FindBoxInRadius4D( ent, inflictor->s.origin, radius, inflictor->timeDelta ) ) != NULL ) { if( ent == ignore || !ent->takedamage ) continue; if( ent == attacker && ent->r.client ) timeDelta = 0; else timeDelta = inflictor->timeDelta; G_SplashFrac4D( ENTNUM( ent ), inflictor->s.origin, radius, pushDir, &kickFrac, &dmgFrac, timeDelta ); damage = max( 0, mindamage + ( ( maxdamage - mindamage ) * dmgFrac ) ); stun = max( 0, minstun + ( ( maxstun - minstun ) * dmgFrac ) ); knockback = max( 0, minknockback + ( ( maxknockback - minknockback ) * kickFrac ) ); // weapon jumps hack : when knockback on self, use strong weapon definition if( ent == attacker && ent->r.client ) { gs_weapon_definition_t *weapondef = NULL; if( inflictor->s.type == ET_ROCKET ) weapondef = GS_GetWeaponDef( WEAP_ROCKETLAUNCHER ); else if( inflictor->s.type == ET_GRENADE ) weapondef = GS_GetWeaponDef( WEAP_GRENADELAUNCHER ); else if( inflictor->s.type == ET_PLASMA ) weapondef = GS_GetWeaponDef( WEAP_PLASMAGUN ); else if( inflictor->s.type == ET_BLASTER ) weapondef = GS_GetWeaponDef( WEAP_GUNBLADE ); if( weapondef ) { G_SplashFrac4D( ENTNUM( ent ), inflictor->s.origin, radius, pushDir, &kickFrac, NULL, 0 ); minknockback = weapondef->firedef.minknockback; maxknockback = weapondef->firedef.knockback; clamp_high( minknockback, maxknockback ); knockback = ( minknockback + ( (float)( maxknockback - minknockback ) * kickFrac ) ) * g_self_knockback->value; damage *= weapondef->firedef.selfdamage; } } if( knockback < 1.0f ) knockback = 0.0f; if( stun < 1.0f ) stun = 0.0f; if( damage <= 0.0f && knockback <= 0.0f && stun <= 0.0f ) continue; if( G_CanSplashDamage( ent, inflictor, plane ) ) G_Damage( ent, inflictor, attacker, pushDir, inflictor->velocity, inflictor->s.origin, damage, knockback, stun, DAMAGE_RADIUS, mod ); } }
/* * G_FireWeapon */ void G_FireWeapon( edict_t *ent, int parm ) { gs_weapon_definition_t *weapondef; firedef_t *firedef; edict_t *projectile; vec3_t origin, angles; vec3_t viewoffset = { 0, 0, 0 }; int ucmdSeed; // racesow float prestep; // !racesow weapondef = GS_GetWeaponDef( ( parm & ~EV_INVERSE ) ); firedef = ( parm & EV_INVERSE ) ? &weapondef->firedef : &weapondef->firedef_weak; // find this shot projection source if( ent->r.client ) { viewoffset[2] += ent->r.client->ps.viewheight; VectorCopy( ent->r.client->ps.viewangles, angles ); is_quad = ( ent->r.client->ps.inventory[POWERUP_QUAD] > 0 ); ucmdSeed = ent->r.client->ucmd.serverTimeStamp & 255; } else { VectorCopy( ent->s.angles, angles ); is_quad = qfalse; ucmdSeed = rand() & 255; } VectorAdd( ent->s.origin, viewoffset, origin ); // racesow prestep=g_projectile_prestep->value; // !racesow // shoot projectile = NULL; switch( weapondef->weapon_id ) { default: case WEAP_NONE: break; case WEAP_GUNBLADE: if( firedef->fire_mode == FIRE_MODE_STRONG ) projectile = G_Fire_Gunblade_Blast( origin, angles, firedef, ent, ucmdSeed ); else projectile = G_Fire_Gunblade_Knife( origin, angles, firedef, ent ); break; case WEAP_MACHINEGUN: projectile = G_Fire_Machinegun( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_RIOTGUN: projectile = G_Fire_Riotgun( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_GRENADELAUNCHER: projectile = G_Fire_Grenade( origin, angles, firedef, ent, ucmdSeed ); // racesow if( GS_RaceGametype() ) //prestep/=2; // racesow 0.42 had default prestep=48 and genade prestep=24 prestep=trap_Cvar_Get( "rs_grenade_prestep", "90", CVAR_ARCHIVE )->integer; // !racesow break; case WEAP_ROCKETLAUNCHER: projectile = G_Fire_Rocket( origin, angles, firedef, ent, ucmdSeed ); // racesow if( GS_RaceGametype() ) //prestep=0; // racesow 0.42 had rocket prestep=0 prestep=trap_Cvar_Get( "rs_rocket_prestep", "90", CVAR_ARCHIVE )->integer; // !racesow break; case WEAP_PLASMAGUN: projectile = G_Fire_Plasma( origin, angles, firedef, ent, ucmdSeed ); // racesow if( GS_RaceGametype() ) //prestep*=2/3; // racesow 0.42 had plasma prestep=32 prestep=trap_Cvar_Get( "rs_plasma_prestep", "90", CVAR_ARCHIVE )->integer; // !racesow break; case WEAP_LASERGUN: projectile = G_Fire_Lasergun( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_ELECTROBOLT: projectile = G_Fire_StrongBolt( origin, angles, firedef, ent, ucmdSeed ); break; case WEAP_INSTAGUN: projectile = G_Fire_Instagun( origin, angles, firedef, ent, ucmdSeed ); break; } // add stats if( ent->r.client && weapondef->weapon_id != WEAP_NONE ) ent->r.client->level.stats.accuracy_shots[firedef->ammo_id - AMMO_GUNBLADE] += firedef->projectile_count; if( projectile ) { //if( projectile->s.linearProjectile ) // convert distance to time for linear projectiles // G_ProjectileTimePrestep( projectile, 1000.0f * ( g_projectile_prestep->value / VectorLengthFast( projectile->velocity ) ) ); //else //G_ProjectileDistancePrestep( projectile, g_projectile_prestep->value ); //racesow Seems like this was added in warsow 0.7 -K1ll // racesow: modified prestep G_ProjectileDistancePrestep( projectile, prestep ); // !racesow } // racesow: enable skipping no_antilag if rs_rocket_antilag is 1 if ( GS_RaceGametype() && ((trap_Cvar_Get( "rs_rocket_antilag", "0", CVAR_ARCHIVE )->integer==1 && projectile->s.type == ET_ROCKET))) return; // !racesow #ifdef NO_ROCKET_ANTILAG // hack for disabling antilag on rockets if( projectile && (projectile->s.type == ET_ROCKET || projectile->s.type == ET_PLASMA) )//racesow { int timeOffset; timeOffset = -projectile->timeDelta; projectile->timeDelta = 0; if( projectile->s.linearProjectile ) projectile->s.modelindex2 = 0; // racesow: testing .42 time prestep function, because im really not sure it is equivalent to the .5 one; the difference is not that major anyway.. // G_ProjectileTimePrestep( projectile, timeOffset ); rs_TimeDeltaPrestepProjectile(projectile,-timeOffset); // !racesow } #endif }