/* =============== FireWeapon3 =============== */ void FireWeapon3( gentity_t *ent ) { if ( ent->client ) { // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); } else { AngleVectors( ent->s.angles2, forward, right, up ); VectorCopy( ent->s.pos.trBase, muzzle ); } // fire the specific weapon switch ( ent->s.weapon ) { case WP_ALEVEL3_UPG: bounceBallFire( ent ); break; case WP_ABUILD2: slowBlobFire( ent ); break; default: break; } }
/* =============== areaZapFire =============== */ void areaZapFire( gentity_t *ent ) { trace_t tr; vec3_t end; gentity_t *traceEnt; vec3_t mins, maxs; VectorSet( mins, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH ); VectorSet( maxs, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH ); // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, LEVEL2_AREAZAP_RANGE, forward, end ); trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); if( tr.surfaceFlags & SURF_NOIMPACT ) return; traceEnt = &g_entities[ tr.entityNum ]; if( ( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || ( traceEnt->s.eType == ET_BUILDABLE && BG_FindTeamForBuildable( traceEnt->s.modelindex ) == BIT_HUMANS ) ) && traceEnt->health > 0 ) { G_CreateNewZap( ent, traceEnt ); } }
/* =============== CheckPounceAttack =============== */ qboolean CheckPounceAttack( gentity_t *ent ) { trace_t tr; gentity_t *traceEnt; int damage, timeMax, pounceRange, pounceWidth, payload; if( ent->client->pmext.pouncePayload <= 0 ) return qfalse; // In case the goon lands on his target, he get's one shot after landing payload = ent->client->pmext.pouncePayload; if( !( ent->client->ps.pm_flags & PMF_CHARGE/* || ent->client->ps.weapon == WP_ALEVEL5 */) ) ent->client->pmext.pouncePayload = 0; // Calculate muzzle point AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); // Trace from muzzle to see what we hit if( ent->client->ps.weapon == WP_ALEVEL5) { pounceRange = LEVEL5_POUNCE_RANGE; pounceWidth = LEVEL5_POUNCE_WIDTH; } else { pounceRange = ent->client->ps.weapon == WP_ALEVEL3 ? LEVEL3_POUNCE_RANGE : LEVEL3_POUNCE_UPG_RANGE; pounceWidth = LEVEL3_POUNCE_WIDTH; } G_WideTrace( &tr, ent, pounceRange, pounceWidth, pounceWidth, &traceEnt ); if( traceEnt == NULL ) return qfalse; // Send blood impact if( traceEnt->takedamage ) WideBloodSpurt( ent, traceEnt, &tr, MOD_LEVEL3_POUNCE ); if( !traceEnt->takedamage ) return qfalse; // Deal damage if( ent->client->ps.weapon == WP_ALEVEL5) { timeMax = LEVEL5_POUNCE_TIME; damage = payload * LEVEL5_POUNCE_DMG / timeMax; ent->client->pmext.pouncePayload = 0; G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_LOCDAMAGE, MOD_LEVEL5_POUNCE ); } else { timeMax = ent->client->ps.weapon == WP_ALEVEL3 ? LEVEL3_POUNCE_TIME : LEVEL3_POUNCE_TIME_UPG; damage = payload * LEVEL3_POUNCE_DMG / timeMax; ent->client->pmext.pouncePayload = 0; G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_LOCDAMAGE, MOD_LEVEL3_POUNCE ); } return qtrue; }
/* =============== G_MeleeFireCheck =============== */ qboolean G_MeleeFireCheck( gentity_t *ent ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; // only living beeings can attack if ( ent->client->ps.stats[STAT_HEALTH] <= 0 ) { return qfalse; } // set aiming directions AngleVectors ( ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint ( ent, forward, right, up, muzzle ); VectorMA (muzzle, 32, forward, end); // compensate for lag G_CalcLagTimeAndShiftAllClients( ent ); trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT); // move the clients back to their proper positions if ( level.delagWeapons && ent->client && !(ent->r.svFlags & SVF_BOT) ) { G_UnTimeShiftAllClients( ent ); } if ( tr.surfaceFlags & SURF_NOIMPACT ) { return qfalse; } traceEnt = &g_entities[ tr.entityNum ]; // send blood impact if ( traceEnt->takedamage && traceEnt->client ) { // compensate for lag effects if ( level.delagWeapons && ent->client && !(ent->r.svFlags & SVF_BOT) ) { VectorSubtract( traceEnt->client->saved.currentOrigin, traceEnt->r.currentOrigin, end ); VectorAdd( tr.endpos, end, tr.endpos ); } // snap the endpos to integers, but nudged towards the line SnapVectorTowards( tr.endpos, muzzle ); // create impact entity tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH ); tent->s.eventParm = traceEnt->s.number; } if ( !traceEnt->takedamage) { return qfalse; } G_Damage( traceEnt, ent, ent, forward, tr.endpos, weLi[WP_SHOCKER].damage, 0, MOD_SHOCKER ); return qtrue; }
/* =============== CheckGrabAttack =============== */ void CheckGrabAttack( gentity_t *ent ) { trace_t tr; vec3_t end, dir; gentity_t *traceEnt; // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end ); trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); if( tr.surfaceFlags & SURF_NOIMPACT ) return; traceEnt = &g_entities[ tr.entityNum ]; if( !traceEnt->takedamage ) return; if( traceEnt->client ) { if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) return; if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) return; if( !( traceEnt->client->ps.stats[ STAT_STATE ] & SS_GRABBED ) ) { AngleVectors( traceEnt->client->ps.viewangles, dir, NULL, NULL ); traceEnt->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir ); //event for client side grab effect G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); } traceEnt->client->ps.stats[ STAT_STATE ] |= SS_GRABBED; if( ent->client->ps.weapon == WP_ALEVEL1 ) traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_TIME; else if( ent->client->ps.weapon == WP_ALEVEL1_UPG ) traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_U_TIME; } else if( traceEnt->s.eType == ET_BUILDABLE && traceEnt->s.modelindex == BA_H_MGTURRET ) { if( !traceEnt->lev1Grabbed ) G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); traceEnt->lev1Grabbed = qtrue; traceEnt->lev1GrabTime = level.time; } }
/* =============== CheckVenomAttack =============== */ qboolean CheckVenomAttack( gentity_t *ent ) { trace_t tr; gentity_t *traceEnt; int damage = LEVEL0_BITE_DMG; if( ent->client->ps.weaponTime ) return qfalse; // Calculate muzzle point AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); G_WideTrace( &tr, ent, LEVEL0_BITE_RANGE, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH, &traceEnt ); if( traceEnt == NULL ) return qfalse; if( !traceEnt->takedamage ) return qfalse; if( traceEnt->health <= 0 ) return qfalse; // only allow bites to work against buildings as they are constructing if( traceEnt->s.eType == ET_BUILDABLE ) { if( traceEnt->buildableTeam == TEAM_ALIENS ) return qfalse; if ( !( traceEnt->s.modelindex == BA_H_MGTURRET || traceEnt->s.modelindex == BA_H_MGTURRET2 || traceEnt->s.modelindex == BA_H_TESLAGEN || !traceEnt->spawned ) ) damage = (int)(damage * g_DretchBuildingDamage.value); else damage = (int)(damage * g_DretchTurretDamage.value); if (damage <= 0) return qfalse; } if( traceEnt->client ) { if( traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) return qfalse; if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) return qfalse; } // send blood impact WideBloodSpurt( ent, traceEnt, &tr, MOD_LEVEL0_BITE ); G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_LEVEL0_BITE ); ent->client->ps.weaponTime += LEVEL0_BITE_REPEAT; return qtrue; }
/* =============== CheckGauntletAttack =============== */ qboolean CheckGauntletAttack( gentity_t *ent ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; int damage; // set aiming directions AngleVectors (ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint ( ent, forward, right, up, muzzle ); VectorMA (muzzle, 32, forward, end); trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT); if ( tr.surfaceFlags & SURF_NOIMPACT ) { return qfalse; } if ( ent->client->noclip ) { return qfalse; } traceEnt = &g_entities[ tr.entityNum ]; // send blood impact if ( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; } if ( !traceEnt->takedamage) { return qfalse; } if (ent->client->ps.powerups[PW_QUAD] ) { G_AddEvent( ent, EV_POWERUP_QUAD, 0 ); s_quadFactor = g_quadfactor.value; } else { s_quadFactor = 1; } #if 1 if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) { s_quadFactor *= 2; } #endif damage = 50 * s_quadFactor; G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_GAUNTLET ); return qtrue; }
qbool CheckGauntletAttack(Gentity *ent) { Trace tr; Vec3 end; Gentity *tent; Gentity *traceEnt; int damage; /* set aiming directions */ anglev3s (ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint (ent, forward, right, up, muzzle); saddv3 (muzzle, 32, forward, end); trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT); if(tr.surfaceFlags & SURF_NOIMPACT) return qfalse; if(ent->client->noclip) return qfalse; traceEnt = &g_entities[tr.entityNum]; /* send blood impact */ if(traceEnt->takedamage && traceEnt->client){ tent = G_TempEntity(tr.endpos, EV_MISSILE_HIT); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte(tr.plane.normal); tent->s.weap[WSpri] = ent->s.weap[WSpri]; tent->s.weap[WSsec] = ent->s.weap[WSsec]; tent->s.weap[WShook] = ent->s.weap[WShook]; } if(!traceEnt->takedamage) return qfalse; if(ent->client->ps.powerups[PW_QUAD]){ G_AddEvent(ent, EV_POWERUP_QUAD, 0); s_quadFactor = g_quadfactor.value; }else s_quadFactor = 1; #ifdef MISSIONPACK if(ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->tag == PW_DOUBLER) then s_quadFactor *= 2; #endif damage = 50 * s_quadFactor; G_Damage(traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_GAUNTLET); return qtrue; }
/* =============== FireWeapon2 =============== */ void FireWeapon2( gentity_t *ent ) { if( ent->client ) { // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); } else { AngleVectors( ent->s.angles2, forward, right, up ); VectorCopy( ent->s.pos.trBase, muzzle ); } // fire the specific weapon switch( ent->s.weapon ) { case WP_MACHINEGUN: bulletFire( ent, RIFLE_SPREAD2, RIFLE_DMG2, MOD_MACHINEGUN ); break; case WP_ALEVEL2_UPG: areaZapFire( ent ); break; case WP_PAIN_SAW: painSawFire2( ent ); break; case WP_LUCIFER_CANNON: LCChargeFire( ent, qtrue ); break; case WP_CHAINGUN: bulletFire( ent, CHAINGUN_SPREAD2, CHAINGUN_DMG2, MOD_CHAINGUN ); break; case WP_LAS_GUN: lasGunFire2( ent ); break; case WP_PULSE_RIFLE: prifleStasisFire( ent ); break; case WP_ABUILD: case WP_HBUILD: cancelBuildFire( ent ); break; default: break; } }
void Weapon_GrapplingHook_Fire (gentity_t *ent) { //freeze AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); //freeze if (!ent->client->fireHeld && !ent->client->hook) fire_grapple (ent, muzzle, forward); ent->client->fireHeld = qtrue; }
void Weapon_GrapplingHook_Fire (gentity_t *ent) { /* LQ3A: Take the direction from the viewangles. */ AngleVectors(ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint(ent, forward, right, up, muzzle); if (!ent->client->fireHeld && !ent->client->hook) fire_grapple (ent, muzzle, forward); ent->client->fireHeld = qtrue; }
/* =============== Offhand_Grapple_Fire =============== */ void Offhand_Grapple_Fire(gentity_t *ent) { AngleVectors(ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint(ent, forward, right, up, muzzle); if (!ent->client->fireHeld && !ent->client->hook) fire_grapple(ent, muzzle, forward); ent->client->hookhasbeenfired = qtrue; ent->client->fireHeld = qtrue; }
/* =============== FireWeapon2 =============== */ void FireWeapon2( gentity_t *ent ) { if( ent->client ) { // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); } else { AngleVectors( ent->s.angles2, forward, right, up ); VectorCopy( ent->s.pos.trBase, muzzle ); } // fire the specific weapon switch( ent->s.weapon ) { /*case WP_ALEVEL1: //Blaster_ball( ent, 0); break;*/ case WP_ALEVEL0: explodedretch( ent ); break; case WP_ALEVEL1_UPG: poisonCloud( ent ); break; case WP_ALEVEL2_UPG: areaZapFire( ent ); break; case WP_LUCIFER_CANNON: LCChargeFire( ent, qtrue ); break; case WP_ABUILD: case WP_ABUILD2: case WP_HBUILD: case WP_HBUILD2: cancelBuildFire( ent ); break; case WP_BLASTER: detonate( ent ); break; default: break; } }
/* =============== FireWeapon3 =============== */ void FireWeapon3( gentity_t *ent ) { if( ent->client ) { // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); } else { AngleVectors( ent->s.angles2, forward, right, up ); VectorCopy( ent->s.pos.trBase, muzzle ); } // fire the specific weapon switch( ent->s.weapon ) { case WP_ALEVEL3_UPG: bounceBallFire( ent ); break; case WP_ABUILD: slowBlobFire( ent ); break; case WP_ALEVEL2_UPG: bounceBallFire_level2( ent ); break; case WP_ALEVEL5: Prickles( ent ); break; case WP_ALEVEL4: // FireBreath_tyrant( ent ); break; case WP_MASS_DRIVER: if(g_humanStage.integer == S5 && BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats )) { massDriverFire2( ent ); } break; default: break; } }
void painSawFire( gentity_t *ent ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, PAINSAW_RANGE, forward, end ); G_UnlaggedOn( ent, muzzle, PAINSAW_RANGE ); trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); G_UnlaggedOff( ); if( tr.surfaceFlags & SURF_NOIMPACT ) return; traceEnt = &g_entities[ tr.entityNum ]; // send blood impact if( traceEnt->takedamage ) { vec3_t temp; //hack to get the particle system to line up with the weapon VectorCopy( tr.endpos, temp ); temp[ 2 ] -= 10.0f; if( traceEnt->client ) { tent = G_TempEntity( temp, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; } else tent = G_TempEntity( temp, EV_MISSILE_MISS ); tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; tent->s.generic1 = ent->s.generic1; //weaponMode } if( traceEnt->takedamage ) G_Damage( traceEnt, ent, ent, forward, tr.endpos, PAINSAW_DAMAGE, DAMAGE_NO_KNOCKBACK, MOD_PAINSAW ); }
void Rune_Phase_Use(gentity_t *ent) { vec3_t oldmuzzle,muzzle,forward,right,up,end; trace_t trace, trace2; AngleVectors (ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint ( ent, forward, right, up, muzzle ); if (ent->runetime<level.time) { VectorMA (muzzle, 250, forward, end); trap_Trace (&trace, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); // we didn't hit anything, so exit if ( trace.fraction == 1) return; SnapVectorTowards( trace.endpos, muzzle ); // prepare for firing through the wall VectorCopy (muzzle, oldmuzzle); VectorCopy (trace.endpos, muzzle); VectorMA (muzzle, 96, forward, muzzle); if ( !( trap_PointContents( muzzle, -1 ) & CONTENTS_SOLID )) { // the point isn't inside a wall, so check to see if we are outside the bounds of the level VectorCopy(muzzle,end); end[2]=-10000; trap_Trace (&trace2, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); // if we didn't hit anything after that big a trace, we are outside the level if (trace2.fraction==1) return; TeleportPlayer(ent,muzzle,ent->client->ps.viewangles, qtrue, qtrue); ent->runetime = level.time + RUNE_PHASE_RECHARGE; } } else { //trap_SendServerCommand( ent->s.clientNum, va("print \"Phase is recharging\n\"")); } }
//--------------------------------------------------------- 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 ); }
/* =============== FireWeapon3 =============== */ void FireWeapon3( gentity_t *ent ) { if( ent->client ) { // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); } else { AngleVectors( ent->s.angles2, forward, right, up ); VectorCopy( ent->s.pos.trBase, muzzle ); } // fire the specific weapon switch( ent->s.weapon ) { case WP_ALEVEL3_UPG: bounceBallFire( ent ); break; case WP_ABUILD2: slowBlobFire( ent ); break; // case WP_ALEVEL4: // lockBlobLauncherFire( ent ); //thats right bitch, i'll trap you! //N/B: Trap as in trap, not males dressing up as women. break; /* case WP_HBUILD2: bulletFire( ent, 300, 1, MOD_TRIGGER_HURT ); bulletFire( ent, 300, 1, MOD_TRIGGER_HURT ); bulletFire( ent, 300, 1, MOD_TRIGGER_HURT ); break; */ default: break; } }
/* =============== meleeAttack =============== */ void meleeAttack( gentity_t *ent, float range, float width, int damage, meansOfDeath_t mod ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; vec3_t mins, maxs; VectorSet( mins, -width, -width, -width ); VectorSet( maxs, width, width, width ); // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, range, forward, end ); G_UnlaggedOn( ent, muzzle, range ); trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); G_UnlaggedOff( ); if( tr.surfaceFlags & SURF_NOIMPACT ) return; traceEnt = &g_entities[ tr.entityNum ]; // send blood impact if( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; tent->s.generic1 = ent->s.generic1; //weaponMode } if( traceEnt->takedamage ) G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, mod ); }
/* =============== G_MedkitTarget Look for a possible healing target (a client) in the front. =============== */ gentity_t *G_MedkitTarget( gentity_t *ent ) { trace_t tr; gentity_t *targetEnt = NULL; if( g_humanMedkitRange.value <= 0 || g_humanMedkitWidth.value <= 0 ) return NULL; // Calculate muzzle point AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); G_WideTrace( &tr, ent, g_humanMedkitRange.value, g_humanMedkitWidth.value, g_humanMedkitWidth.value, &targetEnt ); if( ( targetEnt != NULL ) && ( targetEnt->client != NULL ) ) return targetEnt; else return NULL; }
/* ================ G_WideTrace Trace a bounding box against entities, but not the world Also check there is a line of sight between the start and end point ================ */ static void G_WideTrace( trace_t *tr, gentity_t *ent, float range, float width, gentity_t **target ) { vec3_t mins, maxs; vec3_t end; VectorSet( mins, -width, -width, -width ); VectorSet( maxs, width, width, width ); *target = NULL; if( !ent->client ) return; // Set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, range, forward, end ); G_UnlaggedOn( ent, muzzle, range ); // Trace against entities trap_Trace( tr, muzzle, mins, maxs, end, ent->s.number, CONTENTS_BODY ); if( tr->entityNum != ENTITYNUM_NONE ) { *target = &g_entities[ tr->entityNum ]; // Set range to the trace length plus the width, so that the end of the // LOS trace is close to the exterior of the target's bounding box range = Distance( muzzle, tr->endpos ) + width; VectorMA( muzzle, range, forward, end ); // Trace for line of sight against the world trap_Trace( tr, muzzle, NULL, NULL, end, 0, CONTENTS_SOLID ); if( tr->fraction < 1.0f ) *target = NULL; } G_UnlaggedOff( ); }
//--------------------------------------------------------- void FireWeapon( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { float alert = 256; // track shots taken for accuracy tracking. ent->client->ps.persistant[PERS_ACCURACY_SHOTS]++; // set aiming directions if ( ent->s.weapon == WP_DISRUPTOR && alt_fire ) { if ( ent->NPC ) { //snipers must use the angles they actually did their shot trace with AngleVectors( ent->lastAngles, wpFwd, wpVright, wpUp ); } } else if ( ent->s.weapon == WP_ATST_SIDE || ent->s.weapon == WP_ATST_MAIN ) { vec3_t delta1, enemy_org1, muzzle1; vec3_t angleToEnemy1; VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle1 ); if ( !ent->s.number ) {//player driving an AT-ST //SIGH... because we can't anticipate alt-fire, must calc muzzle here and now mdxaBone_t boltMatrix; int bolt; if ( ent->client->ps.weapon == WP_ATST_MAIN ) {//FIXME: alt_fire should fire both barrels, but slower? if ( ent->alt_fire ) { bolt = ent->handRBolt; } else { bolt = ent->handLBolt; } } else {// ATST SIDE weapons if ( ent->alt_fire ) { if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_light_blaster_cann" ) ) {//don't have it! return; } bolt = ent->genericBolt2; } else { if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_concussion_charger" ) ) {//don't have it! return; } bolt = ent->genericBolt1; } } vec3_t yawOnlyAngles = {0, ent->currentAngles[YAW], 0}; if ( ent->currentAngles[YAW] != ent->client->ps.legsYaw ) { yawOnlyAngles[YAW] = ent->client->ps.legsYaw; } gi.G2API_GetBoltMatrix( ent->ghoul2, ent->playerModel, bolt, &boltMatrix, yawOnlyAngles, ent->currentOrigin, (cg.time?cg.time:level.time), NULL, ent->s.modelScale ); // work the matrix axis stuff into the original axis and origins used. gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->client->renderInfo.muzzlePoint ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, ent->client->renderInfo.muzzleDir ); ent->client->renderInfo.mPCalcTime = level.time; AngleVectors( ent->client->ps.viewangles, wpFwd, wpVright, wpUp ); //CalcMuzzlePoint( ent, wpFwd, vright, wpUp, wpMuzzle, 0 ); } else if ( !ent->enemy ) {//an NPC with no enemy to auto-aim at VectorCopy( ent->client->renderInfo.muzzleDir, wpFwd ); } else {//NPC, auto-aim at enemy CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 ); VectorSubtract (enemy_org1, muzzle1, delta1); vectoangles ( delta1, angleToEnemy1 ); AngleVectors (angleToEnemy1, wpFwd, wpVright, wpUp); } } else if ( ent->s.weapon == WP_BOT_LASER && ent->enemy ) { vec3_t delta1, enemy_org1, muzzle1; vec3_t angleToEnemy1; CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 ); CalcEntitySpot( ent, SPOT_WEAPON, muzzle1 ); VectorSubtract (enemy_org1, muzzle1, delta1); vectoangles ( delta1, angleToEnemy1 ); AngleVectors (angleToEnemy1, wpFwd, wpVright, wpUp); } else { AngleVectors( ent->client->ps.viewangles, wpFwd, wpVright, wpUp ); } ent->alt_fire = alt_fire; CalcMuzzlePoint ( ent, wpFwd, wpVright, wpUp, wpMuzzle , 0); // fire the specific weapon switch( ent->s.weapon ) { // Player weapons //----------------- case WP_SABER: return; break; case WP_BRYAR_PISTOL: WP_FireBryarPistol( ent, alt_fire ); break; case WP_BLASTER: WP_FireBlaster( ent, alt_fire ); break; case WP_DISRUPTOR: alert = 50; // if you want it to alert enemies, remove this WP_FireDisruptor( ent, alt_fire ); break; case WP_BOWCASTER: WP_FireBowcaster( ent, alt_fire ); break; case WP_REPEATER: WP_FireRepeater( ent, alt_fire ); break; case WP_DEMP2: WP_FireDEMP2( ent, alt_fire ); break; case WP_FLECHETTE: WP_FireFlechette( ent, alt_fire ); break; case WP_ROCKET_LAUNCHER: WP_FireRocket( ent, alt_fire ); break; case WP_THERMAL: WP_FireThermalDetonator( ent, alt_fire ); break; case WP_TRIP_MINE: alert = 0; // if you want it to alert enemies, remove this WP_PlaceLaserTrap( ent, alt_fire ); break; case WP_DET_PACK: alert = 0; // if you want it to alert enemies, remove this WP_FireDetPack( ent, alt_fire ); break; case WP_BOT_LASER: WP_BotLaser( ent ); break; case WP_EMPLACED_GUN: // doesn't care about whether it's alt-fire or not. We can do an alt-fire if needed WP_EmplacedFire( ent ); break; case WP_MELEE: alert = 0; // if you want it to alert enemies, remove this WP_Melee( ent ); break; case WP_ATST_MAIN: WP_ATSTMainFire( ent ); break; case WP_ATST_SIDE: // TEMP if ( alt_fire ) { // WP_FireRocket( ent, qfalse ); WP_ATSTSideAltFire(ent); } else { if ( ent->s.number == 0 && ent->client->ps.vehicleModel ) { WP_ATSTMainFire( ent ); } else { WP_ATSTSideFire(ent); } } break; case WP_TIE_FIGHTER: // TEMP WP_EmplacedFire( ent ); break; case WP_RAPID_FIRE_CONC: // TEMP if ( alt_fire ) { WP_FireRepeater( ent, alt_fire ); } else { WP_EmplacedFire( ent ); } break; case WP_STUN_BATON: WP_FireStunBaton( ent, alt_fire ); break; case WP_BLASTER_PISTOL: // enemy version WP_FireBryarPistol( ent, qfalse ); // never an alt-fire? break; // case WP_TRICORDER: // WP_TricorderScan( ent, alt_fire ); // break; default: return; break; } if ( !ent->s.number ) { if ( ent->s.weapon == WP_FLECHETTE || (ent->s.weapon == WP_BOWCASTER && !alt_fire) ) {//these can fire multiple shots, count them individually within the firing functions } else if ( W_AccuracyLoggableWeapon( ent->s.weapon, alt_fire, MOD_UNKNOWN ) ) { ent->client->sess.missionStats.shotsFired++; } } // We should probably just use this as a default behavior, in special cases, just set alert to false. if ( ent->s.number == 0 && alert > 0 ) { AddSoundEvent( ent, wpMuzzle, alert, AEL_DISCOVERED ); AddSightEvent( ent, wpMuzzle, alert*2, AEL_DISCOVERED, 20 ); } }
void Bullet_Fire (gentity_t *ent, float spread, int damage ) { trace_t tr; vec3_t end; #if 1 vec3_t impactpoint, bouncedir; #endif float r, f, d; float u; gentity_t *tent; gentity_t *traceEnt; int i, passent; vec3_t forward, right, up; AngleVectors (ent->client->ps.viewangles, forward, right, up); CalcMuzzlePoint ( ent, forward, right, up, muzzle ); ent->client->accuracy_shots++; f = ((float)(ent->client->accuracy_shots % SPIRAL_SIZE)) / SPIRAL_SIZE; // 0 >= f >= 1 d = (f+(1/SPIRAL_SIZE)) * 2.0 * M_PI; damage *= s_quadFactor; //Com_Printf("f: %f, d: %f\n, a: %i", f, d, ent->client->accuracy_shots); u = sin(d) * (f * spread); r = cos(d) * (f * spread); //Com_Printf("end1 : [%f, %f, %f]\n", end[0], end[1], end[2]); VectorMA (muzzle, 8192, forward, end); //Com_Printf("end2 : [%f, %f, %f]\n", end[0], end[1], end[2]); //Com_Printf("right : [%f, %f, %f]\n", right[0], right[1], right[2]); VectorMA (end, r, right, end); //Com_Printf("end3 : [%f, %f, %f]\n", end[0], end[1], end[2]); //Com_Printf("up : [%f, %f, %f]\n", up[0], up[1], up[2]); VectorMA (end, u, up, end); //Com_Printf("end4 : [%f, %f, %f]\n", end[0], end[1], end[2]); passent = ent->s.number; for (i = 0; i < 10; i++) { trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT); if ( tr.surfaceFlags & SURF_NOIMPACT ) { return; } traceEnt = &g_entities[ tr.entityNum ]; // snap the endpos to integers, but nudged towards the line SnapVectorTowards( tr.endpos, muzzle ); // send bullet impact if ( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH ); tent->s.eventParm = traceEnt->s.number; if( LogAccuracyHit( traceEnt, ent ) ) { ent->client->accuracy_hits++; } } else { tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL ); tent->s.eventParm = DirToByte( tr.plane.normal ); } tent->s.otherEntityNum = ent->s.number; if ( traceEnt->takedamage) { #if 1 if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) { if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) { G_BounceProjectile( muzzle, impactpoint, bouncedir, end ); VectorCopy( impactpoint, muzzle ); // the player can hit him/herself with the bounced rail passent = ENTITYNUM_NONE; } else { VectorCopy( tr.endpos, muzzle ); passent = traceEnt->s.number; } continue; } else { #endif G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_MACHINEGUN); #if 1 } #endif } break; } }
void CalcEntitySpot ( const gentity_t *ent, const spot_t spot, vec3_t point ) { vec3_t forward, up, right; vec3_t start, end; trace_t tr; if ( !ent ) { return; } ViewHeightFix(ent); switch ( spot ) { case SPOT_ORIGIN: if(VectorCompare(ent->currentOrigin, vec3_origin)) {//brush VectorSubtract(ent->absmax, ent->absmin, point);//size VectorMA(ent->absmin, 0.5, point, point); } else { VectorCopy ( ent->currentOrigin, point ); } break; case SPOT_CHEST: case SPOT_HEAD: if ( ent->client && VectorLengthSquared( ent->client->renderInfo.eyePoint ) && (ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD) ) {//Actual tag_head eyespot! //FIXME: Stasis aliens may have a problem here... VectorCopy( ent->client->renderInfo.eyePoint, point ); if ( ent->client->NPC_class == CLASS_ATST ) {//adjust up some point[2] += 28;//magic number :) } if ( ent->NPC ) {//always aim from the center of my bbox, so we don't wiggle when we lean forward or backwards point[0] = ent->currentOrigin[0]; point[1] = ent->currentOrigin[1]; } else if ( !ent->s.number ) { SubtractLeanOfs( ent, point ); } } else { VectorCopy ( ent->currentOrigin, point ); if ( ent->client ) { point[2] += ent->client->ps.viewheight; } } if ( spot == SPOT_CHEST && ent->client ) { if ( ent->client->NPC_class != CLASS_ATST ) {//adjust up some point[2] -= ent->maxs[2]*0.2f; } } break; case SPOT_HEAD_LEAN: if ( ent->client && VectorLengthSquared( ent->client->renderInfo.eyePoint ) && (ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD) ) {//Actual tag_head eyespot! //FIXME: Stasis aliens may have a problem here... VectorCopy( ent->client->renderInfo.eyePoint, point ); if ( ent->client->NPC_class == CLASS_ATST ) {//adjust up some point[2] += 28;//magic number :) } if ( ent->NPC ) {//always aim from the center of my bbox, so we don't wiggle when we lean forward or backwards point[0] = ent->currentOrigin[0]; point[1] = ent->currentOrigin[1]; } else if ( !ent->s.number ) { SubtractLeanOfs( ent, point ); } //NOTE: automatically takes leaning into account! } else { VectorCopy ( ent->currentOrigin, point ); if ( ent->client ) { point[2] += ent->client->ps.viewheight; } //AddLeanOfs ( ent, point ); } break; //FIXME: implement... //case SPOT_CHEST: //Returns point 3/4 from tag_torso to tag_head? //break; case SPOT_LEGS: VectorCopy ( ent->currentOrigin, point ); point[2] += (ent->mins[2] * 0.5); break; case SPOT_WEAPON: if( ent->NPC && !VectorCompare( ent->NPC->shootAngles, vec3_origin ) && !VectorCompare( ent->NPC->shootAngles, ent->client->ps.viewangles )) { AngleVectors( ent->NPC->shootAngles, forward, right, up ); } else { AngleVectors( ent->client->ps.viewangles, forward, right, up ); } CalcMuzzlePoint( (gentity_t*)ent, forward, right, up, point, 0 ); //NOTE: automatically takes leaning into account! break; case SPOT_GROUND: // if entity is on the ground, just use it's absmin if ( ent->s.groundEntityNum != -1 ) { VectorCopy( ent->currentOrigin, point ); point[2] = ent->absmin[2]; break; } // if it is reasonably close to the ground, give the point underneath of it VectorCopy( ent->currentOrigin, start ); start[2] = ent->absmin[2]; VectorCopy( start, end ); end[2] -= 64; gi.trace( &tr, start, ent->mins, ent->maxs, end, ent->s.number, MASK_PLAYERSOLID, G2_NOCOLLIDE, 0 ); if ( tr.fraction < 1.0 ) { VectorCopy( tr.endpos, point); break; } // otherwise just use the origin VectorCopy( ent->currentOrigin, point ); break; default: VectorCopy ( ent->currentOrigin, point ); break; } }
void NPC_BSSniper_Attack( void ) { //Don't do anything if we're hurt if ( NPC->painDebounceTime > level.time ) { NPC_UpdateAngles( qtrue, qtrue ); return; } //NPC_CheckEnemy( qtrue, qfalse ); //If we don't have an enemy, just idle if ( NPC_CheckEnemyExt() == qfalse )//!NPC->enemy )// { NPC->enemy = NULL; NPC_BSSniper_Patrol();//FIXME: or patrol? return; } if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//going to run NPC_UpdateAngles( qtrue, qtrue ); return; } if ( !NPC->enemy ) {//WTF? somehow we lost our enemy? NPC_BSSniper_Patrol();//FIXME: or patrol? return; } enemyLOS = enemyCS = qfalse; AImove = qtrue; faceEnemy = qfalse; shoot = qfalse; enemyDist = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ); if ( enemyDist < 16384 )//128 squared {//too close, so switch to primary fire if ( NPC->client->ps.weapon == WP_DISRUPTOR ) {//sniping... should be assumed if ( NPCInfo->scriptFlags & SCF_ALT_FIRE ) {//use primary fire trace_t trace; gi.trace ( &trace, NPC->enemy->currentOrigin, NPC->enemy->mins, NPC->enemy->maxs, NPC->currentOrigin, NPC->enemy->s.number, NPC->enemy->clipmask, G2_NOCOLLIDE, 0 ); if ( !trace.allsolid && !trace.startsolid && (trace.fraction == 1.0 || trace.entityNum == NPC->s.number ) ) {//he can get right to me NPCInfo->scriptFlags &= ~SCF_ALT_FIRE; //reset fire-timing variables NPC_ChangeWeapon( WP_DISRUPTOR ); NPC_UpdateAngles( qtrue, qtrue ); return; } } //FIXME: switch back if he gets far away again? } } else if ( enemyDist > 65536 )//256 squared { if ( NPC->client->ps.weapon == WP_DISRUPTOR ) {//sniping... should be assumed if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) ) {//use primary fire NPCInfo->scriptFlags |= SCF_ALT_FIRE; //reset fire-timing variables NPC_ChangeWeapon( WP_DISRUPTOR ); NPC_UpdateAngles( qtrue, qtrue ); return; } } } Sniper_UpdateEnemyPos(); //can we see our target? if ( NPC_ClearLOS( NPC->enemy ) )//|| (NPCInfo->stats.aim >= 5 && gi.inPVS( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin )) ) { NPCInfo->enemyLastSeenTime = level.time; VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation ); enemyLOS = qtrue; float maxShootDist = NPC_MaxDistSquaredForWeapon(); if ( enemyDist < maxShootDist ) { vec3_t fwd, right, up, muzzle, end; trace_t tr; AngleVectors( NPC->client->ps.viewangles, fwd, right, up ); CalcMuzzlePoint( NPC, fwd, right, up, muzzle, 0 ); VectorMA( muzzle, 8192, fwd, end ); gi.trace ( &tr, muzzle, NULL, NULL, end, NPC->s.number, MASK_SHOT, G2_RETURNONHIT, 0 ); int hit = tr.entityNum; //can we shoot our target? if ( Sniper_EvaluateShot( hit ) ) { enemyCS = qtrue; } } } /* else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) ) { NPCInfo->enemyLastSeenTime = level.time; faceEnemy = qtrue; } */ if ( enemyLOS ) {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot? faceEnemy = qtrue; } if ( enemyCS ) { shoot = qtrue; } else if ( level.time - NPCInfo->enemyLastSeenTime > 3000 ) {//Hmm, have to get around this bastard... FIXME: this NPCInfo->enemyLastSeenTime builds up when ducked seems to make them want to run when they uncrouch Sniper_ResolveBlockedShot(); } //Check for movement to take care of Sniper_CheckMoveState(); //See if we should override shooting decision with any special considerations Sniper_CheckFireState(); if ( AImove ) {//move toward goal if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist > 10000 ) )//100 squared { AImove = Sniper_Move(); } else { AImove = qfalse; } } if ( !AImove ) { if ( !TIMER_Done( NPC, "duck" ) ) { if ( TIMER_Done( NPC, "watch" ) ) {//not while watching ucmd.upmove = -127; } } //FIXME: what about leaning? //FIXME: also, when stop ducking, start looking, if enemy can see me, chance of ducking back down again } else {//stop ducking! TIMER_Set( NPC, "duck", -1 ); } if ( TIMER_Done( NPC, "duck" ) && TIMER_Done( NPC, "watch" ) && (TIMER_Get( NPC, "attackDelay" )-level.time) > 1000 && NPC->attackDebounceTime < level.time ) { if ( enemyLOS && (NPCInfo->scriptFlags&SCF_ALT_FIRE) ) { if ( NPC->fly_sound_debounce_time < level.time ) { NPC->fly_sound_debounce_time = level.time + 2000; } } } if ( !faceEnemy ) {//we want to face in the dir we're running if ( AImove ) {//don't run away and shoot NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW]; NPCInfo->desiredPitch = 0; shoot = qfalse; } NPC_UpdateAngles( qtrue, qtrue ); } else// if ( faceEnemy ) {//face the enemy Sniper_FaceEnemy(); } if ( NPCInfo->scriptFlags&SCF_DONT_FIRE ) { shoot = qfalse; } //FIXME: don't shoot right away! if ( shoot ) {//try to shoot if it's time if ( TIMER_Done( NPC, "attackDelay" ) ) { WeaponThink( qtrue ); if ( ucmd.buttons&(BUTTON_ATTACK|BUTTON_ALT_ATTACK) ) { G_SoundOnEnt( NPC, CHAN_WEAPON, "sound/null.wav" ); } //took a shot, now hide if ( !(NPC->spawnflags&SPF_NO_HIDE) && !Q_irand( 0, 1 ) ) { //FIXME: do this if in combat point and combat point has duck-type cover... also handle lean-type cover Sniper_StartHide(); } else { TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime-level.time ); } } } }
void Sniper_FaceEnemy( void ) { //FIXME: the ones behind kill holes are facing some arbitrary direction and not firing //FIXME: If actually trying to hit enemy, don't fire unless enemy is at least in front of me? //FIXME: need to give designers option to make them not miss first few shots if ( NPC->enemy ) { vec3_t muzzle, target, angles, forward, right, up; //Get the positions AngleVectors( NPC->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( NPC, forward, right, up, muzzle, 0 ); //CalcEntitySpot( NPC, SPOT_WEAPON, muzzle ); CalcEntitySpot( NPC->enemy, SPOT_ORIGIN, target ); if ( enemyDist > 65536 && NPCInfo->stats.aim < 5 )//is 256 squared, was 16384 (128*128) { if ( NPC->count < (5-NPCInfo->stats.aim) ) {//miss a few times first if ( shoot && TIMER_Done( NPC, "attackDelay" ) && level.time >= NPCInfo->shotTime ) {//ready to fire again qboolean aimError = qfalse; qboolean hit = qtrue; int tryMissCount = 0; trace_t trace; GetAnglesForDirection( muzzle, target, angles ); AngleVectors( angles, forward, right, up ); while ( hit && tryMissCount < 10 ) { tryMissCount++; if ( !Q_irand( 0, 1 ) ) { aimError = qtrue; if ( !Q_irand( 0, 1 ) ) { VectorMA( target, NPC->enemy->maxs[2]*Q_flrand(1.5, 4), right, target ); } else { VectorMA( target, NPC->enemy->mins[2]*Q_flrand(1.5, 4), right, target ); } } if ( !aimError || !Q_irand( 0, 1 ) ) { if ( !Q_irand( 0, 1 ) ) { VectorMA( target, NPC->enemy->maxs[2]*Q_flrand(1.5, 4), up, target ); } else { VectorMA( target, NPC->enemy->mins[2]*Q_flrand(1.5, 4), up, target ); } } gi.trace( &trace, muzzle, vec3_origin, vec3_origin, target, NPC->s.number, MASK_SHOT, G2_NOCOLLIDE, 0 ); hit = Sniper_EvaluateShot( trace.entityNum ); } NPC->count++; } else { if ( !enemyLOS ) { NPC_UpdateAngles( qtrue, qtrue ); return; } } } else {//based on distance, aim value, difficulty and enemy movement, miss //FIXME: incorporate distance as a factor? int missFactor = 8-(NPCInfo->stats.aim+g_spskill->integer) * 3; if ( missFactor > ENEMY_POS_LAG_STEPS ) { missFactor = ENEMY_POS_LAG_STEPS; } else if ( missFactor < 0 ) {//??? missFactor = 0 ; } VectorCopy( NPCInfo->enemyLaggedPos[missFactor], target ); } GetAnglesForDirection( muzzle, target, angles ); } else { target[2] += Q_flrand( 0, NPC->enemy->maxs[2] ); //CalcEntitySpot( NPC->enemy, SPOT_HEAD_LEAN, target ); GetAnglesForDirection( muzzle, target, angles ); } NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] ); NPCInfo->desiredPitch = AngleNormalize360( angles[PITCH] ); } NPC_UpdateAngles( qtrue, qtrue ); }
/* =============== FireWeapon =============== */ void FireWeapon( gentity_t *ent ) { if ( ent->client ) { // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); } else { AngleVectors( ent->turretAim, forward, right, up ); VectorCopy( ent->s.pos.trBase, muzzle ); } // fire the specific weapon switch ( ent->s.weapon ) { case WP_ALEVEL1: meleeAttack( ent, LEVEL1_CLAW_RANGE, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_DMG, MOD_LEVEL1_CLAW ); break; case WP_ALEVEL1_UPG: meleeAttack( ent, LEVEL1_CLAW_U_RANGE, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_DMG, MOD_LEVEL1_CLAW ); break; case WP_ALEVEL3: meleeAttack( ent, LEVEL3_CLAW_RANGE, LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_DMG, MOD_LEVEL3_CLAW ); break; case WP_ALEVEL3_UPG: meleeAttack( ent, LEVEL3_CLAW_UPG_RANGE, LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_DMG, MOD_LEVEL3_CLAW ); break; case WP_ALEVEL2: meleeAttack( ent, LEVEL2_CLAW_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW ); break; case WP_ALEVEL2_UPG: meleeAttack( ent, LEVEL2_CLAW_U_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW ); break; case WP_ALEVEL4: meleeAttack( ent, LEVEL4_CLAW_RANGE, LEVEL4_CLAW_WIDTH, LEVEL4_CLAW_HEIGHT, LEVEL4_CLAW_DMG, MOD_LEVEL4_CLAW ); break; case WP_BLASTER: blasterFire( ent ); break; case WP_MACHINEGUN: bulletFire( ent, RIFLE_SPREAD, RIFLE_DMG, MOD_MACHINEGUN ); break; case WP_SHOTGUN: shotgunFire( ent ); break; case WP_CHAINGUN: bulletFire( ent, CHAINGUN_SPREAD, CHAINGUN_DMG, MOD_CHAINGUN ); break; case WP_FLAMER: flamerFire( ent ); break; case WP_PULSE_RIFLE: pulseRifleFire( ent ); break; case WP_MASS_DRIVER: massDriverFire( ent ); break; case WP_LUCIFER_CANNON: LCChargeFire( ent, qfalse ); break; case WP_LAS_GUN: lasGunFire( ent ); break; case WP_PAIN_SAW: painSawFire( ent ); break; case WP_GRENADE: throwGrenade( ent ); break; case WP_LOCKBLOB_LAUNCHER: lockBlobLauncherFire( ent ); break; case WP_HIVE: hiveFire( ent ); break; case WP_TESLAGEN: teslaFire( ent ); break; case WP_MGTURRET: bulletFire( ent, MGTURRET_SPREAD, MGTURRET_DMG, MOD_MGTURRET ); break; case WP_ABUILD: case WP_ABUILD2: buildFire( ent, MN_A_BUILD ); break; case WP_HBUILD: buildFire( ent, MN_H_BUILD ); break; default: break; } }
/* =============== CheckGrabAttack =============== */ void CheckGrabAttack( gentity_t *ent ) { trace_t tr; vec3_t end, dir; gentity_t *traceEnt; // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); if ( ent->client->ps.weapon == WP_ALEVEL1 ) { VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end ); } else if ( ent->client->ps.weapon == WP_ALEVEL1_UPG ) { VectorMA( muzzle, LEVEL1_GRAB_U_RANGE, forward, end ); } trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); if ( tr.surfaceFlags & SURF_NOIMPACT ) { return; } traceEnt = &g_entities[ tr.entityNum ]; if ( !traceEnt->takedamage ) { return; } if ( traceEnt->client ) { if ( traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { return; } if ( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) { return; } if ( !( traceEnt->client->ps.stats[ STAT_STATE ] & SS_GRABBED ) ) { AngleVectors( traceEnt->client->ps.viewangles, dir, NULL, NULL ); traceEnt->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir ); //event for client side grab effect G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); } traceEnt->client->ps.stats[ STAT_STATE ] |= SS_GRABBED; if ( ent->client->ps.weapon == WP_ALEVEL1 ) { traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_TIME; // Update the last combat time. ent->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; traceEnt->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; } else if ( ent->client->ps.weapon == WP_ALEVEL1_UPG ) { traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_U_TIME; // Update the last combat time. ent->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; traceEnt->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; } } }
/* =============== CheckPounceAttack =============== */ qboolean CheckPounceAttack( gentity_t *ent ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; int damage; vec3_t mins, maxs; VectorSet( mins, -LEVEL3_POUNCE_WIDTH, -LEVEL3_POUNCE_WIDTH, -LEVEL3_POUNCE_WIDTH ); VectorSet( maxs, LEVEL3_POUNCE_WIDTH, LEVEL3_POUNCE_WIDTH, LEVEL3_POUNCE_WIDTH ); if( !ent->client->allowedToPounce ) return qfalse; if( ent->client->ps.groundEntityNum != ENTITYNUM_NONE ) { ent->client->allowedToPounce = qfalse; return qfalse; } if( ent->client->ps.weaponTime ) return qfalse; // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, LEVEL3_POUNCE_RANGE, forward, end ); trap_Trace( &tr, ent->s.origin, mins, maxs, end, ent->s.number, MASK_SHOT ); //miss if( tr.fraction >= 1.0 ) return qfalse; if( tr.surfaceFlags & SURF_NOIMPACT ) return qfalse; traceEnt = &g_entities[ tr.entityNum ]; // send blood impact if( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; tent->s.generic1 = ent->s.generic1; //weaponMode } if( !traceEnt->takedamage ) return qfalse; damage = (int)( ( (float)ent->client->pouncePayload / (float)LEVEL3_POUNCE_SPEED ) * LEVEL3_POUNCE_DMG ); G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_LOCDAMAGE, MOD_LEVEL3_POUNCE ); ent->client->ps.weaponTime += LEVEL3_POUNCE_TIME; ent->client->allowedToPounce = qfalse; return qtrue; }
/* =============== CheckVenomAttack =============== */ qboolean CheckVenomAttack( gentity_t *ent ) { trace_t tr; vec3_t end; gentity_t *tent; gentity_t *traceEnt; vec3_t mins, maxs; int damage = LEVEL0_BITE_DMG; VectorSet( mins, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH ); VectorSet( maxs, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH ); // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, LEVEL0_BITE_RANGE, forward, end ); trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); if( tr.surfaceFlags & SURF_NOIMPACT ) return qfalse; traceEnt = &g_entities[ tr.entityNum ]; if( !traceEnt->takedamage ) return qfalse; if( !traceEnt->client && !traceEnt->s.eType == ET_BUILDABLE ) return qfalse; //allow bites to work against defensive buildables only if( traceEnt->s.eType == ET_BUILDABLE ) { if( traceEnt->s.modelindex != BA_H_MGTURRET && traceEnt->s.modelindex != BA_H_TESLAGEN ) return qfalse; //hackery damage *= 0.5f; } if( traceEnt->client ) { if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) return qfalse; if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) return qfalse; } // send blood impact if( traceEnt->takedamage && traceEnt->client ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.weapon = ent->s.weapon; tent->s.generic1 = ent->s.generic1; //weaponMode } G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_LEVEL0_BITE ); return qtrue; }