/* =============== 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; }
/* =============== 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; }
/* =============== G_ChargeAttack =============== */ void G_ChargeAttack( gentity_t *ent, gentity_t *victim ) { int damage; int i; vec3_t forward; if ( ent->client->ps.stats[ STAT_MISC ] <= 0 || !( ent->client->ps.stats[ STAT_STATE ] & SS_CHARGING ) || ent->client->ps.weaponTime ) { return; } VectorSubtract( victim->s.origin, ent->s.origin, forward ); VectorNormalize( forward ); if ( !victim->takedamage ) { return; } // For buildables, track the last MAX_TRAMPLE_BUILDABLES_TRACKED buildables // hit, and do not do damage if the current buildable is in that list // in order to prevent dancing over stuff to kill it very quickly if ( !victim->client ) { for ( i = 0; i < MAX_TRAMPLE_BUILDABLES_TRACKED; i++ ) { if ( ent->client->trampleBuildablesHit[ i ] == victim - g_entities ) { return; } } ent->client->trampleBuildablesHit[ ent->client->trampleBuildablesHitPos++ % MAX_TRAMPLE_BUILDABLES_TRACKED ] = victim - g_entities; } WideBloodSpurt( ent, victim, NULL ); damage = LEVEL4_TRAMPLE_DMG * ent->client->ps.stats[ STAT_MISC ] / LEVEL4_TRAMPLE_DURATION; G_Damage( victim, ent, ent, forward, victim->s.origin, damage, DAMAGE_NO_LOCDAMAGE, MOD_LEVEL4_TRAMPLE ); ent->client->ps.weaponTime += LEVEL4_TRAMPLE_REPEAT; }
/* =============== meleeAttack =============== */ void meleeAttack( gentity_t *ent, float range, float width, float height, int damage, meansOfDeath_t mod ) { trace_t tr; gentity_t *traceEnt; G_WideTrace( &tr, ent, range, width, height, &traceEnt ); if ( traceEnt == NULL || !traceEnt->takedamage ) { return; } WideBloodSpurt( ent, traceEnt, &tr ); G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, mod ); }
/* =============== meleeAttack =============== */ void meleeAttack( gentity_t *ent, float range, float width, float height, int damage, meansOfDeath_t mod ) { trace_t tr; gentity_t *traceEnt; if( mod == MOD_LEVEL2_CLAW && damage == LEVEL2_CLAW_UPG_DMG ) G_CombatStats_Fire( ent, CSW_LEVEL2_UPG, damage ); else G_CombatStats_FireMOD( ent, mod, damage ); G_WideTrace( &tr, ent, range, width, height, &traceEnt ); if( traceEnt == NULL || !traceEnt->takedamage ) return; WideBloodSpurt( ent, traceEnt, &tr, mod ); G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, mod ); }