void WP_FireScepter( gentity_t *ent, qboolean alt_fire ) {//just a straight beam int damage = 1; vec3_t start, end; trace_t tr; gentity_t *traceEnt = NULL, *tent; float shotRange = 8192; qboolean render_impact = qtrue; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin ); WP_MissileTargetHint(ent, start, forwardVec); VectorMA( start, shotRange, forwardVec, end ); gi.trace( &tr, start, NULL, NULL, end, ent->s.number, MASK_SHOT, G2_RETURNONHIT, 10 ); traceEnt = &g_entities[tr.entityNum]; if ( tr.surfaceFlags & SURF_NOIMPACT ) { render_impact = qfalse; } // always render a shot beam, doing this the old way because I don't much feel like overriding the effect. tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_MAIN_SHOT ); tent->svFlags |= SVF_BROADCAST; VectorCopy( muzzle, tent->s.origin2 ); if ( render_impact ) { if ( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage ) { // Create a simple impact type mark that doesn't last long in the world G_PlayEffect( G_EffectIndex( "disruptor/flesh_impact" ), tr.endpos, tr.plane.normal ); int hitLoc = G_GetHitLocFromTrace( &tr, MOD_DISRUPTOR ); G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, damage, DAMAGE_EXTRA_KNOCKBACK, MOD_DISRUPTOR, hitLoc ); } else { G_PlayEffect( G_EffectIndex( "disruptor/wall_impact" ), tr.endpos, tr.plane.normal ); } } /* shotDist = shotRange * tr.fraction; for ( dist = 0; dist < shotDist; dist += 64 ) { //FIXME: on a really long shot, this could make a LOT of alerts in one frame... VectorMA( start, dist, forwardVec, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); } VectorMA( start, shotDist-4, forwardVec, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); */ }
//--------------------------------------------------------- static void WP_BowcasterAltFire( gentity_t *ent ) //--------------------------------------------------------- { vec3_t start; int damage = weaponData[WP_BOWCASTER].altDamage; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall WP_MissileTargetHint(ent, start, forwardVec); gentity_t *missile = CreateMissile( start, forwardVec, BOWCASTER_VELOCITY, 10000, ent, qtrue ); missile->classname = "bowcaster_alt_proj"; missile->s.weapon = WP_BOWCASTER; // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = BOWCASTER_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = BOWCASTER_NPC_DAMAGE_NORMAL; } else { damage = BOWCASTER_NPC_DAMAGE_HARD; } } VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // missile->flags |= FL_OVERCHARGED; // damage *= 2; // } missile->s.eFlags |= EF_BOUNCE; missile->bounceCount = 3; missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->methodOfDeath = MOD_BOWCASTER_ALT; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = weaponData[WP_BOWCASTER].altSplashDamage; missile->splashRadius = weaponData[WP_BOWCASTER].altSplashRadius; }
//--------------------------------------------------------- static void WP_DEMP2_MainFire( gentity_t *ent ) //--------------------------------------------------------- { vec3_t start; int damage = weaponData[WP_DEMP2].damage; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall WP_MissileTargetHint(ent, start, forwardVec); gentity_t *missile = CreateMissile( start, forwardVec, DEMP2_VELOCITY, 10000, ent ); missile->classname = "demp2_proj"; missile->s.weapon = WP_DEMP2; // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = DEMP2_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = DEMP2_NPC_DAMAGE_NORMAL; } else { damage = DEMP2_NPC_DAMAGE_HARD; } } VectorSet( missile->maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // missile->flags |= FL_OVERCHARGED; // damage *= 2; // } missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->methodOfDeath = MOD_DEMP2; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; // we don't want it to ever bounce missile->bounceCount = 0; }
//--------------------------------------------------------- static void WP_DEMP2_AltFire( gentity_t *ent ) //--------------------------------------------------------- { int damage = weaponData[WP_REPEATER].altDamage; int count; vec3_t start; trace_t tr; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall count = ( level.time - ent->client->ps.weaponChargeTime ) / DEMP2_CHARGE_UNIT; if ( count < 1 ) { count = 1; } else if ( count > 3 ) { count = 3; } damage *= ( 1 + ( count * ( count - 1 )));// yields damage of 12,36,84...gives a higher bonus for longer charge // the shot can travel a whopping 4096 units in 1 second. Note that the shot will auto-detonate at 4096 units...we'll see if this looks cool or not WP_MissileTargetHint(ent, start, forwardVec); gentity_t *missile = CreateMissile( start, forwardVec, DEMP2_ALT_RANGE, 1000, ent, qtrue ); // letting it know what the charge size is. missile->count = count; // missile->speed = missile->nextthink; VectorCopy( tr.plane.normal, missile->pos1 ); missile->classname = "demp2_alt_proj"; missile->s.weapon = WP_DEMP2; missile->e_ThinkFunc = thinkF_DEMP2_AltDetonate; missile->splashDamage = missile->damage = damage; missile->splashMethodOfDeath = missile->methodOfDeath = MOD_DEMP2_ALT; missile->splashRadius = weaponData[WP_DEMP2].altSplashRadius; missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; // we don't want it to ever bounce missile->bounceCount = 0; }
//--------------------------------------------------------- static void WP_DropDetPack( gentity_t *self, vec3_t start, vec3_t dir ) //--------------------------------------------------------- { // Chucking a new one AngleVectors( self->client->ps.viewangles, forwardVec, vrightVec, up ); CalcMuzzlePoint( self, forwardVec, vrightVec, up, muzzle, 0 ); VectorNormalize( forwardVec ); VectorMA( muzzle, -4, forwardVec, muzzle ); VectorCopy( muzzle, start ); WP_TraceSetStart( self, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall gentity_t *missile = CreateMissile( start, forwardVec, 300, 10000, self, qfalse ); missile->fxID = G_EffectIndex( "detpack/explosion" ); // if we set an explosion effect, explode death can use that instead missile->classname = "detpack"; missile->s.weapon = WP_DET_PACK; missile->s.pos.trType = TR_GRAVITY; missile->s.eFlags |= EF_MISSILE_STICK; missile->e_TouchFunc = touchF_charge_stick; missile->damage = weaponData[WP_DET_PACK].damage; missile->methodOfDeath = MOD_DETPACK; missile->splashDamage = weaponData[WP_DET_PACK].splashDamage; missile->splashRadius = weaponData[WP_DET_PACK].splashRadius; missile->splashMethodOfDeath = MOD_DETPACK;// ?SPLASH; missile->clipmask = (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_SHOTCLIP);//MASK_SHOT; // we don't want it to ever bounce missile->bounceCount = 0; missile->s.radius = 30; VectorSet( missile->s.modelScale, 1.0f, 1.0f, 1.0f ); gi.G2API_InitGhoul2Model( missile->ghoul2, weaponData[WP_DET_PACK].missileMdl, G_ModelIndex( weaponData[WP_DET_PACK].missileMdl ), NULL_HANDLE, NULL_HANDLE, 0, 0); AddSoundEvent( NULL, missile->currentOrigin, 128, AEL_MINOR, qtrue ); AddSightEvent( NULL, missile->currentOrigin, 128, AEL_SUSPICIOUS, 10 ); }
//--------------------------------------------------------- void WP_FireStunBaton( gentity_t *ent, qboolean alt_fire ) { gentity_t *tr_ent; trace_t tr; vec3_t mins, maxs, end, start; G_Sound( ent, G_SoundIndex( "sound/weapons/baton/fire" )); VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin ); VectorMA( start, STUN_BATON_RANGE, forwardVec, end ); VectorSet( maxs, 5, 5, 5 ); VectorScale( maxs, -1, mins ); gi.trace ( &tr, start, mins, maxs, end, ent->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_SHOTCLIP, (EG2_Collision)0, 0 ); if ( tr.entityNum >= ENTITYNUM_WORLD || tr.entityNum < 0 ) { return; } tr_ent = &g_entities[tr.entityNum]; if ( tr_ent && tr_ent->takedamage && tr_ent->client ) { G_PlayEffect( "stunBaton/flesh_impact", tr.endpos, tr.plane.normal ); // TEMP! // G_Sound( tr_ent, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) ); tr_ent->client->ps.powerups[PW_SHOCKED] = level.time + 1500; G_Damage( tr_ent, ent, ent, forwardVec, tr.endpos, weaponData[WP_STUN_BATON].damage, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); } else if ( tr_ent->svFlags & SVF_GLASS_BRUSH || ( tr_ent->svFlags & SVF_BBRUSH && tr_ent->material == 12 )) // material grate...we are breaking a grate! { G_Damage( tr_ent, ent, ent, forwardVec, tr.endpos, 999, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); // smash that puppy } }
//--------------------------------------------------------- void WP_PlaceLaserTrap( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { vec3_t start; gentity_t *laserTrap; // limit to 10 placed at any one time WP_RemoveOldTraps( ent ); //FIXME: surface must be within 64 laserTrap = G_Spawn(); if ( laserTrap ) { // now make the new one VectorCopy( wpMuzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall CreateLaserTrap( laserTrap, start, ent ); // set player-created-specific fields laserTrap->setTime = level.time;//remember when we placed it laserTrap->s.eFlags |= EF_MISSILE_STICK; laserTrap->s.pos.trType = TR_GRAVITY; VectorScale( wpFwd, LT_VELOCITY, laserTrap->s.pos.trDelta ); if ( alt_fire ) { laserTrap->count = PROXIMITY_STYLE; laserTrap->delay = level.time + 40000; // will auto-blow in 40 seconds. laserTrap->methodOfDeath = MOD_LASERTRIP_ALT; laserTrap->splashMethodOfDeath = MOD_LASERTRIP_ALT;//? SPLASH; } else { laserTrap->count = TRIPWIRE_STYLE; } } }
//--------------------------------------------------------- static void WP_FlechetteAltFire( gentity_t *self ) //--------------------------------------------------------- { vec3_t dir, fwd, start, angs; vectoangles( wpFwd, angs ); VectorCopy( wpMuzzle, start ); WP_TraceSetStart( self, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall for ( int i = 0; i < 2; i++ ) { VectorCopy( angs, dir ); dir[PITCH] -= random() * 4 + 8; // make it fly upwards dir[YAW] += crandom() * 2; AngleVectors( dir, fwd, NULL, NULL ); WP_CreateFlechetteBouncyThing( start, fwd, self ); self->client->sess.missionStats.shotsFired++; } }
//--------------------------------------------------------- void WP_FireNoghriStick( gentity_t *ent ) //--------------------------------------------------------- { vec3_t dir, angs; vectoangles( forwardVec, angs ); if ( !(ent->client->ps.forcePowersActive&(1<<FP_SEE)) || ent->client->ps.forcePowerLevel[FP_SEE] < FORCE_LEVEL_2 ) {//force sight 2+ gives perfect aim //FIXME: maybe force sight level 3 autoaims some? // add some slop to the main-fire direction angs[PITCH] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angs[YAW] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f } AngleVectors( angs, dir, NULL, NULL ); // FIXME: if temp_org does not have clear trace to inside the bbox, don't shoot! int velocity = 1200; WP_TraceSetStart( ent, muzzle, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall WP_MissileTargetHint(ent, muzzle, dir); gentity_t *missile = CreateMissile( muzzle, dir, velocity, 10000, ent, qfalse ); missile->classname = "noghri_proj"; missile->s.weapon = WP_NOGHRI_STICK; // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { missile->damage = 1; } else if ( g_spskill->integer == 1 ) { missile->damage = 5; } else { missile->damage = 10; } } // if ( ent->client ) // { // if ( ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // missile->flags |= FL_OVERCHARGED; // damage *= 2; // } // } missile->dflags = DAMAGE_NO_KNOCKBACK; missile->methodOfDeath = MOD_BLASTER; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = 0; missile->splashRadius = 100; missile->splashMethodOfDeath = MOD_GAS; //Hmm: maybe spew gas on impact? }
//--------------------------------------------------------- static void WP_FlechetteMainFire( gentity_t *ent ) //--------------------------------------------------------- { vec3_t fwd, angs, start; gentity_t *missile; float damage = weaponData[WP_FLECHETTE].damage, vel = FLECHETTE_VEL; VectorCopy( wpMuzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall // If we aren't the player, we will cut the velocity and damage of the shots if ( ent->s.number ) { damage *= 0.75f; vel *= 0.5f; } // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // damage *= 2; // } for ( int i = 0; i < FLECHETTE_SHOTS; i++ ) { vectoangles( wpFwd, angs ); if ( i == 0 && ent->s.number == 0 ) { // do nothing on the first shot for the player, this one will hit the crosshairs } else { angs[PITCH] += crandom() * FLECHETTE_SPREAD; angs[YAW] += crandom() * FLECHETTE_SPREAD; } AngleVectors( angs, fwd, NULL, NULL ); missile = CreateMissile( start, fwd, vel, 10000, ent ); missile->classname = "flech_proj"; missile->s.weapon = WP_FLECHETTE; VectorSet( missile->maxs, FLECHETTE_SIZE, FLECHETTE_SIZE, FLECHETTE_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); missile->damage = damage; // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // missile->flags |= FL_OVERCHARGED; // } missile->dflags = (DAMAGE_DEATH_KNOCKBACK|DAMAGE_EXTRA_KNOCKBACK); missile->methodOfDeath = MOD_FLECHETTE; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; // we don't want it to bounce forever missile->bounceCount = Q_irand(1,2); missile->s.eFlags |= EF_BOUNCE_SHRAPNEL; ent->client->sess.missionStats.shotsFired++; } }
//--------------------------------------------------------- static void WP_DisruptorMainFire( gentity_t *ent ) //--------------------------------------------------------- { int damage = weaponData[WP_DISRUPTOR].damage; qboolean render_impact = qtrue; vec3_t start, end, spot; trace_t tr; gentity_t *traceEnt = NULL, *tent; float dist, shotDist, shotRange = 8192; if ( ent->NPC ) { switch ( g_spskill->integer ) { case 0: damage = DISRUPTOR_NPC_MAIN_DAMAGE_EASY; break; case 1: damage = DISRUPTOR_NPC_MAIN_DAMAGE_MEDIUM; break; case 2: default: damage = DISRUPTOR_NPC_MAIN_DAMAGE_HARD; break; } } VectorCopy( wpMuzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin ); // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // damage *= 2; // } VectorMA( start, shotRange, wpFwd, end ); int ignore = ent->s.number; int traces = 0; while ( traces < 10 ) {//need to loop this in case we hit a Jedi who dodges the shot gi.trace( &tr, start, NULL, NULL, end, ignore, MASK_SHOT, G2_RETURNONHIT, 0 ); traceEnt = &g_entities[tr.entityNum]; if ( traceEnt && traceEnt->s.weapon == WP_SABER )//&& traceEnt->NPC {//FIXME: need a more reliable way to know we hit a jedi? if ( Jedi_DodgeEvasion( traceEnt, ent, &tr, HL_NONE ) ) {//act like we didn't even hit him VectorCopy( tr.endpos, start ); ignore = tr.entityNum; traces++; continue; } } //a Jedi is not dodging this shot break; } if ( tr.surfaceFlags & SURF_NOIMPACT ) { render_impact = qfalse; } // always render a shot beam, doing this the old way because I don't much feel like overriding the effect. tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_MAIN_SHOT ); tent->svFlags |= SVF_BROADCAST; VectorCopy( wpMuzzle, tent->s.origin2 ); if ( render_impact ) { if ( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage ) { // Create a simple impact type mark that doesn't last long in the world G_PlayEffect( G_EffectIndex( "disruptor/flesh_impact" ), tr.endpos, tr.plane.normal ); if ( traceEnt->client && LogAccuracyHit( traceEnt, ent )) { ent->client->ps.persistant[PERS_ACCURACY_HITS]++; } int hitLoc = G_GetHitLocFromTrace( &tr, MOD_DISRUPTOR ); if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH ) {//hehe G_Damage( traceEnt, ent, ent, wpFwd, tr.endpos, 3, DAMAGE_DEATH_KNOCKBACK, MOD_DISRUPTOR, hitLoc ); } else { G_Damage( traceEnt, ent, ent, wpFwd, tr.endpos, damage, DAMAGE_DEATH_KNOCKBACK, MOD_DISRUPTOR, hitLoc ); } } else { G_PlayEffect( G_EffectIndex( "disruptor/wall_impact" ), tr.endpos, tr.plane.normal ); } } shotDist = shotRange * tr.fraction; for ( dist = 0; dist < shotDist; dist += 64 ) { //FIXME: on a really long shot, this could make a LOT of alerts in one frame... VectorMA( start, dist, wpFwd, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); } VectorMA( start, shotDist-4, wpFwd, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); }
//--------------------------------------------------------- void WP_FireBryarPistol( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { vec3_t start; int damage = !alt_fire ? weaponData[WP_BRYAR_PISTOL].damage : weaponData[WP_BRYAR_PISTOL].altDamage; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall if ( !(ent->client->ps.forcePowersActive&(1<<FP_SEE)) || ent->client->ps.forcePowerLevel[FP_SEE] < FORCE_LEVEL_2 ) {//force sight 2+ gives perfect aim //FIXME: maybe force sight level 3 autoaims some? if ( ent->NPC && ent->NPC->currentAim < 5 ) { vec3_t angs; vectoangles( forwardVec, angs ); if ( ent->client->NPC_class == CLASS_IMPWORKER ) {//*sigh*, hack to make impworkers less accurate without affecteing imperial officer accuracy angs[PITCH] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angs[YAW] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f } else { angs[PITCH] += ( crandom() * ((5-ent->NPC->currentAim)*0.25f) ); angs[YAW] += ( crandom() * ((5-ent->NPC->currentAim)*0.25f) ); } AngleVectors( angs, forwardVec, NULL, NULL ); } } WP_MissileTargetHint(ent, start, forwardVec); gentity_t *missile = CreateMissile( start, forwardVec, BRYAR_PISTOL_VEL, 10000, ent, alt_fire ); missile->classname = "bryar_proj"; if ( ent->s.weapon == WP_BLASTER_PISTOL || ent->s.weapon == WP_JAWA ) {//*SIGH*... I hate our weapon system... missile->s.weapon = ent->s.weapon; } else { missile->s.weapon = WP_BRYAR_PISTOL; } if ( alt_fire ) { int count = ( level.time - ent->client->ps.weaponChargeTime ) / BRYAR_CHARGE_UNIT; if ( count < 1 ) { count = 1; } else if ( count > 5 ) { count = 5; } damage *= count; missile->count = count; // this will get used in the projectile rendering code to make a beefier effect } // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // missile->flags |= FL_OVERCHARGED; // damage *= 2; // } missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; if ( alt_fire ) { missile->methodOfDeath = MOD_BRYAR_ALT; } else { missile->methodOfDeath = MOD_BRYAR; } missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; // we don't want it to bounce forever missile->bounceCount = 8; if ( ent->weaponModel[1] > 0 ) {//dual pistols, toggle the muzzle point back and forth between the two pistols each time he fires ent->count = (ent->count)?0:1; } }
//--------------------------------------------------------- gentity_t *WP_FireThermalDetonator( gentity_t *ent, qboolean altFire ) //--------------------------------------------------------- { gentity_t *bolt; vec3_t dir, start; float chargeAmount = 1.0f; // default of full charge VectorCopy( forward, dir ); VectorCopy( muzzle, start ); bolt = G_Spawn(); bolt->physicsObject = qtrue; bolt->classname = "thermal_detonator"; bolt->think = thermalThinkStandard; bolt->nextthink = level.time; bolt->touch = Thermal_Touch; // How 'bout we give this thing a size... VectorSet( bolt->r.mins, -3.0f, -3.0f, -3.0f ); VectorSet( bolt->r.maxs, 3.0f, 3.0f, 3.0f ); bolt->clipmask = MASK_SHOT; WP_TraceSetStart( ent, start, bolt->r.mins, bolt->r.maxs );//make sure our start point isn't on the other side of a wall if ( ent->client ) { chargeAmount = level.time - ent->client->ps.weaponChargeTime; } // get charge amount chargeAmount = chargeAmount / (float)TD_VELOCITY; if ( chargeAmount > 1.0f ) { chargeAmount = 1.0f; } else if ( chargeAmount < TD_MIN_CHARGE ) { chargeAmount = TD_MIN_CHARGE; } // normal ones bounce, alt ones explode on impact bolt->genericValue5 = level.time + TD_TIME; // How long 'til she blows bolt->s.pos.trType = TR_GRAVITY; bolt->parent = ent; bolt->r.ownerNum = ent->s.number; VectorScale( dir, TD_VELOCITY * chargeAmount, bolt->s.pos.trDelta ); if ( ent->health >= 0 ) { bolt->s.pos.trDelta[2] += 120; } if ( !altFire ) { bolt->flags |= FL_BOUNCE_HALF; } bolt->s.loopSound = G_SoundIndex( "sound/weapons/thermal/thermloop.wav" ); bolt->s.loopIsSoundset = qfalse; bolt->damage = TD_DAMAGE; bolt->dflags = 0; bolt->splashDamage = TD_SPLASH_DAM; bolt->splashRadius = TD_SPLASH_RAD; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_THERMAL; bolt->methodOfDeath = MOD_THERMAL; bolt->splashMethodOfDeath = MOD_THERMAL_SPLASH; bolt->s.pos.trTime = level.time; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy (start, bolt->r.currentOrigin); VectorCopy( start, bolt->pos2 ); bolt->bounceCount = -5; return bolt; }
//--------------------------------------------------------- gentity_t *WP_FireThermalDetonator( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { gentity_t *bolt; vec3_t dir, start; float damageScale = 1.0f; VectorCopy( wpFwd, dir ); VectorCopy( wpMuzzle, start ); bolt = G_Spawn(); bolt->classname = "thermal_detonator"; if ( ent->s.number != 0 ) { // If not the player, cut the damage a bit so we don't get pounded on so much damageScale = TD_NPC_DAMAGE_CUT; } if ( !alt_fire && ent->s.number == 0 ) { // Main fires for the players do a little bit of extra thinking bolt->e_ThinkFunc = thinkF_WP_ThermalThink; bolt->nextthink = level.time + TD_THINK_TIME; bolt->delay = level.time + TD_TIME; // How long 'til she blows } else { bolt->e_ThinkFunc = thinkF_thermalDetonatorExplode; bolt->nextthink = level.time + TD_TIME; // How long 'til she blows } bolt->mass = 10; // How 'bout we give this thing a size... VectorSet( bolt->mins, -4.0f, -4.0f, -4.0f ); VectorSet( bolt->maxs, 4.0f, 4.0f, 4.0f ); bolt->clipmask = MASK_SHOT; bolt->clipmask &= ~CONTENTS_CORPSE; bolt->contents = CONTENTS_SHOTCLIP; bolt->takedamage = qtrue; bolt->health = 15; bolt->e_DieFunc = dieF_thermal_die; WP_TraceSetStart( ent, start, bolt->mins, bolt->maxs );//make sure our start point isn't on the other side of a wall float chargeAmount = 1.0f; // default of full charge if ( ent->client ) { chargeAmount = level.time - ent->client->ps.weaponChargeTime; } // get charge amount chargeAmount = chargeAmount / (float)TD_VELOCITY; if ( chargeAmount > 1.0f ) { chargeAmount = 1.0f; } else if ( chargeAmount < TD_MIN_CHARGE ) { chargeAmount = TD_MIN_CHARGE; } // normal ones bounce, alt ones explode on impact bolt->s.pos.trType = TR_GRAVITY; bolt->owner = ent; VectorScale( dir, TD_VELOCITY * chargeAmount, bolt->s.pos.trDelta ); if ( ent->health > 0 ) { bolt->s.pos.trDelta[2] += 120; if ( ent->NPC && ent->enemy ) {//FIXME: we're assuming he's actually facing this direction... vec3_t target; VectorCopy( ent->enemy->currentOrigin, target ); if ( target[2] <= start[2] ) { vec3_t vec; VectorSubtract( target, start, vec ); VectorNormalize( vec ); VectorMA( target, Q_flrand( 0, -32 ), vec, target );//throw a little short } target[0] += Q_flrand( -5, 5 )+(crandom()*(6-ent->NPC->currentAim)*2); target[1] += Q_flrand( -5, 5 )+(crandom()*(6-ent->NPC->currentAim)*2); target[2] += Q_flrand( -5, 5 )+(crandom()*(6-ent->NPC->currentAim)*2); WP_LobFire( ent, start, target, bolt->mins, bolt->maxs, bolt->clipmask, bolt->s.pos.trDelta, qtrue, ent->s.number, ent->enemy->s.number ); } } if ( alt_fire ) { bolt->alt_fire = qtrue; } else { bolt->s.eFlags |= EF_BOUNCE_HALF; } bolt->s.loopSound = G_SoundIndex( "sound/weapons/thermal/thermloop.wav" ); bolt->damage = weaponData[WP_THERMAL].damage * damageScale; bolt->dflags = 0; bolt->splashDamage = weaponData[WP_THERMAL].splashDamage * damageScale; bolt->splashRadius = weaponData[WP_THERMAL].splashRadius; bolt->s.eType = ET_MISSILE; bolt->svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_THERMAL; if ( alt_fire ) { bolt->methodOfDeath = MOD_THERMAL_ALT; bolt->splashMethodOfDeath = MOD_THERMAL_ALT;//? SPLASH; } else { bolt->methodOfDeath = MOD_THERMAL; bolt->splashMethodOfDeath = MOD_THERMAL;//? SPLASH; } bolt->s.pos.trTime = level.time; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy (start, bolt->currentOrigin); VectorCopy( start, bolt->pos2 ); return bolt; }
static void WP_FireConcussionAlt( gentity_t *ent ) {//a rail-gun-like beam int damage = weaponData[WP_CONCUSSION].altDamage, skip, traces = DISRUPTOR_ALT_TRACES; qboolean render_impact = qtrue; vec3_t start, end; vec3_t muzzle2, spot, dir; trace_t tr; gentity_t *traceEnt, *tent; float dist, shotDist, shotRange = 8192; qboolean hitDodged = qfalse; if (ent->s.number >= MAX_CLIENTS) { vec3_t angles; vectoangles(forwardVec, angles); angles[PITCH] += ( crandom() * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angles[YAW] += ( crandom() * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f AngleVectors(angles, forwardVec, vrightVec, up); } //Shove us backwards for half a second VectorMA( ent->client->ps.velocity, -200, forwardVec, ent->client->ps.velocity ); ent->client->ps.groundEntityNum = ENTITYNUM_NONE; if ( (ent->client->ps.pm_flags&PMF_DUCKED) ) {//hunkered down ent->client->ps.pm_time = 100; } else { ent->client->ps.pm_time = 250; } ent->client->ps.pm_flags |= PMF_TIME_KNOCKBACK|PMF_TIME_NOFRICTION; //FIXME: only if on ground? So no "rocket jump"? Or: (see next FIXME) //FIXME: instead, set a forced ucmd backmove instead of this sliding VectorCopy( muzzle, muzzle2 ); // making a backup copy // The trace start will originate at the eye so we can ensure that it hits the crosshair. if ( ent->NPC ) { switch ( g_spskill->integer ) { case 0: damage = CONC_ALT_NPC_DAMAGE_EASY; break; case 1: damage = CONC_ALT_NPC_DAMAGE_MEDIUM; break; case 2: default: damage = CONC_ALT_NPC_DAMAGE_HARD; break; } } VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin ); skip = ent->s.number; // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // damage *= 2; // } //Make it a little easier to hit guys at long range vec3_t shot_mins, shot_maxs; VectorSet( shot_mins, -1, -1, -1 ); VectorSet( shot_maxs, 1, 1, 1 ); for ( int i = 0; i < traces; i++ ) { VectorMA( start, shotRange, forwardVec, end ); //NOTE: if you want to be able to hit guys in emplaced guns, use "G2_COLLIDE, 10" instead of "G2_RETURNONHIT, 0" //alternately, if you end up hitting an emplaced_gun that has a sitter, just redo this one trace with the "G2_COLLIDE, 10" to see if we it the sitter //gi.trace( &tr, start, NULL, NULL, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 ); gi.trace( &tr, start, shot_mins, shot_maxs, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 ); if ( tr.surfaceFlags & SURF_NOIMPACT ) { render_impact = qfalse; } if ( tr.entityNum == ent->s.number ) { // should never happen, but basically we don't want to consider a hit to ourselves? // Get ready for an attempt to trace through another person VectorCopy( tr.endpos, muzzle2 ); VectorCopy( tr.endpos, start ); skip = tr.entityNum; #ifdef _DEBUG gi.Printf( "BAD! Concussion gun shot somehow traced back and hit the owner!\n" ); #endif continue; } // always render a shot beam, doing this the old way because I don't much feel like overriding the effect. //NOTE: let's just draw one beam at the end //tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT ); //tent->svFlags |= SVF_BROADCAST; //VectorCopy( muzzle2, tent->s.origin2 ); if ( tr.fraction >= 1.0f ) { // draw the beam but don't do anything else break; } traceEnt = &g_entities[tr.entityNum]; if ( traceEnt //&& traceEnt->NPC && ( traceEnt->s.weapon == WP_SABER || (traceEnt->client && (traceEnt->client->NPC_class == CLASS_BOBAFETT||traceEnt->client->NPC_class == CLASS_REBORN) ) ) ) {//FIXME: need a more reliable way to know we hit a jedi? hitDodged = Jedi_DodgeEvasion( traceEnt, ent, &tr, HL_NONE ); //acts like we didn't even hit him } if ( !hitDodged ) { if ( render_impact ) { if (( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage ) || !Q_stricmp( traceEnt->classname, "misc_model_breakable" ) || traceEnt->s.eType == ET_MOVER ) { // Create a simple impact type mark that doesn't last long in the world G_PlayEffect( G_EffectIndex( "concussion/alt_hit" ), tr.endpos, tr.plane.normal ); if ( traceEnt->client && LogAccuracyHit( traceEnt, ent )) {//NOTE: hitting multiple ents can still get you over 100% accuracy ent->client->ps.persistant[PERS_ACCURACY_HITS]++; } int hitLoc = G_GetHitLocFromTrace( &tr, MOD_CONC_ALT ); qboolean noKnockBack = (traceEnt->flags&FL_NO_KNOCKBACK);//will be set if they die, I want to know if it was on *before* they died if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH ) {//hehe G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, 10, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc ); break; } G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, damage, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc ); //do knockback and knockdown manually if ( traceEnt->client ) {//only if we hit a client vec3_t pushDir; VectorCopy( forwardVec, pushDir ); if ( pushDir[2] < 0.2f ) { pushDir[2] = 0.2f; }//hmm, re-normalize? nah... //if ( traceEnt->NPC || Q_irand(0,g_spskill->integer+1) ) { if ( !noKnockBack ) {//knock-backable G_Throw( traceEnt, pushDir, 200 ); if ( traceEnt->client->NPC_class == CLASS_ROCKETTROOPER ) { traceEnt->client->ps.pm_time = Q_irand( 1500, 3000 ); } } if ( traceEnt->health > 0 ) {//alive if ( G_HasKnockdownAnims( traceEnt ) ) {//knock-downable G_Knockdown( traceEnt, ent, pushDir, 400, qtrue ); } } } } if ( traceEnt->s.eType == ET_MOVER ) {//stop the traces on any mover break; } } else { // we only make this mark on things that can't break or move tent = G_TempEntity( tr.endpos, EV_CONC_ALT_MISS ); tent->svFlags |= SVF_BROADCAST; VectorCopy( tr.plane.normal, tent->pos1 ); break; // hit solid, but doesn't take damage, so stop the shot...we _could_ allow it to shoot through walls, might be cool? } } else // not rendering impact, must be a skybox or other similar thing? { break; // don't try anymore traces } } // Get ready for an attempt to trace through another person VectorCopy( tr.endpos, muzzle2 ); VectorCopy( tr.endpos, start ); skip = tr.entityNum; hitDodged = qfalse; } //just draw one beam all the way to the end tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT ); tent->svFlags |= SVF_BROADCAST; VectorCopy( muzzle, tent->s.origin2 ); // now go along the trail and make sight events VectorSubtract( tr.endpos, muzzle, dir ); shotDist = VectorNormalize( dir ); //FIXME: if shoot *really* close to someone, the alert could be way out of their FOV for ( dist = 0; dist < shotDist; dist += 64 ) { //FIXME: on a really long shot, this could make a LOT of alerts in one frame... VectorMA( muzzle, dist, dir, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); //FIXME: creates *way* too many effects, make it one effect somehow? G_PlayEffect( G_EffectIndex( "concussion/alt_ring" ), spot, forwardVec ); } //FIXME: spawn a temp ent that continuously spawns sight alerts here? And 1 sound alert to draw their attention? VectorMA( start, shotDist-4, forwardVec, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); G_PlayEffect( G_EffectIndex( "concussion/altmuzzle_flash" ), muzzle, forwardVec ); }
void WP_FireVehicleWeapon( gentity_t *ent, vec3_t start, vec3_t dir, vehWeaponInfo_t *vehWeapon ) { if ( !vehWeapon ) {//invalid vehicle weapon return; } else if ( vehWeapon->bIsProjectile ) {//projectile entity gentity_t *missile; vec3_t mins, maxs; VectorSet( maxs, vehWeapon->fWidth/2.0f,vehWeapon->fWidth/2.0f,vehWeapon->fHeight/2.0f ); VectorScale( maxs, -1, mins ); //make sure our start point isn't on the other side of a wall WP_TraceSetStart( ent, start, mins, maxs ); //QUERY: alt_fire true or not? Does it matter? missile = CreateMissile( start, dir, vehWeapon->fSpeed, 10000, ent, qfalse ); if ( vehWeapon->bHasGravity ) {//TESTME: is this all we need to do? missile->s.pos.trType = TR_GRAVITY; } missile->classname = "vehicle_proj"; missile->damage = vehWeapon->iDamage; missile->splashDamage = vehWeapon->iSplashDamage; missile->splashRadius = vehWeapon->fSplashRadius; // HUGE HORRIBLE HACK if (ent->owner && ent->owner->s.number==0) { //Should only be for speeders - mainly for t2_trip if (ent->m_pVehicle->m_pVehicleInfo && ent->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER) { missile->damage *= 20.0f; missile->splashDamage *= 20.0f; missile->splashRadius *= 20.0f; } } //FIXME: externalize some of these properties? missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->clipmask = MASK_SHOT; //Maybe by checking flags...? if ( vehWeapon->bSaberBlockable ) { missile->clipmask |= CONTENTS_LIGHTSABER; } /* if ( (vehWeapon->iFlags&VWF_KNOCKBACK) ) { missile->dflags &= ~DAMAGE_DEATH_KNOCKBACK; } if ( (vehWeapon->iFlags&VWF_DISTORTION_TRAIL) ) { missile->s.eFlags |= EF_DISTORTION_TRAIL; } if ( (vehWeapon->iFlags&VWF_RADAR) ) { missile->s.eFlags |= EF_RADAROBJECT; } */ missile->s.weapon = WP_BLASTER;//does this really matter? // Make it easier to hit things VectorCopy( mins, missile->mins ); VectorCopy( maxs, missile->maxs ); //some slightly different stuff for things with bboxes if ( vehWeapon->fWidth || vehWeapon->fHeight ) {//we assume it's a rocket-like thing missile->methodOfDeath = MOD_ROCKET; missile->splashMethodOfDeath = MOD_ROCKET;// ?SPLASH; // we don't want it to ever bounce missile->bounceCount = 0; missile->mass = 10; } else {//a blaster-laser-like thing missile->s.weapon = WP_BLASTER;//does this really matter? missile->methodOfDeath = MOD_EMPLACED;//MOD_TURBLAST; //count as a heavy weap missile->splashMethodOfDeath = MOD_EMPLACED;//MOD_TURBLAST;// ?SPLASH; // we don't want it to bounce forever missile->bounceCount = 8; } if ( vehWeapon->iHealth ) {//the missile can take damage missile->health = vehWeapon->iHealth; missile->takedamage = qtrue; missile->contents = MASK_SHOT; missile->e_DieFunc = dieF_WP_ExplosiveDie;//dieF_RocketDie; } //set veh as cgame side owner for purpose of fx overrides if (ent->m_pVehicle && ent->m_pVehicle->m_pPilot) { missile->owner = ent->m_pVehicle->m_pPilot; } else { missile->owner = ent; } missile->s.otherEntityNum = ent->s.number; missile->s.otherEntityNum2 = (vehWeapon-&g_vehWeaponInfo[0]); if ( vehWeapon->iLifeTime ) {//expire after a time if ( vehWeapon->bExplodeOnExpire ) {//blow up when your lifetime is up missile->e_ThinkFunc = thinkF_WP_Explode;//FIXME: custom func? } else {//just remove yourself missile->e_ThinkFunc = thinkF_G_FreeEntity;//FIXME: custom func? } missile->nextthink = level.time + vehWeapon->iLifeTime; } if ( vehWeapon->fHoming ) {//homing missile //crap, we need to set up the homing stuff like it is in MP... WP_RocketLock( ent, 16384 ); if ( ent->client && ent->client->rocketLockIndex != ENTITYNUM_NONE ) { int dif = 0; float rTime; rTime = ent->client->rocketLockTime; if (rTime == -1) { rTime = ent->client->rocketLastValidTime; } if ( !vehWeapon->iLockOnTime ) {//no minimum lock-on time dif = 10;//guaranteed lock-on } else { float lockTimeInterval = vehWeapon->iLockOnTime/16.0f; dif = ( level.time - rTime ) / lockTimeInterval; } if (dif < 0) { dif = 0; } //It's 10 even though it locks client-side at 8, because we want them to have a sturdy lock first, and because there's a slight difference in time between server and client if ( dif >= 10 && rTime != -1 ) { missile->enemy = &g_entities[ent->client->rocketLockIndex]; if (missile->enemy && missile->enemy->client && missile->enemy->health > 0 && !OnSameTeam(ent, missile->enemy)) { //if enemy became invalid, died, or is on the same team, then don't seek it missile->spawnflags |= 1;//just to let it know it should be faster... FIXME: EXTERNALIZE missile->speed = vehWeapon->fSpeed; missile->angle = vehWeapon->fHoming; if ( vehWeapon->iLifeTime ) {//expire after a time missile->disconnectDebounceTime = level.time + vehWeapon->iLifeTime; missile->lockCount = (int)(vehWeapon->bExplodeOnExpire); } missile->e_ThinkFunc = thinkF_rocketThink; missile->nextthink = level.time + VEH_HOMING_MISSILE_THINK_TIME; //FIXME: implement radar in SP? //missile->s.eFlags |= EF_RADAROBJECT; } } ent->client->rocketLockIndex = ENTITYNUM_NONE; ent->client->rocketLockTime = 0; ent->client->rocketTargetTime = 0; VectorCopy( dir, missile->movedir ); missile->random = 1.0f;//FIXME: externalize? } } } else {//traceline //FIXME: implement } }
static void WP_FireConcussion( gentity_t *ent ) {//a fast rocket-like projectile vec3_t start; int damage = weaponData[WP_CONCUSSION].damage; float vel = CONC_VELOCITY; if (ent->s.number >= MAX_CLIENTS) { vec3_t angles; vectoangles(forwardVec, angles); angles[PITCH] += ( crandom() * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angles[YAW] += ( crandom() * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f AngleVectors(angles, forwardVec, vrightVec, up); } //hold us still for a bit ent->client->ps.pm_time = 300; ent->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; //add viewkick if ( ent->s.number < MAX_CLIENTS//player only && !cg.renderingThirdPerson )//gives an advantage to being in 3rd person, but would look silly otherwise {//kick the view back cg.kick_angles[PITCH] = Q_flrand( -10, -15 ); cg.kick_time = level.time; } VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall gentity_t *missile = CreateMissile( start, forwardVec, vel, 10000, ent, qfalse ); missile->classname = "conc_proj"; missile->s.weapon = WP_CONCUSSION; missile->mass = 10; // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = CONC_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = CONC_NPC_DAMAGE_NORMAL; } else { damage = CONC_NPC_DAMAGE_HARD; } } // Make it easier to hit things VectorSet( missile->maxs, ROCKET_SIZE, ROCKET_SIZE, ROCKET_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); missile->damage = damage; missile->dflags = DAMAGE_EXTRA_KNOCKBACK; missile->methodOfDeath = MOD_CONC; missile->splashMethodOfDeath = MOD_CONC; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = weaponData[WP_CONCUSSION].splashDamage; missile->splashRadius = weaponData[WP_CONCUSSION].splashRadius; // we don't want it to ever bounce missile->bounceCount = 0; }
//--------------------------------------------------------- static void WP_BowcasterMainFire( gentity_t *ent ) //--------------------------------------------------------- { int damage = weaponData[WP_BOWCASTER].damage, count; float vel; vec3_t angs, dir, start; gentity_t *missile; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = BOWCASTER_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = BOWCASTER_NPC_DAMAGE_NORMAL; } else { damage = BOWCASTER_NPC_DAMAGE_HARD; } } count = ( level.time - ent->client->ps.weaponChargeTime ) / BOWCASTER_CHARGE_UNIT; if ( count < 1 ) { count = 1; } else if ( count > 5 ) { count = 5; } if ( !(count & 1 )) { // if we aren't odd, knock us down a level count--; } // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // damage *= 2; // } WP_MissileTargetHint(ent, start, forwardVec); for ( int i = 0; i < count; i++ ) { // create a range of different velocities vel = BOWCASTER_VELOCITY * ( crandom() * BOWCASTER_VEL_RANGE + 1.0f ); vectoangles( forwardVec, angs ); if ( !(ent->client->ps.forcePowersActive&(1<<FP_SEE)) || ent->client->ps.forcePowerLevel[FP_SEE] < FORCE_LEVEL_2 ) {//force sight 2+ gives perfect aim //FIXME: maybe force sight level 3 autoaims some? // add some slop to the fire direction angs[PITCH] += crandom() * BOWCASTER_ALT_SPREAD * 0.2f; angs[YAW] += ((i+0.5f) * BOWCASTER_ALT_SPREAD - count * 0.5f * BOWCASTER_ALT_SPREAD ); if ( ent->NPC ) { angs[PITCH] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) ); angs[YAW] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) ); } } AngleVectors( angs, dir, NULL, NULL ); missile = CreateMissile( start, dir, vel, 10000, ent ); missile->classname = "bowcaster_proj"; missile->s.weapon = WP_BOWCASTER; VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // missile->flags |= FL_OVERCHARGED; // } missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->methodOfDeath = MOD_BOWCASTER; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = weaponData[WP_BOWCASTER].splashDamage; missile->splashRadius = weaponData[WP_BOWCASTER].splashRadius; // we don't want it to bounce missile->bounceCount = 0; ent->client->sess.missionStats.shotsFired++; } }
//--------------------------------------------------------- void WP_FireRocket( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { vec3_t start; int damage = weaponData[WP_ROCKET_LAUNCHER].damage; float vel = ROCKET_VELOCITY; if ( alt_fire ) { vel *= 0.5f; } VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall gentity_t *missile = CreateMissile( start, forwardVec, vel, 10000, ent, alt_fire ); missile->classname = "rocket_proj"; missile->s.weapon = WP_ROCKET_LAUNCHER; missile->mass = 10; // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = ROCKET_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = ROCKET_NPC_DAMAGE_NORMAL; } else { damage = ROCKET_NPC_DAMAGE_HARD; } if (ent->client && ent->client->NPC_class==CLASS_BOBAFETT) { damage = damage/2; } } if ( alt_fire ) { int lockEntNum, lockTime; if ( ent->NPC && ent->enemy ) { lockEntNum = ent->enemy->s.number; lockTime = Q_irand( 600, 1200 ); } else { lockEntNum = g_rocketLockEntNum; lockTime = g_rocketLockTime; } // we'll consider attempting to lock this little poochie onto some baddie. if ( (lockEntNum > 0||ent->NPC&&lockEntNum>=0) && lockEntNum < ENTITYNUM_WORLD && lockTime > 0 ) { // take our current lock time and divide that by 8 wedge slices to get the current lock amount int dif = ( level.time - lockTime ) / ( 1200.0f / 8.0f ); if ( dif < 0 ) { dif = 0; } else if ( dif > 8 ) { dif = 8; } // if we are fully locked, always take on the enemy. // Also give a slight advantage to higher, but not quite full charges. // Finally, just give any amount of charge a very slight random chance of locking. if ( dif == 8 || random() * dif > 2 || random() > 0.97f ) { missile->enemy = &g_entities[lockEntNum]; if ( missile->enemy && missile->enemy->inuse )//&& DistanceSquared( missile->currentOrigin, missile->enemy->currentOrigin ) < 262144 && InFOV( missile->currentOrigin, missile->enemy->currentOrigin, missile->enemy->client->ps.viewangles, 45, 45 ) ) { if ( missile->enemy->client && (missile->enemy->client->ps.forcePowersKnown&(1<<FP_PUSH)) && missile->enemy->client->ps.forcePowerLevel[FP_PUSH] > FORCE_LEVEL_0 ) {//have force push, don't flee from homing rockets } else { vec3_t dir, dir2; AngleVectors( missile->enemy->currentAngles, dir, NULL, NULL ); AngleVectors( ent->client->renderInfo.eyeAngles, dir2, NULL, NULL ); if ( DotProduct( dir, dir2 ) < 0.0f ) { G_StartFlee( missile->enemy, ent, missile->enemy->currentOrigin, AEL_DANGER_GREAT, 3000, 5000 ); if ( !TIMER_Done( missile->enemy, "flee" ) ) { TIMER_Set( missile->enemy, "rocketChasing", 500 ); } } } } } } VectorCopy( forwardVec, missile->movedir ); missile->e_ThinkFunc = thinkF_rocketThink; missile->random = 1.0f; missile->nextthink = level.time + ROCKET_ALT_THINK_TIME; } // Make it easier to hit things VectorSet( missile->maxs, ROCKET_SIZE, ROCKET_SIZE, ROCKET_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; if ( alt_fire ) { missile->methodOfDeath = MOD_ROCKET_ALT; missile->splashMethodOfDeath = MOD_ROCKET_ALT;// ?SPLASH; } else { missile->methodOfDeath = MOD_ROCKET; missile->splashMethodOfDeath = MOD_ROCKET;// ?SPLASH; } missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = weaponData[WP_ROCKET_LAUNCHER].splashDamage; missile->splashRadius = weaponData[WP_ROCKET_LAUNCHER].splashRadius; // we don't want it to ever bounce missile->bounceCount = 0; }
//--------------------------------------------------------- void WP_FireTuskenRifle( gentity_t *ent ) //--------------------------------------------------------- { vec3_t start; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall if ( !(ent->client->ps.forcePowersActive&(1<<FP_SEE)) || ent->client->ps.forcePowerLevel[FP_SEE] < FORCE_LEVEL_2 ) {//force sight 2+ gives perfect aim //FIXME: maybe force sight level 3 autoaims some? if ( ent->NPC && ent->NPC->currentAim < 5 ) { vec3_t angs; vectoangles( forwardVec, angs ); if ( ent->client->NPC_class == CLASS_IMPWORKER ) {//*sigh*, hack to make impworkers less accurate without affecteing imperial officer accuracy angs[PITCH] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angs[YAW] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f } else { angs[PITCH] += ( crandom() * ((5-ent->NPC->currentAim)*0.25f) ); angs[YAW] += ( crandom() * ((5-ent->NPC->currentAim)*0.25f) ); } AngleVectors( angs, forwardVec, NULL, NULL ); } } WP_MissileTargetHint(ent, start, forwardVec); gentity_t *missile = CreateMissile( start, forwardVec, TUSKEN_RIFLE_VEL, 10000, ent, qfalse ); missile->classname = "trifle_proj"; missile->s.weapon = WP_TUSKEN_RIFLE; if ( ent->s.number < MAX_CLIENTS || g_spskill->integer >= 2 ) { missile->damage = TUSKEN_RIFLE_DAMAGE_HARD; } else if ( g_spskill->integer > 0 ) { missile->damage = TUSKEN_RIFLE_DAMAGE_MEDIUM; } else { missile->damage = TUSKEN_RIFLE_DAMAGE_EASY; } missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->methodOfDeath = MOD_BRYAR;//??? missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; // we don't want it to bounce forever missile->bounceCount = 8; }
//--------------------------------------------------------- static void WP_RepeaterAltFire( gentity_t *ent ) //--------------------------------------------------------- { vec3_t start; int damage = weaponData[WP_REPEATER].altDamage; gentity_t *missile = NULL; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall if ( ent->client && ent->client->NPC_class == CLASS_GALAKMECH ) { missile = CreateMissile( start, ent->client->hiddenDir, ent->client->hiddenDist, 10000, ent, qtrue ); } else { WP_MissileTargetHint(ent, start, forwardVec); missile = CreateMissile( start, forwardVec, REPEATER_ALT_VELOCITY, 10000, ent, qtrue ); } missile->classname = "repeater_alt_proj"; missile->s.weapon = WP_REPEATER; missile->mass = 10; // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = REPEATER_ALT_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = REPEATER_ALT_NPC_DAMAGE_NORMAL; } else { damage = REPEATER_ALT_NPC_DAMAGE_HARD; } } VectorSet( missile->maxs, REPEATER_ALT_SIZE, REPEATER_ALT_SIZE, REPEATER_ALT_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); missile->s.pos.trType = TR_GRAVITY; missile->s.pos.trDelta[2] += 40.0f; //give a slight boost in the upward direction // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // missile->flags |= FL_OVERCHARGED; // damage *= 2; // } missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->methodOfDeath = MOD_REPEATER_ALT; missile->splashMethodOfDeath = MOD_REPEATER_ALT; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = weaponData[WP_REPEATER].altSplashDamage; missile->splashRadius = weaponData[WP_REPEATER].altSplashRadius; // we don't want it to bounce forever missile->bounceCount = 8; }