void FireSentryBulletsNEW( int shotcount, gedict_t * targ, float spread_x, float spread_y, float spread_z ) { vec3_t src; vec3_t dst; vec3_t norm_dir; sgAimNew( self, targ, src, dst, norm_dir ); ClearMultiDamage( ); traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self ); VectorScale( norm_dir, 4, puff_org ); VectorSubtract( g_globalvars.trace_endpos, puff_org, puff_org ); for ( ; shotcount > 0 ; shotcount-- ) { // для каждого выстрела определяем trace_ent trace_endpos // т.к.выстрелы могут убрать препятствия traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self ); // TraceAttack требует нормализованый вектор для корректного определения blood_org if(g_globalvars.trace_fraction != 1) TraceAttack( 4, norm_dir ); } ApplyMultiDamage( ); Multi_Finish( ); }
void View_ThirdPerson () { local float dist, dist2; local vector view, add_h; dist = 50; view = input_angles; view_x = view_x * (-1); makevectors (view); view = '0 0 0'; view_z = input_angles_x * 0.1; traceline(player.origin + '0 0 40' + v_right*(dist/6), player.origin + '0 0 40' + view - v_forward*dist - v_up*(input_angles_x/6) + v_right*(dist/3), TRUE, self); dist2 = vlen(trace_endpos - (player.origin + '0 0 40' + v_right*(dist/6))) ; add_h_z = 35 + (dist2 * 2 * (input_angles_x * 0.01)); traceline(player.origin + '0 0 40' + v_right*(dist/6), player.origin + add_h + view - v_forward*dist2 - v_up*(input_angles_x/6) + v_right*(dist/3), TRUE, self); CSQC_VIEW = trace_endpos; CSQC_VIEW = CSQC_VIEW + v_forward*4; }
int CheckArea( gedict_t * obj, gedict_t * builder ) { vec3_t src; vec3_t end; int pos; gedict_t *te; pos = CheckAreaNew( obj, builder ); if ( pos == 0 ) return 0; pos = trap_pointcontents( PASSVEC3( obj->s.v.origin ) ); if ( pos == CONTENT_SOLID || pos == CONTENT_SKY ) return 0; src[0] = obj->s.v.origin[0] + 24; src[1] = obj->s.v.origin[1] + 24; src[2] = obj->s.v.origin[2] + 16; pos = trap_pointcontents( PASSVEC3( src ) ); if ( pos == CONTENT_SOLID || pos == CONTENT_SKY ) return 0; end[0] = obj->s.v.origin[0] - 16; end[1] = obj->s.v.origin[1] - 16; end[2] = obj->s.v.origin[2] - 16; traceline( PASSVEC3( src ), PASSVEC3( end ), 1, obj ); if ( g_globalvars.trace_fraction != 1 ) return 0; pos = trap_pointcontents( PASSVEC3( end ) ); if ( pos == CONTENT_SOLID || pos == CONTENT_SKY ) return 0; src[0] = obj->s.v.origin[0] - 16; src[1] = obj->s.v.origin[1] + 16; src[2] = obj->s.v.origin[2] + 16; pos = trap_pointcontents( PASSVEC3( src ) ); if ( pos == CONTENT_SOLID || pos == CONTENT_SKY ) return 0; end[0] = obj->s.v.origin[0] + 16; end[1] = obj->s.v.origin[1] - 16; end[2] = obj->s.v.origin[2] - 16; traceline( PASSVEC3( src ), PASSVEC3( end ), 1, obj ); if ( g_globalvars.trace_fraction != 1 ) return 0; pos = trap_pointcontents( PASSVEC3( end ) ); if ( pos == CONTENT_SOLID || pos == CONTENT_SKY ) return 0; traceline( PASSVEC3( builder->s.v.origin ), PASSVEC3( obj->s.v.origin ), 1, builder ); if ( g_globalvars.trace_fraction != 1 ) return 0; te = findradius( world, obj->s.v.origin, 64 ); if ( te ) return 0; return 1; }
/* ================= LightningDamage ================= */ void LightningDamage( vec3_t p1, vec3_t p2, gedict_t * from, float damage ) { gedict_t *e1, *e2; vec3_t f; VectorSubtract( p2, p1, f ); // f = p2 - p1; VectorNormalize( f ); // normalize (f); f[0] = 0 - f[1]; f[1] = f[0]; f[2] = 0; VectorScale( f, 16, f ); //f = f*16; e1 = e2 = world; traceline( PASSVEC3( p1 ), PASSVEC3( p2 ), false, self ); if ( PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage ) { LightningHit( from, damage ); if ( streq( self->s.v.classname, "player" ) ) { if ( streq( other->s.v.classname, "player" ) ) PROG_TO_EDICT( g_globalvars.trace_ent )->s.v. velocity[2] += 400; } } e1 = PROG_TO_EDICT( g_globalvars.trace_ent ); //traceline (p1 + f, p2 + f, FALSE, self); traceline( p1[0] + f[0], p1[1] + f[1], p1[2] + f[2], p2[0] + f[0], p2[1] + f[1], p2[2] + f[2], false, self ); if ( PROG_TO_EDICT( g_globalvars.trace_ent ) != e1 && PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage ) { LightningHit( from, damage ); } e2 = PROG_TO_EDICT( g_globalvars.trace_ent ); traceline( p1[0] - f[0], p1[1] - f[1], p1[2] - f[2], p2[0] - f[0], p2[1] - f[1], p2[2] - f[2], false, self ); if ( PROG_TO_EDICT( g_globalvars.trace_ent ) != e1 && PROG_TO_EDICT( g_globalvars.trace_ent ) != e2 && PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage ) { LightningHit( from, damage ); } }
/* ================ FireBullets Used by shotgun, super shotgun, and enemy soldier firing Go to the trouble of combining multiple pellets into a single damage call. ================ */ void FireBullets( float shotcount, vec3_t dir, float spread_x, float spread_y, float spread_z ) { vec3_t direction; vec3_t src, tmp; makevectors( self->s.v.v_angle ); VectorScale( g_globalvars.v_forward, 10, tmp ); VectorAdd( self->s.v.origin, tmp, src ); //src = self->s.v.origin + v_forward*10; src[2] = self->s.v.absmin[2] + self->s.v.size[2] * 0.7; ClearMultiDamage(); traceline( PASSVEC3( src ), src[0] + dir[0] * 2048, src[1] + dir[1] * 2048, src[2] + dir[2] * 2048, false, self ); VectorScale( dir, 4, tmp ); VectorSubtract( g_globalvars.trace_endpos, tmp, puff_org ); // puff_org = trace_endpos - dir*4; while ( shotcount > 0 ) { VectorScale( g_globalvars.v_right, crandom() * spread_x, tmp ); VectorAdd( dir, tmp, direction ); VectorScale( g_globalvars.v_up, crandom() * spread_y, tmp ); VectorAdd( direction, tmp, direction ); // direction = dir + crandom()*spread[0]*v_right + crandom()*spread[1]*v_up; VectorScale( direction, 2048, tmp ); VectorAdd( src, tmp, tmp ); traceline( PASSVEC3( src ), PASSVEC3( tmp ), false, self ); if ( g_globalvars.trace_fraction != 1.0 ) TraceAttack( 4, direction ); shotcount = shotcount - 1; } ApplyMultiDamage(); Multi_Finish(); }
void FireSentryBulletsMTFL2( int shotcount, gedict_t * targ, float spread_x, float spread_y, float spread_z ) { vec3_t direction; vec3_t src; vec3_t dir, end, tmp; sgAimMTFL2( self, targ, src, dir ); ClearMultiDamage( ); VectorScale( dir, 2048, end ); VectorAdd( end, src, end ); traceline( PASSVEC3( src ), PASSVEC3( end ), 0, self ); VectorScale( dir, 4, puff_org ); VectorSubtract( g_globalvars.trace_endpos, puff_org, puff_org ); while ( shotcount > 0 ) { VectorScale( g_globalvars.v_right, crandom( ) * spread_x, tmp ); VectorScale( g_globalvars.v_up, crandom( ) * spread_y, direction ); VectorAdd( direction, tmp, direction ); VectorAdd( direction, dir, direction ); VectorNormalize( direction ); VectorScale( direction, 2048, end ); VectorAdd( end, src, end ); traceline( PASSVEC3( src ), PASSVEC3( end ), 0, self ); if ( g_globalvars.trace_fraction != 1 ) { TraceAttack( 4, direction ); } shotcount = shotcount - 1; } ApplyMultiDamage( ); Multi_Finish( ); }
void traceerror( tsd_t *TSD, const treenode *thisptr, int RC ) { streng *message; if ( ( TSD->trace_stat == 'N' ) || ( TSD->trace_stat == 'F' ) ) traceline( TSD, thisptr, 'C', 0 ); if ( TSD->trace_stat != 'O' ) { message = Str_makeTSD( 20 + sizeof( int ) * 3 ) ; message->len = sprintf( message->value, " +++ RC=%d +++", RC ); printout( TSD, message ); Free_stringTSD( message ); } }
/* ============= visible returns 1 if the entity is visible to self, even if not infront () ============= */ float visible( gedict_t *targ ) { vec3_t spot1, spot2; VectorAdd( self->s.v.origin, self->s.v.view_ofs, spot1 ); VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, spot2 ); traceline( PASSVEC3( spot1 ), PASSVEC3( spot2 ), true, self ); // see through other monsters if ( g_globalvars.trace_inopen && g_globalvars.trace_inwater ) return false; // sight line crossed contents if ( g_globalvars.trace_fraction == 1 ) return true; return false; }
void CheckBelowBuilding( gedict_t * bld ) { vec3_t below; VectorCopy( bld->s.v.origin, below ); if ( streq( bld->s.v.classname, "detpack" ) ) below[2] = below[2] - 8; else below[2] = below[2] - 24; traceline( PASSVEC3( bld->s.v.origin ), PASSVEC3( below ), 1, bld ); if ( g_globalvars.trace_fraction == 1 ) { bld->s.v.movetype = MOVETYPE_TOSS; bld->s.v.flags = ( int ) bld->s.v.flags - ( ( int ) bld->s.v.flags & FL_ONGROUND ); } }
/* ================ W_FireAxe ================ */ void W_FireAxe() { vec3_t source, dest; vec3_t org; makevectors( self->s.v.v_angle ); VectorCopy( self->s.v.origin, source ); source[2] += 16; VectorScale( g_globalvars.v_forward, 64, dest ); VectorAdd( dest, source, dest ) //source = self->s.v.origin + '0 0 16'; traceline( PASSVEC3( source ), PASSVEC3( dest ), false, self ); if ( g_globalvars.trace_fraction == 1.0 ) return; VectorScale( g_globalvars.v_forward, 4, org ); VectorSubtract( g_globalvars.trace_endpos, org, org ); // org = trace_endpos - v_forward*4; if ( PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage ) { PROG_TO_EDICT( g_globalvars.trace_ent )->axhitme = 1; SpawnBlood( org, 20 ); if ( deathmatch > 3 ) T_Damage( PROG_TO_EDICT( g_globalvars.trace_ent ), self, self, 75 ); else T_Damage( PROG_TO_EDICT( g_globalvars.trace_ent ), self, self, 20 ); } else { // hit wall sound( self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM ); trap_WriteByte( MSG_MULTICAST, SVC_TEMPENTITY ); trap_WriteByte( MSG_MULTICAST, TE_GUNSHOT ); trap_WriteByte( MSG_MULTICAST, 3 ); trap_WriteCoord( MSG_MULTICAST, org[0] ); trap_WriteCoord( MSG_MULTICAST, org[1] ); trap_WriteCoord( MSG_MULTICAST, org[2] ); trap_multicast( PASSVEC3( org ), MULTICAST_PVS ); } }
void sgAimNew( gedict_t* self, gedict_t* targ, vec3_t src, vec3_t dst, vec3_t norm_dir) { vec3_t dir, tmp; trap_makevectors( self->s.v.v_angle ); VectorAdd( self->s.v.origin, self->s.v.view_ofs, src ); VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, dst ); VectorSubtract( dst, src, dir ); normalize(dir, norm_dir); //чтобы не попадать в подставку traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self ); if( (PROG_TO_EDICT(g_globalvars.trace_ent) == self->trigger_field) && vlen(dir) > 100 ) { VectorScale( norm_dir, 60, tmp); VectorAdd(src,tmp,src); } }
// 20mm cannon // self->nojumptime < - fixes the bh w/ 20mm bug void BigAssBullet ( vec3_t direction, float damage ) { vec3_t org, src, vtemp; makevectors( self->s.v.v_angle ); src[0] = self->s.v.origin[0] + ( g_globalvars.v_forward[0] * 10 ); src[1] = self->s.v.origin[1] + ( g_globalvars.v_forward[0] * 10 ); src[2] = self->s.v.absmin[2] + ( self->s.v.size[2] * 0.7 ); ClearMultiDamage ( ); VectorScale( direction, 1500, vtemp ); VectorAdd( vtemp, src, vtemp ); traceline( PASSVEC3( src ), PASSVEC3( vtemp ), 0, self ); //traceline( src, (src + (direction * 1500)), 0, self ); if ( g_globalvars.trace_fraction != 1 ) TraceAttack ( damage, direction ); if ( PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage ) { org[0] = g_globalvars.trace_endpos[0] - ( g_globalvars.v_forward[0] * 4 ); org[1] = g_globalvars.trace_endpos[1] - ( g_globalvars.v_forward[1] * 4 ); org[2] = g_globalvars.trace_endpos[2] - ( g_globalvars.v_forward[2] * 4 ); //org = (trace_endpos - (v_forward * 4)); SpawnBlood ( org, 9 ); } else { //org = (trace_endpos - (v_forward * 4)); org[0] = g_globalvars.trace_endpos[0] - ( g_globalvars.v_forward[0] * 4 ); org[1] = g_globalvars.trace_endpos[1] - ( g_globalvars.v_forward[1] * 4 ); org[2] = g_globalvars.trace_endpos[2] - ( g_globalvars.v_forward[0] * 4 ); trap_WriteByte( MSG_BROADCAST, SVC_TEMPENTITY ); trap_WriteByte( MSG_BROADCAST, TE_SPIKE ); trap_WriteCoord( MSG_BROADCAST, org[0] ); trap_WriteCoord( MSG_BROADCAST, org[1] ); trap_WriteCoord( MSG_BROADCAST, org[2] ); trap_multicast( PASSVEC3( g_globalvars.trace_endpos ), MULTICAST_PHS ); } ApplyMultiDamage ( ); }
/* ============ CanDamage Returns true if the inflictor can directly damage the target. Used for explosions and melee attacks. ============ */ qbool CanDamage( gedict_t * targ, gedict_t * inflictor ) { vec3_t dif; // bmodels need special checking because their origin is 0,0,0 if ( targ->s.v.movetype == MOVETYPE_PUSH ) { traceline( PASSVEC3( inflictor->s.v.origin ), 0.5 * ( targ->s.v.absmin[0] + targ->s.v.absmax[0] ), 0.5 * ( targ->s.v.absmin[1] + targ->s.v.absmax[1] ), 0.5 * ( targ->s.v.absmin[2] + targ->s.v.absmax[2] ), true, self ); if ( g_globalvars.trace_fraction == 1 ) return true; if ( PROG_TO_EDICT( g_globalvars.trace_ent ) == targ ) return true; return false; } traceline( PASSVEC3( inflictor->s.v.origin ), PASSVEC3( targ->s.v.origin ), true, self ); if ( g_globalvars.trace_fraction == 1 ) return true; // 1998-09-16 CanDamage fix by Maddes/Kryten start // testing middle of half-size bounding box dif[2] = 0; // ...front right dif[1] = targ->s.v.maxs[1] * 0.5; dif[0] = targ->s.v.maxs[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...front left dif[0] = targ->s.v.mins[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...back left dif[1] = targ->s.v.mins[1] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...back right dif[0] = targ->s.v.maxs[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // testing top of half-sized bounding box dif[2] = targ->s.v.maxs[2] * 0.5; // ...front right dif[1] = targ->s.v.maxs[1] * 0.5; dif[0] = targ->s.v.maxs[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...front left dif[0] = targ->s.v.mins[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...back left dif[1] = targ->s.v.mins[1] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...back right dif[0] = targ->s.v.maxs[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // testing bottom of half-sized bounding box dif[2] = targ->s.v.mins[2] * 0.5; // ...front right dif[1] = targ->s.v.maxs[1] * 0.5; dif[0] = targ->s.v.maxs[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...front left dif[0] = targ->s.v.mins[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...back left dif[1] = targ->s.v.mins[1] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // ...back right dif[0] = targ->s.v.maxs[0] * 0.5; traceline(PASSVEC3( inflictor->s.v.origin ), targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self); if ( g_globalvars.trace_fraction == 1 ) return true; // 1998-09-16 CanDamage fix by Maddes/Kryten end return false; }
void T_Damage( gedict_t * targ, gedict_t * inflictor, gedict_t * attacker, float damage ) { vec3_t dir; gedict_t *oldself; float save; float take; int i, c1 = 8, c2 = 4, hdp; float dmg_dealt = 0, virtual_take = 0; float non_hdp_damage; // save damage before handicap apply for kickback calculation float native_damage = damage; // save damage before apply any modificator char *attackerteam, *targteam, *attackername, *victimname; qbool tp4teamdmg = false; //midair and instagib float playerheight = 0, midheight = 0; qbool midair = false, inwater = false, do_dmg = false, rl_dmg = false, stomp_dmg = false; // can't apply damage to dead if ( !targ->s.v.takedamage || ISDEAD( targ ) ) return; // can't damage other players in race if ( isRACE() && ( attacker != targ ) ) { if ( targ->ct == ctPlayer || attacker->ct == ctPlayer ) return; } // ignore almost all damage in CA while coutdown if ( isCA() && match_in_progress && ra_match_fight != 2 ) { if ( !( dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype // do suicide damage anyway ) ) return; } // used by buttons and triggers to set activator for target firing damage_attacker = attacker; damage_inflictor = inflictor; attackerteam = getteam( attacker ); targteam = getteam( targ ); if ( (int)cvar("k_midair") ) midair = true; // in bloodfest boss damage factor. if ( k_bloodfest && attacker->bloodfest_boss ) { damage *= 4; } // check for quad damage powerup on the attacker // midair quad makes rockets fast, but no change to damage if ( attacker->super_damage_finished > g_globalvars.time && strneq( inflictor->s.v.classname, "door" ) && dtSTOMP != targ->deathtype && !midair ) damage *= ( deathmatch == 4 ? 8 : 4 ); // in dmm4 quad is octa actually // ctf strength rune if ( attacker->ctf_flag & CTF_RUNE_STR ) damage *= 2; // ctf resistance rune if ( targ->ctf_flag & CTF_RUNE_RES ) { damage /= 2; ResistanceSound( targ ); } // did we hurt enemy flag carrier? if ( (targ->ctf_flag & CTF_FLAG) && (!streq(targteam, attackerteam)) ) { attacker->carrier_hurt_time = g_globalvars.time; } // in teamplay 4 we do no armor or health damage to teammates (unless telefrag), but do apply velocity changes if ( tp_num() == 4 && streq(targteam, attackerteam) && ( isCA() || targ != attacker ) && !TELEDEATH(targ) ) { tp4teamdmg = true; } if ( midair || cvar("k_instagib") ) { traceline( PASSVEC3(targ->s.v.origin), targ->s.v.origin[0], targ->s.v.origin[1], targ->s.v.origin[2] - 2048, true, targ ); playerheight = targ->s.v.absmin[2] - g_globalvars.trace_endpos[2] + ( cvar("k_instagib") ? 1 : 0 ); } // get some data before apply damage in mid air mode if ( midair ) { inwater = ( ((int)targ->s.v.flags & FL_INWATER) && targ->s.v.waterlevel > 1 ); if ( streq( inflictor->s.v.classname, "rocket" )) midheight = targ->s.v.origin[2] - inflictor->s.v.oldorigin[2]; rl_dmg = ( targ->ct == ctPlayer && dtRL == targ->deathtype ); stomp_dmg = ( targ->ct == ctPlayer && dtSTOMP == targ->deathtype ); if ( !rl_dmg ) { // damage types which ignore "lowheight" do_dmg = targ->ct != ctPlayer // always do damage to non player, secret doors etc... || dtWATER_DMG == targ->deathtype // always do water damage || dtLAVA_DMG == targ->deathtype // always do lava damage || dtSLIME_DMG == targ->deathtype // always do slime damage || dtSTOMP == targ->deathtype // always do stomp damage || dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype; // do suicide damage anyway } } non_hdp_damage = damage; // save damage before handicap apply for kickback calculation // #handicap# if ( attacker != targ ) // attack no self if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) // player vs player if ( ( hdp = GetHandicap(attacker) ) != 100 ) // skip checks if hdp == 100 if ( dtAXE == targ->deathtype || dtSG == targ->deathtype || dtSSG == targ->deathtype || dtNG == targ->deathtype || dtSNG == targ->deathtype || dtGL == targ->deathtype || dtRL == targ->deathtype || dtLG_BEAM == targ->deathtype || dtLG_DIS == targ->deathtype || dtLG_DIS_SELF == targ->deathtype // even that impossible ) { damage *= 0.01f * hdp; } // save damage based on the target's armor level save = newceil( targ->s.v.armortype * damage ); if ( tp4teamdmg ) save = 0; // we do not touch armor if ( save >= targ->s.v.armorvalue ) { save = targ->s.v.armorvalue; targ->s.v.armortype = 0; // lost all armor targ->s.v.items -= ( ( int ) targ->s.v.items & ( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ) ); } dmg_dealt += save; if ( match_in_progress == 2 ) targ->s.v.armorvalue = targ->s.v.armorvalue - save; take = newceil( damage - save ); // mid air damage modificators if ( midair ) { int k_midair_minheight, midair_minheight; k_midair_minheight = (int)cvar("k_midair_minheight"); if ( k_midair_minheight == 1 ) midair_minheight = 128; else if ( k_midair_minheight == 2 ) midair_minheight = 256; else if ( k_midair_minheight == 3 ) midair_minheight = 512; else if ( k_midair_minheight == 4 ) midair_minheight = 1024; else midair_minheight = 64; if ( rl_dmg || stomp_dmg ) take = 9999; if ( playerheight < midair_minheight && rl_dmg ) take = 0; // no dmg done if target is not high enough if ( playerheight < 45 && !inwater && rl_dmg ) take = 0; // no rl dmg in such case if ( !rl_dmg && !do_dmg ) take = 0; // unknown damage for midair, so do not damage if ( rl_dmg && targ == attacker ) take = 0; // no self rl damage } // instagib damage modificators if ( cvar("k_instagib") ) { if ( inflictor->ct == ctPlayer ) take = 5000; if ( attacker == targ ) take = 0; } // helps kill player in prewar at "wrong" places if ( match_in_progress != 2 && native_damage > 450 ) take = 99999; // team play damage avoidance and godmode or invincibility check virtual_take = max(0, take); // virtual_take used for calculating dmg_dealt only in case of k_dmgfrags // ignore this checks for suicide damage if ( dtSUICIDE != targ->deathtype ) { if ( ( int ) targ->s.v.flags & FL_GODMODE ) { take = 0; // what if god was one of us } else if ( targ->invincible_finished >= g_globalvars.time ) { if ( targ->invincible_sound < g_globalvars.time ) { sound( targ, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM ); targ->invincible_sound = g_globalvars.time + 2; } take = 0; } else if ( ( tp_num() == 1 || ( tp_num() == 3 && targ != attacker ) ) && !strnull( attackerteam ) && streq( targteam, attackerteam ) && attacker->ct == ctPlayer && strneq( inflictor->s.v.classname, "door" ) && !TELEDEATH( targ ) // do telefrag damage in tp ) { // teamplay == 1 don't damage self and mates (armor affected anyway) // teamplay == 3 don't damage mates, do damage to self (armor affected anyway) take = 0; } else if ( tp4teamdmg ) { take = 0; // we do not touch health } } take = max(0, take); // avoid negative take, if any if ( cvar("k_dmgfrags") ) { if ( TELEDEATH( targ ) ) { // tele doesn't count for any dmgfrags damage dmg_dealt = 0; } else if ( targ->invincible_finished >= g_globalvars.time ) { // damage dealt _not_ capped by victim's health if victim has pent dmg_dealt += virtual_take; } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, virtual_take, targ->s.v.health ); } } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, take, targ->s.v.health ); } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // FIXME: remove after combining shotgun blasts? if ( targ->ct == ctPlayer ) { targ->s.v.dmg_take += take; targ->s.v.dmg_save += save; targ->s.v.dmg_inflictor = EDICT_TO_PROG( inflictor ); } if ( save ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>1</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)save ); } // figure momentum add if ( inflictor != world && ( targ->s.v.movetype == MOVETYPE_WALK || ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) ) ) { float nailkick; for ( i = 0; i < 3; i++ ) dir[i] = targ->s.v.origin[i] - ( inflictor->s.v.absmin[i] + inflictor->s.v.absmax[i] ) * 0.5; VectorNormalize( dir ); dir[2] = ((dtLG_DIS_SELF == targ->deathtype || dtLG_DIS == targ->deathtype) && dir[2] < 0) ? -dir[2] : dir[2]; if ( midair && non_hdp_damage < 60 && attacker != targ ) { c1 = 11; c2 = 6; } // Yawnmode: nails increases kickback // - Molgrum if ( k_yawnmode && streq( inflictor->s.v.classname, "spike" ) ) nailkick = 1.2; else nailkick = 1.0; for ( i = 0; i < 3; i++ ) targ->s.v.velocity[i] += dir[i] * non_hdp_damage * c1 * nailkick * ( midair && playerheight >= 45 ? ( 1 + ( playerheight - 45 ) / 64 ) : 1 ); if ( midair && playerheight < 45 ) targ->s.v.velocity[2] += dir[2] * non_hdp_damage * c2 * nailkick; // only for z component if ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) { targ->s.v.flags = (int)targ->s.v.flags & ~FL_ONGROUND; } } if ( match_in_progress == 2 && (int)cvar("k_dmgfrags") ) { if ( attacker->ct == ctPlayer && targ->ct == ctPlayer && attacker != targ ) { if ( isDuel() || isFFA() || strneq(attackerteam, targteam) ) { int dmg_frags; attacker->ps.dmg_frags += dmg_dealt; // add dealt dmg_frags = attacker->ps.dmg_frags / 100; // 1 frag = 100 damage attacker->s.v.frags = (int)(attacker->s.v.frags + dmg_frags); attacker->ps.dmg_frags -= dmg_frags * 100; } } } // do the damage if ( match_in_progress == 2 || dtSUICIDE == targ->deathtype // do suicide damage anyway || TELEDEATH( targ ) || ( k_practice && targ->ct != ctPlayer ) // #practice mode# || take >= 99999 // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2 ) { targ->s.v.health -= take; // G_bprint( 2, "%s %f\n", targ->s.v.classname, targ->s.v.health ); if ( take ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>0</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)take ); } if ( !targ->s.v.health || dtSUICIDE == targ->deathtype ) targ->s.v.health = -1; // qqshka, no zero health, heh, imo less bugs after this } // show damage in sbar if ( match_in_progress != 2 && ISLIVE( targ ) && !k_matchLess ) { if ( !midair || ( (int)targ->s.v.flags & FL_ONGROUND ) ) { if ( targ->ct == ctPlayer ) targ->s.v.currentammo = 1000 + Q_rint(damage); if ( attacker != targ && attacker->ct == ctPlayer) attacker->s.v.health = 1000 + Q_rint(damage); } } // update damage stats like: give/taked/team damage if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) { if ( attacker == targ ) { // self damage attacker->ps.dmg_self += dmg_dealt; } else { int items = targ->s.v.items; // damage to enemy weapon if ( items & (IT_ROCKET_LAUNCHER | IT_LIGHTNING) ) { attacker->ps.dmg_eweapon += dmg_dealt; } if ( tp_num() && streq(attackerteam, targteam) ) { attacker->ps.dmg_team += dmg_dealt; } else { attacker->ps.dmg_g += dmg_dealt; targ->ps.dmg_t += dmg_dealt; } // real hits if ( take || save ) { if ( dtRL == targ->deathtype ) attacker->ps.wpn[wpRL].rhits++; if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].rhits++; } // virtual hits if ( virtual_take || save ) { if ( dtRL == targ->deathtype ) { attacker->ps.wpn[wpRL].vhits++; // virtual given rl damage attacker->ps.dmg_g_rl += ( virtual_take + save ); } if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].vhits++; } } } // mid air bonuses if ( midair && match_in_progress == 2 && attacker != targ && take && rl_dmg) MidairDamageBonus(attacker, midheight); if ( midair && match_in_progress == 2 && stomp_dmg ) { attacker->ps.mid_stomps++; targ->s.v.frags -= 3; } // if targed killed, do appropriate action and return if ( ISDEAD( targ ) ) { Killed( targ, attacker, inflictor ); return; } // react to the damage - call pain function oldself = self; self = targ; if ( (int)self->s.v.flags & FL_MONSTER ) { GetMadAtAttacker( attacker ); } if ( self->th_pain ) { self->th_pain( attacker, take ); } self = oldself; }
float AverageTraceAngle (gedict_t* self, qbool debug, qbool report) { vec3_t back_left, projection, incr; int angles[] = { 45, 30, 15, 0, -15, -30, -45 }; int i; float best_angle = 0; float best_angle_frac = 0; float total_angle = 0; float avg_angle; float distance = 320; if (self->fb.path_state & JUMP_LEDGE) return 0; if (debug) { trap_makevectors (self->s.v.angles); } else { trap_makevectors (self->fb.dir_move_); } VectorMA (self->s.v.origin, -VEC_HULL_MIN[0], g_globalvars.v_forward, back_left); VectorMA (back_left, VEC_HULL_MIN[1], g_globalvars.v_right, back_left); VectorScale (g_globalvars.v_right, (VEC_HULL_MAX[0] - VEC_HULL_MIN[0]) / (sizeof(angles) / sizeof(angles[0]) - 1), incr); if (debug) { G_bprint (2, "Current origin: %d %d %d\n", PASSINTVEC3 (self->s.v.origin)); G_bprint (2, "Current angles: %d %d\n", PASSINTVEC3 (self->s.v.angles)); } for (i = 0; i < sizeof (angles) / sizeof (angles[0]); ++i) { int angle = angles[i]; RotatePointAroundVector (projection, g_globalvars.v_up, g_globalvars.v_forward, angle); VectorMA (back_left, distance, projection, projection); traceline (PASSVEC3 (back_left), PASSVEC3 (projection), false, self); if (g_globalvars.trace_fraction == 1) { total_angle += angle * 1.5; // bonus for success } else if (g_globalvars.trace_fraction > 0.4) { total_angle += angle * g_globalvars.trace_fraction; } if (debug) { G_bprint (2, "Angle: %d => [%d %d %d] [%d %d %d] = %f\n", angle, PASSINTVEC3 (back_left), PASSINTVEC3 (projection), g_globalvars.trace_fraction); } if (i == 0 || g_globalvars.trace_fraction > best_angle_frac) { best_angle = angle; best_angle_frac = g_globalvars.trace_fraction; } VectorAdd (back_left, incr, back_left); } avg_angle = total_angle / (sizeof (angles) / sizeof (angles[0])); if (debug) { G_bprint (2, "Best angle: %d\n", best_angle); G_bprint (2, "Total angle: %f\n", avg_angle); } return avg_angle; }
void FireSentryLighting( gedict_t * targ ) { vec3_t src; vec3_t dst; vec3_t dir, end, norm_dir; gedict_t*trace_ent; switch( tfset_sg_sfire ) { case SG_SFIRE_NEW: VectorCopy( self->s.v.angles, self->s.v.v_angle ); sgAimNew( self, targ, src, dst, norm_dir ); VectorCopy(dst,end); break; case SG_SFIRE_MTFL2: VectorCopy( self->s.v.angles, self->s.v.v_angle ); sgAimMTFL2( self, targ, src, dir ); VectorNormalize( dir ); VectorScale( dir, 2048, end ); VectorAdd( end, src, end ); break; case SG_SFIRE_MTFL1: VectorCopy( self->s.v.angles, self->s.v.v_angle ); case SG_SFIRE_281: trap_makevectors( self->s.v.v_angle ); VectorScale( g_globalvars.v_forward, 10, src ); VectorAdd( self->s.v.origin, src, src ); src[2] = self->s.v.absmin[2] + self->s.v.size[2] * 0.7; VectorSubtract( targ->s.v.origin, self->s.v.origin, dir ); VectorScale( dir, 2048, end ); VectorAdd( end, src, end ); break; default: return; } g_globalvars.trace_ent = 0; traceline( PASSVEC3( src ), PASSVEC3( end ), 0, self ); trap_WriteByte( MSG_MULTICAST, SVC_TEMPENTITY ); trap_WriteByte( MSG_MULTICAST, TE_LIGHTNING2 ); WriteEntity( MSG_MULTICAST, self ); trap_WriteCoord( MSG_MULTICAST, src[0] ); trap_WriteCoord( MSG_MULTICAST, src[1] ); trap_WriteCoord( MSG_MULTICAST, src[2] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[0] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[1] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[2] ); trap_multicast( PASSVEC3( src ), 1 ); if ( g_globalvars.trace_ent ) { trace_ent = PROG_TO_EDICT(g_globalvars.trace_ent); if ( streq( trace_ent->s.v.classname, "player" ) ) { switch((int)( g_random( ) * 30) ) { case 0: sound( trace_ent, 2, "player/pain1.wav" , 1, 1 ); break; case 1: sound( trace_ent, 2, "player/pain1.wav" , 1, 1 ); break; case 2: sound( trace_ent, 2, "player/pain2.wav" , 1, 1 ); break; case 3: sound( trace_ent, 2, "player/pain3.wav" , 1, 1 ); break; case 4: sound( trace_ent, 2, "player/pain4.wav" , 1, 1 ); break; case 5: sound( trace_ent, 2, "player/pain5.wav" , 1, 1 ); break; case 6: sound( trace_ent, 2, "player/pain6.wav" , 1, 1 ); break; default:break; } } } }
/* =========== CheckAttack The player is in view, so decide to move or launch an attack Returns false if movement should continue ============ */ float CheckAttack () { vec3_t spot1, spot2; gedict_t *targ; float chance; targ = PROG_TO_EDICT( self->s.v.enemy ); // see if any entities are in the way of the shot VectorAdd( self->s.v.origin, self->s.v.view_ofs, spot1 ); VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, spot2 ); traceline( PASSVEC3( spot1 ), PASSVEC3( spot2 ), false, self ); if ( PROG_TO_EDICT( g_globalvars.trace_ent ) != targ ) return false; // don't have a clear shot if ( g_globalvars.trace_inopen && g_globalvars.trace_inwater ) return false; // sight line crossed contents if ( enemy_range == RANGE_MELEE ) { // melee attack if ( self->th_melee ) { self->th_melee(); return true; } } // missile attack if ( !self->th_missile ) return false; if ( g_globalvars.time < self->attack_finished ) return false; if ( enemy_range == RANGE_FAR ) return false; if ( enemy_range == RANGE_MELEE ) { chance = 0.9; self->attack_finished = 0; } else if ( enemy_range == RANGE_NEAR ) { if (self->th_melee) chance = 0.2; else chance = 0.4; } else if ( enemy_range == RANGE_MID ) { if ( self->th_melee ) chance = 0.05; else chance = 0.1; } else chance = 0; if ( g_random() < chance ) { if ( self->th_missile ) self->th_missile(); SUB_AttackFinished( 2 * g_random() ); return true; } return false; }
void W_FireLightning() { vec3_t org; float cells; vec3_t tmp; if ( self->s.v.ammo_cells < 1 ) { self->s.v.weapon = W_BestWeapon(); W_SetCurrentAmmo(); return; } // explode if under water if ( self->s.v.waterlevel > 1 ) { if ( deathmatch > 3 ) { if ( g_random() <= 0.5 ) { self->deathtype = "selfwater"; T_Damage( self, self, PROG_TO_EDICT( self->s.v.owner ), 4000 ); } else { cells = self->s.v.ammo_cells; self->s.v.ammo_cells = 0; W_SetCurrentAmmo(); T_RadiusDamage( self, self, 35 * cells, world, "" ); return; } } else { cells = self->s.v.ammo_cells; self->s.v.ammo_cells = 0; W_SetCurrentAmmo(); T_RadiusDamage( self, self, 35 * cells, world, "" ); return; } } if ( self->t_width < g_globalvars.time ) { sound( self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM ); self->t_width = g_globalvars.time + 0.6; } g_globalvars.msg_entity = EDICT_TO_PROG( self ); trap_WriteByte( MSG_ONE, SVC_SMALLKICK ); if ( deathmatch != 4 ) self->s.v.currentammo = self->s.v.ammo_cells = self->s.v.ammo_cells - 1; VectorCopy( self->s.v.origin, org ); //org = self->s.v.origin + '0 0 16'; org[2] += 16; traceline( PASSVEC3( org ), org[0] + g_globalvars.v_forward[0] * 600, org[1] + g_globalvars.v_forward[1] * 600, org[2] + g_globalvars.v_forward[2] * 600, true, self ); trap_WriteByte( MSG_MULTICAST, SVC_TEMPENTITY ); trap_WriteByte( MSG_MULTICAST, TE_LIGHTNING2 ); WriteEntity( MSG_MULTICAST, self ); trap_WriteCoord( MSG_MULTICAST, org[0] ); trap_WriteCoord( MSG_MULTICAST, org[1] ); trap_WriteCoord( MSG_MULTICAST, org[2] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[0] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[1] ); trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[2] ); trap_multicast( PASSVEC3( org ), MULTICAST_PHS ); VectorScale( g_globalvars.v_forward, 4, tmp ); VectorAdd( g_globalvars.trace_endpos, tmp, tmp ); LightningDamage( self->s.v.origin, tmp, self, 30 ); }