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) + 1;
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)
312 antilag_takeback(pl, time - lag);
317 savetime = frametime;
322 // DP tracetoss is stupid and always traces in 0.05s
323 // ticks. This makes it trace in 0.05*0.125s ticks
329 self.velocity = self.velocity * 0.125;
330 self.gravity *= 0.125 * 0.125;
332 tracetoss(self, oldself);
336 zcurveparticles_from_tracetoss(particleeffectnum("TR_VORESPIKE"), self.origin, trace_endpos, self.velocity);
337 if(trace_fraction == 1)
339 // won't hit anything anytime soon (DP's
340 // tracetoss does 200 tics of, here,
341 // 0.05*0.125s, that is, 1.25 seconds
344 dt = vlen(trace_endpos - self.origin) / vlen(self.velocity); // this is only approximate!
345 setorigin(self, trace_endpos);
346 self.velocity_z -= sv_gravity * dt;
348 if(!SUB_OwnerCheck())
350 if(SUB_NoImpactCheck())
354 W_BallisticBullet_Hit ();
358 if(!W_BallisticBullet_LeaveSolid(self, self.velocity, self.dmg_radius))
361 W_BallisticBullet_LeaveSolid_think();
363 frametime = savetime;
375 if(tracereffects & EF_RED)
376 CSQCProjectile(proj, TRUE, PROJECTILE_BULLET_GLOWING, TRUE);
378 CSQCProjectile(proj, TRUE, PROJECTILE_BULLET, TRUE);
383 void fireBullet (vector start, vector dir, float spread, float damage, float force, float dtype, float tracer)
388 if(cvar("g_ballistics_force"))
390 if (DEATH_ISWEAPON(dtype, WEP_SHOTGUN))
391 fireBallisticBullet(start, dir, spread, cvar("g_ballistics_force_shotgun_speed"), 5, damage, 0, force, dtype, 0, 1, cvar("g_ballistics_force_shotgun_bulletconstant"));
393 fireBallisticBullet(start, dir, spread, cvar("g_ballistics_force_uzi_speed"), 5, damage, 0, force, dtype, 0, 1, cvar("g_ballistics_force_shotgun_bulletconstant"));
397 dir = dir + randomvec() * spread;
398 end = start + dir * MAX_SHOT_DISTANCE;
399 if(self.antilag_debug)
400 traceline_antilag (self, start, end, FALSE, self, self.antilag_debug);
402 traceline_antilag (self, start, end, FALSE, self, ANTILAG_LATENCY(self));
408 e.movetype = MOVETYPE_FLY;
410 e.think = SUB_Remove;
411 e.nextthink = time + vlen(trace_endpos - start) / 6000;
412 e.velocity = dir * 6000;
413 e.angles = vectoangles(e.velocity);
414 setorigin (e, start);
415 e.flags = FL_PROJECTILE;
417 CSQCProjectile(e, TRUE, PROJECTILE_BULLET, TRUE);
420 if ((trace_fraction != 1.0) && (pointcontents (trace_endpos) != CONTENT_SKY))
422 if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
423 Damage_DamageInfo(trace_endpos, damage, 0, 0, dir * force, dtype);
424 Damage (trace_ent, self, self, damage, dtype, trace_endpos, dir * force);
429 void W_PrepareExplosionByDamage(entity attacker, void() explode)
431 self.takedamage = DAMAGE_NO;
432 self.event_damage = SUB_Null;
433 self.owner = attacker;
435 // do not explode NOW but in the NEXT FRAME!
436 // because recursive calls to RadiusDamage are not allowed
437 self.nextthink = time;
438 self.think = explode;