qboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) { trace_t tr; int damage, i, passent; gentity_t *traceEnt; #ifdef MISSIONPACK vec3_t impactpoint, bouncedir; #endif vec3_t tr_start, tr_end; passent = ent->s.number; VectorCopy( start, tr_start ); VectorCopy( end, tr_end ); for (i = 0; i < 10; i++) { trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT); traceEnt = &g_entities[ tr.entityNum ]; // send bullet impact if ( tr.surfaceFlags & SURF_NOIMPACT ) { return qfalse; } if ( traceEnt->takedamage) { /* LQ3A */ damage = (g_damageShell.integer > 0) ? g_damageShell.integer : 0; damage *= s_quadFactor; #ifdef MISSIONPACK if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) { if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) { G_BounceProjectile( tr_start, impactpoint, bouncedir, tr_end ); VectorCopy( impactpoint, tr_start ); // the player can hit him/herself with the bounced rail passent = ENTITYNUM_NONE; } else { VectorCopy( tr.endpos, tr_start ); passent = traceEnt->s.number; } continue; } else { G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_SHOTGUN); if( LogAccuracyHit( traceEnt, ent ) ) { return qtrue; } } #else G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_SHOTGUN); if( LogAccuracyHit( traceEnt, ent ) ) { return qtrue; } #endif } return qfalse; } return qfalse; }
void Weapon_LightningFire( gentity_t *ent ) { trace_t tr; vec3_t end; #if 1 vec3_t impactpoint, bouncedir; #endif gentity_t *traceEnt, *tent; int damage, i, passent; damage = 8 * s_quadFactor; passent = ent->s.number; for (i = 0; i < 10; i++) { VectorMA( muzzle, LIGHTNING_RANGE, forward, end ); trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT ); #if 1 // if not the first trace (the lightning bounced of an invulnerability sphere) if (i) { // add bounced off lightning bolt temp entity // the first lightning bolt is a cgame only visual // tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT ); VectorCopy( tr.endpos, end ); SnapVector( end ); VectorCopy( end, tent->s.origin2 ); } #endif if ( tr.entityNum == ENTITYNUM_NONE ) { return; } traceEnt = &g_entities[ tr.entityNum ]; 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 ); VectorSubtract( end, impactpoint, forward ); VectorNormalize(forward); // the player can hit him/herself with the bounced lightning passent = ENTITYNUM_NONE; } else { VectorCopy( tr.endpos, muzzle ); passent = traceEnt->s.number; } continue; } else { G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LIGHTNING); } #else G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LIGHTNING); #endif } 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( LogAccuracyHit( traceEnt, ent ) ) { ent->client->accuracy_hits++; } } else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS ); tent->s.eventParm = DirToByte( tr.plane.normal ); } break; } }
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 weapon_railgun_fire (gentity_t *ent) { vec3_t end; #ifdef MISSIONPACK vec3_t impactpoint, bouncedir; #endif trace_t trace; gentity_t *tent; gentity_t *traceEnt; int damage; int i; int hits; int unlinked; int passent; gentity_t *unlinkedEntities[MAX_RAIL_HITS]; LS_Weapon_Fire_Start(WF_RAIL, ent); damage = 100 * s_quadFactor; VectorMA (muzzle, 8192, forward, end); // trace only against the solids, so the railgun will go through people unlinked = 0; hits = 0; passent = ent->s.number; do { trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT ); if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) { break; } traceEnt = &g_entities[ trace.entityNum ]; if ( traceEnt->takedamage ) { #ifdef MISSIONPACK if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) { if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) { G_BounceProjectile( muzzle, impactpoint, bouncedir, end ); // snap the endpos to integers to save net bandwidth, but nudged towards the line SnapVectorTowards( trace.endpos, muzzle ); // send railgun beam effect tent = G_TempEntity( trace.endpos, EV_RAILTRAIL ); // set player number for custom colors on the railtrail tent->s.clientNum = ent->s.clientNum; VectorCopy( muzzle, tent->s.origin2 ); // move origin a bit to come closer to the drawn gun muzzle VectorMA( tent->s.origin2, 4, right, tent->s.origin2 ); VectorMA( tent->s.origin2, -1, up, tent->s.origin2 ); tent->s.eventParm = 255; // don't make the explosion at the end // VectorCopy( impactpoint, muzzle ); // the player can hit him/herself with the bounced rail passent = ENTITYNUM_NONE; } } else { if( LogAccuracyHit( traceEnt, ent ) ) { hits++; } G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN); } #else if( LogAccuracyHit( traceEnt, ent ) ) { hits++; } G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN); #endif } if ( trace.contents & CONTENTS_SOLID ) { break; // we hit something solid enough to stop the beam } // unlink this entity, so the next trace will go past it trap_UnlinkEntity( traceEnt ); unlinkedEntities[unlinked] = traceEnt; unlinked++; } while ( unlinked < MAX_RAIL_HITS ); // link back in any entities we unlinked for ( i = 0 ; i < unlinked ; i++ ) { trap_LinkEntity( unlinkedEntities[i] ); } // the final trace endpos will be the terminal point of the rail trail // snap the endpos to integers to save net bandwidth, but nudged towards the line SnapVectorTowards( trace.endpos, muzzle ); // send railgun beam effect tent = G_TempEntity( trace.endpos, EV_RAILTRAIL ); // set player number for custom colors on the railtrail tent->s.clientNum = ent->s.clientNum; VectorCopy( muzzle, tent->s.origin2 ); // move origin a bit to come closer to the drawn gun muzzle VectorMA( tent->s.origin2, 4, right, tent->s.origin2 ); VectorMA( tent->s.origin2, -1, up, tent->s.origin2 ); // no explosion at end if SURF_NOIMPACT, but still make the trail if ( trace.surfaceFlags & SURF_NOIMPACT ) { tent->s.eventParm = 255; // don't make the explosion at the end } else { tent->s.eventParm = DirToByte( trace.plane.normal ); } tent->s.clientNum = ent->s.clientNum; // give the shooter a reward sound if they have made two railgun hits in a row if ( hits == 0 ) { // complete miss ent->client->accurateCount = 0; } else { // check for "impressive" reward sound ent->client->accurateCount += hits; if ( ent->client->accurateCount >= 2 ) { ent->client->accurateCount -= 2; ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++; // add the sprite over the player's head ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP ); ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE; ent->client->rewardTime = level.time + REWARD_SPRITE_TIME; } ent->client->accuracy_hits++; } LS_Weapon_Fire_End(WF_RAIL, ent); }
void Bullet_Fire (gentity_t *ent, float spread, int damage ) { trace_t tr; vec3_t end; #ifdef MISSIONPACK vec3_t impactpoint, bouncedir; #endif float r; float u; gentity_t *tent; gentity_t *traceEnt; int i, passent; damage *= s_quadFactor; r = random() * M_PI * 2.0f; u = sin(r) * crandom() * spread * 16; r = cos(r) * crandom() * spread * 16; VectorMA (muzzle, 8192*16, forward, end); VectorMA (end, r, right, end); VectorMA (end, u, up, end); 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) { #ifdef MISSIONPACK 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); #ifdef MISSIONPACK } #endif } break; } }
// self is the "parent", the entity that owns the missile (like a player or shooter_*) qboolean fire_projectile(gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up, int projnum, float quadFactor, int mod, int splashMod, int handSide) { vec3_t mins = { -8, -8, -8 }; vec3_t maxs = { 8, 8, 8 }; gentity_t *bolt; vec3_t dir; vec3_t end; int count; int spread; int damage; int splashDamage; float splashRadius; int range; qboolean hitClient; if (projnum < 0 || projnum >= BG_NumProjectiles()) { return qfalse; } // Check if can fire grappling projectile if (self && self->player && bg_projectileinfo[projnum].grappling) { #ifdef IOQ3ZTM #ifdef TURTLEARENA // HOLD_SHURIKEN if (handSide == HS_CENTER) // Shuriken holdable item { if ((self->player->ps.pm_flags & PMF_USE_ITEM_HELD) || self->player->hook) { return qfalse; } self->player->ps.pm_flags |= PMF_USE_ITEM_HELD; } else #endif { if ((self->player->ps.pm_flags & PMF_FIRE_HELD) || self->player->hook) { return qfalse; } self->player->ps.pm_flags |= PMF_FIRE_HELD; } #else if (self->player->fireHeld || self->player->hook) { return qfalse; } self->player->fireHeld = qtrue; #endif } spread = bg_projectileinfo[projnum].spread; #if 0 // ZTM: WONTFIX: Only for machinegun if (g_gametype.integer == GT_TEAM) { damage = bg_projectileinfo[projnum].damage * 0.7; splashDamage = bg_projectileinfo[projnum].splashDamage * 0.7; } else #endif { damage = bg_projectileinfo[projnum].damage; splashDamage = bg_projectileinfo[projnum].splashDamage; } splashRadius = bg_projectileinfo[projnum].splashRadius; if (quadFactor > 1) { damage *= quadFactor; splashDamage *= quadFactor; } // Use default kill messages // Missile is spawned if (mod == MOD_UNKNOWN) { mod = MOD_PROJECTILE; } if (splashMod == MOD_UNKNOWN) { splashMod = MOD_PROJECTILE_EXPLOSION; } range = 0; if (bg_projectileinfo[projnum].instantDamage) { range = bg_projectileinfo[projnum].speed; } if (!range) { // 8192 is used by bullets, railgun, and nails // Lightning uses 768 range = 8192; } for (count = 0; count < bg_projectileinfo[projnum].numProjectiles; count++ ) { if (spread) // if spread make your own dir. { float r, u; r = random() * M_PI * 2.0f; u = sin(r) * crandom() * spread * 16; r = cos(r) * crandom() * spread * 16; VectorMA(start, (range * 16), forward, end); VectorMA(end, r, right, end); VectorMA(end, u, up, end); VectorSubtract(end, start, dir); } else { VectorMA(start, range, forward, end); VectorCopy(forward, dir); } if (bg_projectileinfo[projnum].flags & PF_USE_GRAVITY) { // extra vertical velocity dir[2] += 0.2f; } VectorNormalize (dir); if (bg_projectileinfo[projnum].instantDamage) { // Based on Q3's Bullet_Fire // (with extra code from Weapon_LightningFire and weapon_railgun_fire) trace_t tr; #if defined MISSIONPACK && !defined TURTLEARENA // POWERS vec3_t impactpoint, bouncedir; #endif gentity_t *tent; gentity_t *traceEnt; int i, passent; int unlinked; gentity_t *unlinkedEntities[10]; int hits; unlinked = hits = 0; // Do a bullet trace instead of spawning a missile. passent = self->s.number; for (i = 0; i < 10; i++) // 10 for lightning { trap_Trace (&tr, start, NULL, NULL, end, passent, MASK_SHOT); #if defined MISSIONPACK && !defined TURTLEARENA // POWERS // if not the first trace (the lightning bounced off an invulnerability sphere) if (i && bg_projectileinfo[projnum].trailType == PT_LIGHTNING) { // add bounced off lightning bolt temp entity // the first lightning bolt is a cgame only visual // tent = G_TempEntity( start, EV_LIGHTNINGBOLT ); tent->s.weapon = projnum; VectorCopy( tr.endpos, end ); SnapVector( end ); VectorCopy( end, tent->s.origin2 ); } #endif #if 0 // RAIL if ( tr.entityNum >= ENTITYNUM_MAX_NORMAL ) { break; } #else // LIGHTNING if ( tr.entityNum == ENTITYNUM_NONE ) { break; } #endif traceEnt = &g_entities[ tr.entityNum ]; // snap the endpos to integers, but nudged towards the line SnapVectorTowards( tr.endpos, start ); if ( !(tr.surfaceFlags & SURF_NOIMPACT) ) { // send bullet impact if ( traceEnt->takedamage && traceEnt->player ) { #if 1 // lightning tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); tent->s.otherEntityNum = traceEnt->s.number; tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.playerNum = self->s.number; #else tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH ); tent->s.eventParm = traceEnt->s.number; tent->s.otherEntityNum = self->s.number; #endif tent->s.weapon = projnum; } else if (tr.surfaceFlags & SURF_METALSTEPS) { tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS_METAL ); tent->s.playerNum = self->s.number; tent->s.weapon = projnum; tent->s.eventParm = DirToByte( tr.plane.normal ); } else { #if 1 // lightning tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS ); tent->s.playerNum = self->s.number; #else tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL ); tent->s.otherEntityNum = self->s.number; #endif tent->s.weapon = projnum; tent->s.eventParm = DirToByte( tr.plane.normal ); } } if ( traceEnt->takedamage) { #if defined MISSIONPACK && !defined TURTLEARENA // POWERS if ( traceEnt->player && traceEnt->player->invulnerabilityTime > level.time ) { if (G_InvulnerabilityEffect( traceEnt, dir, tr.endpos, impactpoint, bouncedir )) { G_BounceProjectile( start, impactpoint, bouncedir, end ); if (bg_projectileinfo[projnum].trailType == PT_RAIL) { // snap the endpos to integers to save net bandwidth, but nudged towards the line SnapVectorTowards( tr.endpos, start ); // send railgun beam effect tent = G_TempEntity( tr.endpos, EV_RAILTRAIL ); // set player number for custom colors on the railtrail tent->s.playerNum = self->s.playerNum; tent->s.weapon = projnum; tent->s.weaponHands = MAX_HANDS; // Don't attach to player's gun VectorCopy( start, tent->s.origin2 ); // move origin a bit to come closer to the drawn gun muzzle VectorMA( tent->s.origin2, 4, right, tent->s.origin2 ); VectorMA( tent->s.origin2, -1, up, tent->s.origin2 ); tent->s.eventParm = 255; // don't make the explosion at the end } VectorCopy( impactpoint, start ); #if 1 // lightning VectorSubtract( end, impactpoint, dir ); VectorNormalize(dir); #endif // the player can hit him/herself with the bounced rail passent = ENTITYNUM_NONE; } else { VectorCopy( tr.endpos, start ); passent = traceEnt->s.number; } if (bg_projectileinfo[projnum].trailType != PT_RAIL) { continue; } } else #endif { G_Damage( traceEnt, self, self, #if 1 // ZTM: Knockback in direction projectile was moving dir, #else forward, #endif tr.endpos, damage, 0, mod); hitClient = LogAccuracyHit( traceEnt, self ); // Splash damage! if (G_RadiusDamage(tr.endpos, self, self, damage, splashRadius, traceEnt, splashMod)) { hitClient = qtrue; } if( hitClient ) { hits++; } } } // weapon_railgun_fire if (bg_projectileinfo[projnum].maxHits > 1) { if ( tr.contents & CONTENTS_SOLID ) { break; // we hit something solid enough to stop the beam } // unlink this entity, so the next trace will go past it trap_UnlinkEntity( traceEnt ); unlinkedEntities[unlinked] = traceEnt; unlinked++; if (i+1 >= bg_projectileinfo[projnum].maxHits) { break; } } else { break; } } // link back in any entities we unlinked for ( i = 0 ; i < unlinked ; i++ ) { trap_LinkEntity( unlinkedEntities[i] ); } if (self && self->player) { #ifndef TURTLEARENA // AWARDS if (bg_projectileinfo[projnum].maxHits > 1) { // give the shooter a reward sound if they have made two railgun hits in a row if ( hits == 0 ) { // complete miss self->player->accurateCount = 0; } else { // check for "impressive" reward sound self->player->accurateCount += hits; if ( self->player->accurateCount >= 2 ) { self->player->accurateCount -= 2; self->player->ps.persistant[PERS_IMPRESSIVE_COUNT]++; // add the sprite over the player's head #ifdef IOQ3ZTM self->player->ps.eFlags &= ~EF_AWARD_BITS; #else self->player->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP ); #endif self->player->ps.eFlags |= EF_AWARD_IMPRESSIVE; self->player->rewardTime = level.time + REWARD_SPRITE_TIME; } self->player->accuracy_hits++; } } else #endif if (hits) { self->player->accuracy_hits++; } } // From weapon_railgun_fire if (bg_projectileinfo[projnum].trailType == PT_RAIL) { gentity_t *tent; // the final trace endpos will be the terminal point of the rail trail // snap the endpos to integers to save net bandwidth, but nudged towards the line SnapVectorTowards( tr.endpos, start ); // send railgun beam effect tent = G_TempEntity( tr.endpos, EV_RAILTRAIL ); // set player number for custom colors on the railtrail tent->s.playerNum = self->s.playerNum; // Set projectile number tent->s.weapon = projnum; // ZTM: NOTE: This could be a problem if multiple hands use the same handSide. tent->s.weaponHands = MAX_HANDS; if (self->player) { for (i = 0; i < MAX_HANDS; i++) { if (self->player->pers.playercfg.handSide[i] == handSide) { tent->s.weaponHands = i; break; } } } VectorCopy( start, tent->s.origin2 ); // move origin a bit to come closer to the drawn gun muzzle if (handSide == HS_RIGHT) VectorMA( tent->s.origin2, 4, right, tent->s.origin2 ); else if (handSide == HS_LEFT) VectorMA( tent->s.origin2, -4, right, tent->s.origin2 ); VectorMA( tent->s.origin2, -1, up, tent->s.origin2 ); } continue; } bolt = G_Spawn(); bolt->classname = bg_projectileinfo[projnum].name; if (self && self->player && bg_projectileinfo[projnum].grappling) { if (bg_projectileinfo[projnum].timetolive == -1) bolt->nextthink = -1; else bolt->nextthink = level.time + bg_projectileinfo[projnum].timetolive; bolt->think = Weapon_HookFree; self->player->hook = bolt; } else if (bg_projectileinfo[projnum].homing) { bolt->nextthink = level.time + bg_projectileinfo[projnum].homing; bolt->think = G_HomingMissile; } else { if (bg_projectileinfo[projnum].timetolive == -1) bolt->nextthink = -1; else bolt->nextthink = level.time + bg_projectileinfo[projnum].timetolive; if (bg_projectileinfo[projnum].fallToGround) bolt->think = G_MissileFall; // Just fall out of air. else bolt->think = G_ExplodeMissile; } bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = projnum; if (self) { bolt->r.ownerNum = self->s.number; } else { bolt->r.ownerNum = ENTITYNUM_WORLD; } bolt->parent = self; // grapple bolt->s.otherEntityNum = bolt->r.ownerNum; // use to match beam in client if (!bg_projectileinfo[projnum].damageAttacker) { bolt->flags |= FL_MISSILE_NO_DAMAGE_PARENT; } bolt->damage = damage; bolt->splashDamage = splashDamage; bolt->splashRadius = splashRadius; bolt->methodOfDeath = mod; bolt->splashMethodOfDeath = splashMod; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; VectorCopy( start, bolt->s.pos.trBase ); bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame G_SetMissileVelocity(bolt, dir, projnum); VectorCopy (start, bolt->r.currentOrigin); if (bg_projectileinfo[projnum].bounceType == PB_FULL) bolt->s.eFlags = EF_BOUNCE; else if (bg_projectileinfo[projnum].bounceType == PB_HALF) bolt->s.eFlags = EF_BOUNCE_HALF; if (bg_projectileinfo[projnum].flags & PF_USE_GRAVITY) bolt->s.pos.trType = TR_GRAVITY; // Limit bounces bolt->s.modelindex2 = bg_projectileinfo[projnum].maxBounces; // ZTM: Shootable missiles, taken from XREAL if (bg_projectileinfo[projnum].shootable) { // Make the projectile shootable bolt->s.contents = CONTENTS_SHOOTABLE; VectorCopy(mins, bolt->s.mins); VectorCopy(maxs, bolt->s.maxs); bolt->takedamage = qtrue; bolt->health = bg_projectileinfo[projnum].damage; if (bg_projectileinfo[projnum].fallToGround) bolt->die = G_MissileFall_Die; else bolt->die = G_Missile_Die; } // Save handSide in missile bolt->s.weaponHands = handSide; if (self && self->player) { // Taken from Q3's fire_prox; // ZTM: Used by prox mines so that if that player changes teams the mines // don't "change" teams as well (or something...). bolt->s.team = self->player->sess.sessionTeam; } else { bolt->s.team = TEAM_FREE; } // Needed for stickOnImpact and grappling projectiles vectoangles( forward, bolt->s.angles ); } return qtrue; }
void Weapon_LightningFire( gentity_t *ent ) { trace_t tr; vec3_t end; #ifdef MISSIONPACK vec3_t impactpoint, bouncedir; #endif gentity_t *traceEnt, *tent; int damage, i, passent; damage = 8 * s_quadFactor; passent = ent->s.number; for (i = 0; i < 10; i++) { VectorMA( muzzle, LIGHTNING_RANGE, forward, end ); // eser - lightning discharge if (trap_PointContents (muzzle, -1) & MASK_WATER) { int zaps; gentity_t *tent; zaps = ent->client->ps.ammo[WP_LIGHTNING]; // determines size/power of discharge if (!zaps) return; // prevents any subsequent frames causing second discharge + error zaps++; // pmove does an ammo[gun]--, so we must compensate SnapVectorTowards (muzzle, ent->s.origin); // save bandwidth tent = G_TempEntity (muzzle, EV_LIGHTNING_DISCHARGE); tent->s.eventParm = zaps; // duration / size of explosion graphic ent->client->ps.ammo[WP_LIGHTNING] = 0; // drain ent's lightning count if (G_RadiusDamage (muzzle, ent, damage * zaps, (damage * zaps) + 16, NULL, MOD_LIGHTNING_DISCHARGE, qtrue)) ent->client->accuracy_hits++; return; } // eser - lightning discharge trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT ); #ifdef MISSIONPACK // if not the first trace (the lightning bounced of an invulnerability sphere) if (i) { // add bounced off lightning bolt temp entity // the first lightning bolt is a cgame only visual // tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT ); VectorCopy( tr.endpos, end ); SnapVector( end ); VectorCopy( end, tent->s.origin2 ); } #endif if ( tr.entityNum == ENTITYNUM_NONE ) { return; } traceEnt = &g_entities[ tr.entityNum ]; if ( traceEnt->takedamage) { #ifdef MISSIONPACK 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 ); VectorSubtract( end, impactpoint, forward ); VectorNormalize(forward); // the player can hit him/herself with the bounced lightning passent = ENTITYNUM_NONE; } else { VectorCopy( tr.endpos, muzzle ); passent = traceEnt->s.number; } continue; } #endif if( LogAccuracyHit( traceEnt, ent ) ) { ent->client->accuracy_hits++; } G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LIGHTNING); } 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; } else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) { tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS ); tent->s.eventParm = DirToByte( tr.plane.normal ); } break; } }
void Bullet_Fire (gentity_t *ent, float spread, int damage, int mod ) { trace_t tr; vec3_t end; #ifdef MISSIONPACK vec3_t impactpoint, bouncedir; #endif float r; float u; gentity_t *tent; gentity_t *traceEnt; int i, passent; damage *= s_quadFactor; //unlagged - attack prediction #2 if ( g_unlagged.integer ) { // we have to use something now that the client knows in advance int seed = ent->client->attackTime % 256; // this has to match what's on the client r = Q_random(&seed) * M_PI * 2.0f; u = sin(r) * Q_crandom(&seed) * spread * 16; r = cos(r) * Q_crandom(&seed) * spread * 16; } else { r = random() * M_PI * 2.0f; u = sin(r) * crandom() * spread * 16; r = cos(r) * crandom() * spread * 16; } //-unlagged - attack prediction #2 VectorMA (muzzle, 8192*16, forward, end); VectorMA (end, r, right, end); VectorMA (end, u, up, end); passent = ent->s.number; for (i = 0; i < 10; i++) { //unlagged - backward reconciliation #2 // backward-reconcile the other clients if ( g_unlagged.integer ) G_DoTimeShiftFor( ent ); //-unlagged - backward reconciliation #2 trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT); //unlagged - backward reconciliation #2 // put them back if ( g_unlagged.integer ) G_UndoTimeShiftFor( ent ); //-unlagged - backward reconciliation #2 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; //unlagged - attack prediction #2 // we need the client number to determine whether or not to // suppress this event if ( g_unlagged.integer ) tent->s.clientNum = ent->s.clientNum; //-unlagged - attack prediction #2 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 ); //unlagged - attack prediction #2 // we need the client number to determine whether or not to // suppress this event if ( g_unlagged.integer ) tent->s.clientNum = ent->s.clientNum; //-unlagged - attack prediction #2 } tent->s.otherEntityNum = ent->s.number; if ( traceEnt->takedamage) { #ifdef MISSIONPACK 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, DAMAGE_COMBAT, mod); #ifdef MISSIONPACK } #endif } break; } }