2 void W_GiveWeapon (entity e, float wep, string name)
9 e.weapons = e.weapons | W_WeaponBit(wep);
14 if (other.classname == "player")
16 sprint (other, "You got the ^2");
25 void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float deathtype)
27 local vector hitloc, force, endpoint, dir;
28 local entity ent, endent;
29 local float endq3surfaceflags;
30 //local entity explosion;
32 railgun_start = start;
35 dir = normalize(end - start);
38 // go a little bit into the wall because we need to hit this wall later
41 // trace multiple times until we hit a wall, each obstacle will be made
42 // non-solid so we can hit the next, while doing this we spawn effects and
43 // note down which entities were hit so we can damage them later
46 if(self.antilag_debug)
47 traceline_antilag (self, start, end, FALSE, self, self.antilag_debug);
49 traceline_antilag (self, start, end, FALSE, self, ANTILAG_LATENCY(self));
51 // if it is world we can't hurt it so stop now
52 if (trace_ent == world || trace_fraction == 1)
55 // make the entity non-solid so we can hit the next one
56 trace_ent.railgunhit = TRUE;
57 trace_ent.railgunhitloc = end;
58 trace_ent.railgunhitsolidbackup = trace_ent.solid;
60 // stop if this is a wall
61 if (trace_ent.solid == SOLID_BSP)
64 // make the entity non-solid
65 trace_ent.solid = SOLID_NOT;
68 endpoint = trace_endpos;
70 endq3surfaceflags = trace_dphitq3surfaceflags;
72 // find all the entities the railgun hit and restore their solid state
73 ent = findfloat(world, railgunhit, TRUE);
76 // restore their solid type
77 ent.solid = ent.railgunhitsolidbackup;
78 ent = findfloat(ent, railgunhit, TRUE);
81 // spawn a temporary explosion entity for RadiusDamage calls
82 //explosion = spawn();
84 // find all the entities the railgun hit and hurt them
85 ent = findfloat(world, railgunhit, TRUE);
88 // get the details we need to call the damage function
89 hitloc = ent.railgunhitloc;
90 ent.railgunhitloc = '0 0 0';
91 ent.railgunhitsolidbackup = SOLID_NOT;
92 ent.railgunhit = FALSE;
95 if (ent.takedamage || ent.classname == "case")
96 Damage (ent, self, self, bdamage, deathtype, hitloc, force);
98 // create a small explosion to throw gibs around (if applicable)
99 //setorigin (explosion, hitloc);
100 //RadiusDamage (explosion, self, 10, 0, 50, world, 300, deathtype);
102 // advance to the next entity
103 ent = findfloat(ent, railgunhit, TRUE);
106 // we're done with the explosion entity, remove it
109 trace_endpos = endpoint;
111 trace_dphitq3surfaceflags = endq3surfaceflags;
117 void W_BallisticBullet_Hit (void)
121 f = pow(bound(0, vlen(self.velocity) / vlen(self.oldvelocity), 1), 2); // energy multiplier
123 if(other.solid == SOLID_BSP)
124 Damage_DamageInfo(self.origin, self.dmg * f, 0, 0, self.dmg_force * normalize(self.velocity) * f, self.projectiledeathtype);
126 if(other && other != self.enemy)
130 damage_headshotbonus = self.dmg_edge;
131 railgun_start = self.origin - 2 * frametime * self.velocity;
132 railgun_end = self.origin + 2 * frametime * self.velocity;
134 Damage(other, self, self.owner, self.dmg * f, self.projectiledeathtype, self.origin, self.dmg_force * normalize(self.velocity) * f);
135 damage_headshotbonus = 0;
137 if(self.dmg_edge != 0)
140 announce(self.owner, "announcer/male/headshot.wav");
142 announce(self.owner, "announcer/male/yoda.wav");
145 //sound (self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_NORM);
148 self.enemy = other; // don't hit the same player twice with the same bullet
151 .void(void) W_BallisticBullet_LeaveSolid_think_save;
152 .float W_BallisticBullet_LeaveSolid_nextthink_save;
153 .vector W_BallisticBullet_LeaveSolid_origin;
154 .vector W_BallisticBullet_LeaveSolid_velocity;
156 void W_BallisticBullet_LeaveSolid_think()
158 setorigin(self, self.W_BallisticBullet_LeaveSolid_origin);
159 self.velocity = self.W_BallisticBullet_LeaveSolid_velocity;
161 self.think = self.W_BallisticBullet_LeaveSolid_think_save;
162 self.nextthink = max(time, self.W_BallisticBullet_LeaveSolid_nextthink_save);
163 self.W_BallisticBullet_LeaveSolid_think_save = SUB_Null;
165 self.flags &~= FL_ONGROUND;
167 if(self.enemy.solid == SOLID_BSP)
170 f = pow(bound(0, vlen(self.velocity) / vlen(self.oldvelocity), 1), 2); // energy multiplier
171 Damage_DamageInfo(self.origin, 0, 0, 0, self.dmg_force * normalize(self.velocity) * -f, self.projectiledeathtype);
174 UpdateCSQCProjectile(self);
177 // a fake logarithm function
182 if(x > 0.9 && x < 1.1)
184 return 2 * log(sqrt(x));
187 float W_BallisticBullet_LeaveSolid(entity e, vector vel, float constant)
189 // move the entity along its velocity until it's out of solid, then let it resume
191 float dt, dst, velfactor, v0, vs;
195 // outside the world? forget it
196 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)
199 // E(s) = E0 - constant * s, constant = area of bullet circle * material constant / mass
202 E0_m = 0.5 * v0 * v0;
203 maxdist = E0_m / constant;
204 // maxdist = 0.5 * v0 * v0 / constant
205 // dprint("max dist = ", ftos(maxdist), "\n");
210 traceline_inverted (self.origin, self.origin + normalize(vel) * maxdist, MOVE_NORMAL, self);
212 if(trace_fraction == 1) // 1: we never got out of solid
215 self.W_BallisticBullet_LeaveSolid_origin = trace_endpos;
217 dst = vlen(trace_endpos - self.origin);
218 // E(s) = E0 - constant * s, constant = area of bullet circle * material constant / mass
219 Es_m = E0_m - constant * dst;
222 // roundoff errors got us
228 dt = dst / (0.5 * (v0 + vs));
229 // this is not correct, but the differential equations have no analytic
230 // solution - and these times are very small anyway
231 //print("dt = ", ftos(dt), "\n");
233 self.W_BallisticBullet_LeaveSolid_think_save = self.think;
234 self.W_BallisticBullet_LeaveSolid_nextthink_save = self.nextthink;
235 self.think = W_BallisticBullet_LeaveSolid_think;
236 self.nextthink = time + dt;
238 vel = vel * velfactor;
240 self.velocity = '0 0 0';
241 self.flags |= FL_ONGROUND; // prevent moving
242 self.W_BallisticBullet_LeaveSolid_velocity = vel;
247 void W_BallisticBullet_Touch (void)
249 if(self.think == W_BallisticBullet_LeaveSolid_think) // skip this!
253 W_BallisticBullet_Hit ();
256 if(!W_BallisticBullet_LeaveSolid(self, self.velocity, self.dmg_radius))
262 self.projectiledeathtype |= HITTYPE_BOUNCE;
265 void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float headshotbonus, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant)
267 float lag, dt, savetime;
272 proj.classname = "bullet";
274 proj.solid = SOLID_BBOX;
275 if(gravityfactor > 0)
277 proj.movetype = MOVETYPE_TOSS;
278 proj.gravity = gravityfactor;
281 proj.movetype = MOVETYPE_FLY;
282 proj.think = SUB_Remove;
283 proj.nextthink = time + lifetime; // min(pLifetime, vlen(world.maxs - world.mins) / pSpeed);
284 proj.velocity = (dir + randomvec() * spread) * pSpeed;
285 W_SetupProjectileVelocity(proj);
286 proj.angles = vectoangles(proj.velocity);
287 proj.dmg_radius = cvar("g_ballistics_materialconstant") / bulletconstant;
288 // so: bulletconstant = bullet mass / area of bullet circle
289 setorigin(proj, start);
290 proj.flags = FL_PROJECTILE;
292 proj.touch = W_BallisticBullet_Touch;
294 proj.dmg_edge = headshotbonus;
295 proj.dmg_force = force;
296 proj.projectiledeathtype = dtype;
298 proj.oldvelocity = proj.velocity;
300 if(cvar("g_antilag_bullets"))
301 if(pSpeed >= cvar("g_antilag_bullets"))
303 // NOTE: this may severely throw off weapon balance
304 lag = ANTILAG_LATENCY(self);
307 if(clienttype(self) != CLIENTTYPE_REAL)
309 if(cvar("g_antilag") == 0)
310 lag = 0; // only do hitscan, but no antilag
314 antilag_takeback(pl, time - lag);
319 savetime = frametime;
324 // DP tracetoss is stupid and always traces in 0.05s
325 // ticks. This makes it trace in 0.05*0.125s ticks
331 self.velocity = self.velocity * 0.125;
332 self.gravity *= 0.125 * 0.125;
334 tracetoss(self, oldself);
338 if(vlen(trace_endpos - self.origin) > 32)
339 zcurveparticles_from_tracetoss(particleeffectnum("tr_bullet"), self.origin, trace_endpos, self.velocity);
340 if(trace_fraction == 1)
342 // won't hit anything anytime soon (DP's
343 // tracetoss does 200 tics of, here,
344 // 0.05*0.125s, that is, 1.25 seconds
347 dt = vlen(trace_endpos - self.origin) / vlen(self.velocity); // this is only approximate!
348 setorigin(self, trace_endpos);
349 self.velocity_z -= sv_gravity * dt;
351 if(!SUB_OwnerCheck())
353 if(SUB_NoImpactCheck())
357 W_BallisticBullet_Hit ();
361 if(!W_BallisticBullet_LeaveSolid(self, self.velocity, self.dmg_radius))
364 W_BallisticBullet_LeaveSolid_think();
366 frametime = savetime;
378 if(tracereffects & EF_RED)
379 CSQCProjectile(proj, TRUE, PROJECTILE_BULLET_GLOWING, TRUE);
381 CSQCProjectile(proj, TRUE, PROJECTILE_BULLET, TRUE);
386 void fireBullet (vector start, vector dir, float spread, float damage, float force, float dtype, float tracer)
391 if(cvar("g_ballistics_force"))
393 if (DEATH_ISWEAPON(dtype, WEP_SHOTGUN))
394 fireBallisticBullet(start, dir, spread, cvar("g_ballistics_force_shotgun_speed"), 5, damage, 0, force, dtype, 0, 1, cvar("g_ballistics_force_shotgun_bulletconstant"));
396 fireBallisticBullet(start, dir, spread, cvar("g_ballistics_force_uzi_speed"), 5, damage, 0, force, dtype, 0, 1, cvar("g_ballistics_force_shotgun_bulletconstant"));
400 dir = dir + randomvec() * spread;
401 end = start + dir * MAX_SHOT_DISTANCE;
402 if(self.antilag_debug)
403 traceline_antilag (self, start, end, FALSE, self, self.antilag_debug);
405 traceline_antilag (self, start, end, FALSE, self, ANTILAG_LATENCY(self));
411 e.movetype = MOVETYPE_FLY;
413 e.think = SUB_Remove;
414 e.nextthink = time + vlen(trace_endpos - start) / 6000;
415 e.velocity = dir * 6000;
416 e.angles = vectoangles(e.velocity);
417 setorigin (e, start);
418 e.flags = FL_PROJECTILE;
420 CSQCProjectile(e, TRUE, PROJECTILE_BULLET, TRUE);
423 if ((trace_fraction != 1.0) && (pointcontents (trace_endpos) != CONTENT_SKY))
425 if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
426 Damage_DamageInfo(trace_endpos, damage, 0, 0, dir * force, dtype);
427 Damage (trace_ent, self, self, damage, dtype, trace_endpos, dir * force);
432 void W_PrepareExplosionByDamage(entity attacker, void() explode)
434 self.takedamage = DAMAGE_NO;
435 self.event_damage = SUB_Null;
436 self.owner = attacker;
438 // do not explode NOW but in the NEXT FRAME!
439 // because recursive calls to RadiusDamage are not allowed
440 self.nextthink = time;
441 self.think = explode;