+float spiberbot_calcartillery_flighttime;
+vector spiberbot_calcartillery(vector org, vector tgt, float ht)
+{
+ float grav, sdist, zdist, vs, vz, jumpheight;
+ vector sdir;
+
+ grav = autocvar_sv_gravity;
+ zdist = tgt_z - org_z;
+ sdist = vlen(tgt - org - zdist * '0 0 1');
+ sdir = normalize(tgt - org - zdist * '0 0 1');
+
+ // how high do we need to go?
+ jumpheight = fabs(ht);
+ if(zdist > 0)
+ jumpheight = jumpheight + zdist;
+
+ // push so high...
+ vz = sqrt(2 * grav * jumpheight); // NOTE: sqrt(positive)!
+
+ // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
+ if(ht < 0)
+ if(zdist < 0)
+ vz = -vz;
+
+ vector solution;
+ solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
+ // ALWAYS solvable because jumpheight >= zdist
+ if(!solution_z)
+ solution_y = solution_x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
+ if(zdist == 0)
+ solution_x = solution_y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
+
+ if(zdist < 0)
+ {
+ // down-jump
+ if(ht < 0)
+ {
+ // almost straight line type
+ // jump apex is before the jump
+ // we must take the larger one
+ spiberbot_calcartillery_flighttime = solution_y;
+ }
+ else
+ {
+ // regular jump
+ // jump apex is during the jump
+ // we must take the larger one too
+ spiberbot_calcartillery_flighttime = solution_y;
+ }
+ }
+ else
+ {
+ // up-jump
+ if(ht < 0)
+ {
+ // almost straight line type
+ // jump apex is after the jump
+ // we must take the smaller one
+ spiberbot_calcartillery_flighttime = solution_x;
+ }
+ else
+ {
+ // regular jump
+ // jump apex is during the jump
+ // we must take the larger one
+ spiberbot_calcartillery_flighttime = solution_y;
+ }
+ }
+ vs = sdist / spiberbot_calcartillery_flighttime;
+
+ // finally calculate the velocity
+ return sdir * vs + '0 0 1' * vz;
+}
+