X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fw_common.qc;h=c1a1093fd52e5b12f98ae472f9164ff93e642567;hp=67f5b3356b056b0d63c071877068247b87376897;hb=b62d5345eba99bc31d9a5ac2493a54a77d6ef97d;hpb=f12e71e50f3c78ac1569cc9f4fedcab33f73fad2 diff --git a/qcsrc/server/w_common.qc b/qcsrc/server/w_common.qc index 67f5b3356b..c1a1093fd5 100644 --- a/qcsrc/server/w_common.qc +++ b/qcsrc/server/w_common.qc @@ -1,23 +1,18 @@ -void W_GiveWeapon (entity e, float wep, string name) +void W_GiveWeapon (entity e, float wep) { entity oldself; if (!wep) return; - WEPSET_OR_EW(e, wep); + e.weapons |= WepSet_FromWeapon(wep); oldself = self; self = e; - if not(g_minstagib) - if (other.classname == "player") - { - sprint (other, "You got the ^2"); - sprint (other, name); - sprint (other, "\n"); - } + if(IS_PLAYER(other)) + { Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_WEAPON_GOT, wep); } self = oldself; } @@ -109,7 +104,10 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f // Find all non-hit players the beam passed close by if(deathtype == WEP_MINSTANEX || deathtype == WEP_NEX) { - FOR_EACH_REALCLIENT(msg_entity) if(msg_entity != self) if(!msg_entity.railgunhit) if not(msg_entity.classname == "spectator" && msg_entity.enemy == self) // we use realclient, so spectators can hear the whoosh too + FOR_EACH_REALCLIENT(msg_entity) + if(msg_entity != self) + if(!msg_entity.railgunhit) + if(!(IS_SPEC(msg_entity) && msg_entity.enemy == self)) // we use realclient, so spectators can hear the whoosh too { // nearest point on the beam beampos = start + dir * bound(0, (msg_entity.origin - start) * dir, length); @@ -122,7 +120,7 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f if(!pseudoprojectile) pseudoprojectile = spawn(); // we need this so the sound uses the "entchannel4" volume - soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, snd, VOL_BASE * f, ATTN_NONE); + soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, snd, VOL_BASE * f, ATTEN_NONE); } if(pseudoprojectile) @@ -170,6 +168,7 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f .float dmg_force; .float dmg_radius; .float dmg_total; +//.float last_yoda; void W_BallisticBullet_Hit (void) { float f, q, g; @@ -190,8 +189,11 @@ void W_BallisticBullet_Hit (void) g = accuracy_isgooddamage(self.realowner, other); Damage(other, self, self.realowner, self.dmg * f, self.projectiledeathtype, self.origin, self.dmg_force * normalize(self.velocity) * f); - if(yoda) - AnnounceTo(self.realowner, "awesome"); + /*if(yoda && (time > (self.last_yoda + 5))) + { + Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA); + self.last_yoda = time; + }*/ // calculate hits for ballistic weapons if(g) @@ -220,7 +222,7 @@ void W_BallisticBullet_LeaveSolid_think() self.nextthink = max(time, self.W_BallisticBullet_LeaveSolid_nextthink_save); self.W_BallisticBullet_LeaveSolid_think_save = func_null; - self.flags &~= FL_ONGROUND; + self.flags &= ~FL_ONGROUND; if(self.enemy.solid == SOLID_BSP) { @@ -245,7 +247,7 @@ float W_BallisticBullet_LeaveSolid(float eff) if(self.origin_x > world.maxs_x || self.origin_y > world.maxs_y || self.origin_z > world.maxs_z || self.origin_x < world.mins_x || self.origin_y < world.mins_y || self.origin_z < world.mins_z) return 0; - // special case for zero density and zero bullet constant: + // special case for zero density and zero bullet constant: if(self.dmg_radius == 0) { @@ -355,8 +357,8 @@ void W_BallisticBullet_Touch (void) // common/weapclip (intended) // common/noimpact (is supposed to eat projectiles, but is erased farther above) if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW) - if not(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID) - if not(trace_dphitcontents & DPCONTENTS_OPAQUE) + if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID)) + if (!(trace_dphitcontents & DPCONTENTS_OPAQUE)) { remove(self); return; @@ -387,29 +389,20 @@ void fireBallisticBullet_trace_callback(vector start, vector hit, vector end) self.owner = world; } -void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant) +void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float force, float dtype, float tracereffects, float bulletconstant) { float lag, dt, savetime; //, density; entity pl, oldself; - float antilagging; - - antilagging = (autocvar_g_antilag_bullets && (pSpeed >= autocvar_g_antilag_bullets)); entity proj; proj = spawn(); proj.classname = "bullet"; proj.owner = proj.realowner = self; PROJECTILE_MAKETRIGGER(proj); - if(gravityfactor > 0) - { - proj.movetype = MOVETYPE_TOSS; - proj.gravity = gravityfactor; - } - else - proj.movetype = MOVETYPE_FLY; + proj.movetype = MOVETYPE_FLY; proj.think = SUB_Remove; proj.nextthink = time + lifetime; // min(pLifetime, vlen(world.maxs - world.mins) / pSpeed); - W_SetupProjectileVelocityEx(proj, dir, v_up, pSpeed, 0, 0, spread, antilagging); + W_SetupProjectileVelocityEx(proj, dir, v_up, pSpeed, 0, 0, spread, TRUE); proj.angles = vectoangles(proj.velocity); if(bulletconstant > 0) proj.dmg_radius = autocvar_g_ballistics_materialconstant / bulletconstant; @@ -430,122 +423,163 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f other = proj; MUTATOR_CALLHOOK(EditProjectile); - if(antilagging) - { - float eff; + float eff; - if(tracereffects & EF_RED) - eff = particleeffectnum("tr_rifle"); - else if(tracereffects & EF_BLUE) - eff = particleeffectnum("tr_rifle_weak"); - else - eff = particleeffectnum("tr_bullet"); + if(tracereffects & EF_RED) + eff = particleeffectnum("tr_rifle"); + else if(tracereffects & EF_BLUE) + eff = particleeffectnum("tr_rifle_weak"); + else + eff = particleeffectnum("tr_bullet"); + + // NOTE: this may severely throw off weapon balance + lag = ANTILAG_LATENCY(self); + if(lag < 0.001) + lag = 0; + if (!IS_REAL_CLIENT(self)) + lag = 0; + if(autocvar_g_antilag == 0 || self.cvar_cl_noantilag) + lag = 0; // only do hitscan, but no antilag + + if(lag) + FOR_EACH_PLAYER(pl) + if(pl != self) + antilag_takeback(pl, time - lag); - // NOTE: this may severely throw off weapon balance - lag = ANTILAG_LATENCY(self); - if(lag < 0.001) - lag = 0; - if(clienttype(self) != CLIENTTYPE_REAL) - lag = 0; - if(autocvar_g_antilag == 0 || self.cvar_cl_noantilag) - lag = 0; // only do hitscan, but no antilag + oldself = self; + self = proj; - if(lag) - FOR_EACH_PLAYER(pl) - if(pl != self) - antilag_takeback(pl, time - lag); + savetime = frametime; + frametime = 0.05; - oldself = self; - self = proj; + for(;;) + { + // DP tracetoss is stupid and always traces in 0.05s + // ticks. This makes it trace in 0.05*0.125s ticks + // instead. + vector v0; + v0 = self.velocity; + self.velocity = self.velocity * 0.125; + trace_fraction = 0; + fireBallisticBullet_trace_callback_ent = self; + fireBallisticBullet_trace_callback_eff = eff; + WarpZone_TraceToss_ThroughZone(self, self.owner, world, fireBallisticBullet_trace_callback); + self.velocity = v0; + + if(trace_fraction == 1) + break; + // won't hit anything anytime soon (DP's + // tracetoss does 200 tics of, here, + // 0.05*0.125s, that is, 1.25 seconds - savetime = frametime; - frametime = 0.05; + other = trace_ent; + dt = WarpZone_tracetoss_time * 0.125; // this is only approximate! + setorigin(self, trace_endpos); + self.velocity = WarpZone_tracetoss_velocity * (1 / 0.125); - for(;;) + if(!SUB_OwnerCheck()) { - // DP tracetoss is stupid and always traces in 0.05s - // ticks. This makes it trace in 0.05*0.125s ticks - // instead. - vector v0; - float g0; - v0 = self.velocity; - g0 = self.gravity; - self.velocity = self.velocity * 0.125; - self.gravity *= 0.125 * 0.125; - trace_fraction = 0; - fireBallisticBullet_trace_callback_ent = self; - fireBallisticBullet_trace_callback_eff = eff; - WarpZone_TraceToss_ThroughZone(self, self.owner, world, fireBallisticBullet_trace_callback); - self.velocity = v0; - self.gravity = g0; - - if(trace_fraction == 1) + if(SUB_NoImpactCheck()) break; - // won't hit anything anytime soon (DP's - // tracetoss does 200 tics of, here, - // 0.05*0.125s, that is, 1.25 seconds - other = trace_ent; - dt = WarpZone_tracetoss_time * 0.125; // this is only approximate! - setorigin(self, trace_endpos); - self.velocity = WarpZone_tracetoss_velocity * (1 / 0.125); + // hit the player + W_BallisticBullet_Hit(); + } - if(!SUB_OwnerCheck()) - { - if(SUB_NoImpactCheck()) - break; + if(proj.dmg_radius < 0) // these NEVER penetrate solid + break; - // hit the player - W_BallisticBullet_Hit(); - } + // if we hit "weapclip", bail out + // + // rationale of this check: + // + // any shader that is solid, nodraw AND trans is meant to clip weapon + // shots and players, but has no other effect! + // + // if it is not trans, it is caulk and should not have this side effect + // + // matching shaders: + // common/weapclip (intended) + // common/noimpact (is supposed to eat projectiles, but is erased farther above) + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW) + if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID)) + if (!(trace_dphitcontents & DPCONTENTS_OPAQUE)) + break; - if(proj.dmg_radius < 0) // these NEVER penetrate solid - break; + // go through solid! + if(!W_BallisticBullet_LeaveSolid((other && (other.solid != SOLID_BSP)) ? eff : -1)) + break; - // if we hit "weapclip", bail out - // - // rationale of this check: - // - // any shader that is solid, nodraw AND trans is meant to clip weapon - // shots and players, but has no other effect! - // - // if it is not trans, it is caulk and should not have this side effect - // - // matching shaders: - // common/weapclip (intended) - // common/noimpact (is supposed to eat projectiles, but is erased farther above) - if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW) - if not(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID) - if not(trace_dphitcontents & DPCONTENTS_OPAQUE) - break; + W_BallisticBullet_LeaveSolid_think(); - // go through solid! - if(!W_BallisticBullet_LeaveSolid((other && (other.solid != SOLID_BSP)) ? eff : -1)) - break; + self.projectiledeathtype |= HITTYPE_BOUNCE; + } + frametime = savetime; + self = oldself; + + if(lag) + FOR_EACH_PLAYER(pl) + if(pl != self) + antilag_restore(pl); - W_BallisticBullet_LeaveSolid_think(); + remove(proj); - self.projectiledeathtype |= HITTYPE_BOUNCE; + return; +} + +void fireBallisticBullet_simple(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float force, float dtype, float tracereffects, float bulletconstant) +{ + vector end; + + dir = normalize(dir + randomvec() * spread); + end = start + dir * MAX_SHOT_DISTANCE; + + for (;;) + { + // TODO also show effect + if(self.antilag_debug) + WarpZone_traceline_antilag (self, start, end, FALSE, self, self.antilag_debug); + else + WarpZone_traceline_antilag (self, start, end, FALSE, self, ANTILAG_LATENCY(self)); + + if (pointcontents (trace_endpos) != CONTENT_SKY) + { + trace_endpos = end; + return; } - frametime = savetime; - self = oldself; - if(lag) - FOR_EACH_PLAYER(pl) - if(pl != self) - antilag_restore(pl); + // Avoid self-damage + if (!trace_ent || (trace_ent == self)) + { + if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) + return; - remove(proj); + W_BallisticBullet_Hit(); // FIXME + } - return; + // if we hit "weapclip", bail out + // + // rationale of this check: + // + // any shader that is solid, nodraw AND trans is meant to clip weapon + // shots and players, but has no other effect! + // + // if it is not trans, it is caulk and should not have this side effect + // + // matching shaders: + // common/weapclip (intended) + // common/noimpact (is supposed to eat projectiles, but is erased farther above) + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW) + if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID)) + if (!(trace_dphitcontents & DPCONTENTS_OPAQUE)) + return; + + // go through solid! + if(!W_BallisticBullet_LeaveSolid((trace_ent && (trace_ent.solid != SOLID_BSP)) ? eff : -1)) // FIXME + return; + + W_BallisticBullet_LeaveSolid_think(); // FIXME } - - if(tracereffects & EF_RED) - CSQCProjectile(proj, TRUE, PROJECTILE_BULLET_GLOWING_TRACER, TRUE); - else if(tracereffects & EF_BLUE) - CSQCProjectile(proj, TRUE, PROJECTILE_BULLET_GLOWING, TRUE); - else - CSQCProjectile(proj, TRUE, PROJECTILE_BULLET, TRUE); } void fireBullet (vector start, vector dir, float spread, float damage, float force, float dtype, float tracer) @@ -563,8 +597,8 @@ void fireBullet (vector start, vector dir, float spread, float damage, float for if (pointcontents (trace_endpos) != CONTENT_SKY) { - if not (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) - Damage_DamageInfo(trace_endpos, damage, 0, 0, dir * max(1, force), dtype, trace_ent.species, self); + if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) + Damage_DamageInfo(trace_endpos, damage, 0, 0, dir * max(1, force), dtype, trace_ent.species, self); Damage (trace_ent, self, self, damage, dtype, trace_endpos, dir * force); } @@ -576,7 +610,7 @@ float W_CheckProjectileDamage(entity inflictor, entity projowner, float deathtyp float is_from_contents = (deathtype == DEATH_SLIME || deathtype == DEATH_LAVA); float is_from_owner = (inflictor == projowner); float is_from_exception = (exception != -1); - + //dprint(strcat("W_CheckProjectileDamage: from_contents ", ftos(is_from_contents), " : from_owner ", ftos(is_from_owner), " : exception ", strcat(ftos(is_from_exception), " (", ftos(exception), "). \n"))); if(autocvar_g_projectiles_damage <= -2) @@ -594,14 +628,14 @@ float W_CheckProjectileDamage(entity inflictor, entity projowner, float deathtyp { if(is_from_exception) return (exception); // if exception is detected, allow it to override - else if not(is_from_contents) + else if (!is_from_contents) return FALSE; // otherwise, only allow damage from contents - } + } else if(autocvar_g_projectiles_damage == 1) { if(is_from_exception) return (exception); // if exception is detected, allow it to override - else if not(is_from_contents || is_from_owner) + else if (!(is_from_contents || is_from_owner)) return FALSE; // otherwise, only allow self damage and damage from contents } else if(autocvar_g_projectiles_damage == 2) // allow any damage, but override for exceptions @@ -617,13 +651,13 @@ void W_PrepareExplosionByDamage(entity attacker, void() explode) { self.takedamage = DAMAGE_NO; self.event_damage = func_null; - - if((attacker.flags & FL_CLIENT) && !autocvar_g_projectiles_keep_owner) + + if(IS_CLIENT(attacker) && !autocvar_g_projectiles_keep_owner) { self.owner = attacker; self.realowner = attacker; } - + // do not explode NOW but in the NEXT FRAME! // because recursive calls to RadiusDamage are not allowed self.nextthink = time;