- setorigin(self, self.W_BallisticBullet_LeaveSolid_origin);
- self.velocity = self.W_BallisticBullet_LeaveSolid_velocity;
-
- self.think = self.W_BallisticBullet_LeaveSolid_think_save;
- self.nextthink = max(time, self.W_BallisticBullet_LeaveSolid_nextthink_save);
- self.W_BallisticBullet_LeaveSolid_think_save = func_null;
-
- self.flags &= ~FL_ONGROUND;
-
- if(self.enemy.solid == SOLID_BSP)
- {
- float f;
- f = pow(bound(0, vlen(self.velocity) / vlen(self.oldvelocity), 1), 2); // energy multiplier
- Damage_DamageInfo(self.origin, 0, 0, 0, max(1, self.dmg_force) * normalize(self.velocity) * -f, self.projectiledeathtype, 0, self);
- }
-
- UpdateCSQCProjectile(self);
-}
-
-float W_BallisticBullet_LeaveSolid(float eff)
-{
- // move the entity along its velocity until it's out of solid, then let it resume
- vector vel = self.velocity;
- float dt, dst, velfactor, v0, vs;
- float maxdist;
- float E0_m, Es_m;
- float constant = self.dmg_radius * (other.ballistics_density ? other.ballistics_density : 1);
-
- // outside the world? forget it
- 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:
-
- if(self.dmg_radius == 0)
- {
- if(other.ballistics_density < 0)
- constant = 0; // infinite travel distance
- else
- return 0; // no penetration
- }
- else
- {
- if(other.ballistics_density < 0)
- constant = 0; // infinite travel distance
- else if(other.ballistics_density == 0)
- constant = self.dmg_radius;
- else
- constant = self.dmg_radius * other.ballistics_density;
- }
-
- // E(s) = E0 - constant * s, constant = area of bullet circle * material constant / mass
- v0 = vlen(vel);
-
- E0_m = 0.5 * v0 * v0;
-
- if(constant)
- {
- maxdist = E0_m / constant;
- // maxdist = 0.5 * v0 * v0 / constant
- // dprint("max dist = ", ftos(maxdist), "\n");
-
- if(maxdist <= autocvar_g_ballistics_mindistance)
- return 0;
- }
- else
- {
- maxdist = vlen(other.maxs - other.mins) + 1; // any distance, as long as we leave the entity
- }
-
- traceline_inverted (self.origin, self.origin + normalize(vel) * maxdist, MOVE_NORMAL, self, TRUE);
- if(trace_fraction == 1) // 1: we never got out of solid
- return 0;
-
- self.W_BallisticBullet_LeaveSolid_origin = trace_endpos;
-
- dst = max(autocvar_g_ballistics_mindistance, vlen(trace_endpos - self.origin));
- // E(s) = E0 - constant * s, constant = area of bullet circle * material constant / mass
- Es_m = E0_m - constant * dst;
- if(Es_m <= 0)
- {
- // roundoff errors got us
- return 0;
- }
- vs = sqrt(2 * Es_m);
- velfactor = vs / v0;
-
- dt = dst / (0.5 * (v0 + vs));
- // this is not correct, but the differential equations have no analytic
- // solution - and these times are very small anyway
- //print("dt = ", ftos(dt), "\n");
-
- self.W_BallisticBullet_LeaveSolid_think_save = self.think;
- self.W_BallisticBullet_LeaveSolid_nextthink_save = self.nextthink;
- self.think = W_BallisticBullet_LeaveSolid_think;
- self.nextthink = time + dt;
-
- vel = vel * velfactor;
-
- self.velocity = '0 0 0';
- self.flags |= FL_ONGROUND; // prevent moving
- self.W_BallisticBullet_LeaveSolid_velocity = vel;
-
- if(eff >= 0)
- if(vlen(trace_endpos - self.origin) > 4)
- {
- endzcurveparticles();
- trailparticles(self, eff, self.origin, trace_endpos);
- }
-
- return 1;
-}
-
-void W_BallisticBullet_Touch (void)
-{
- //float density;
-
- if(self.think == W_BallisticBullet_LeaveSolid_think) // skip this!
- return;
-
- PROJECTILE_TOUCH;
- W_BallisticBullet_Hit ();
-
- if(self.dmg_radius < 0) // these NEVER penetrate solid
- {
- remove(self);
- 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))
- {
- remove(self);
- return;
- }
-
- // go through solid!
- if(!W_BallisticBullet_LeaveSolid(-1))
- {
- remove(self);
- return;
- }
-
- self.projectiledeathtype |= HITTYPE_BOUNCE;
-}
-
-void endFireBallisticBullet()
-{
- endzcurveparticles();
-}
-
-entity fireBallisticBullet_trace_callback_ent;
-float fireBallisticBullet_trace_callback_eff;
-void fireBallisticBullet_trace_callback(vector start, vector hit, vector end)
-{
- if(vlen(trace_endpos - fireBallisticBullet_trace_callback_ent.origin) > 16)
- zcurveparticles_from_tracetoss(fireBallisticBullet_trace_callback_eff, fireBallisticBullet_trace_callback_ent.origin, trace_endpos, fireBallisticBullet_trace_callback_ent.velocity);