if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
- trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
+ trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true, false);
CL_VM_SetTraceGlobals(&trace, svent);
// R_TimeReport("traceline");
start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
stop[2] = start[2] - 2*sv_stepheight.value;
- trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true, false);
if (trace.fraction == 1.0)
return;
start[0] = stop[0] = x ? maxs[0] : mins[0];
start[1] = stop[1] = y ? maxs[1] : mins[1];
- trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true, false);
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
bottom = trace.endpos[2];
static void CSQC_R_RecalcView (void)
{
extern matrix4x4_t viewmodelmatrix;
- Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], 1);
- Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], cl_viewmodel_scale.value);
+ Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], 1);
+ Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], cl_viewmodel_scale.value);
}
void CL_RelinkLightFlashes(void);
r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
r_refdef.view.clear = true;
r_refdef.view.isoverlay = false;
- // FIXME: restore cl.csqc_origin
- // FIXME: restore cl.csqc_angles
+ VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
+ VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
cl.csqc_vidvars.drawworld = r_drawworld.integer != 0;
cl.csqc_vidvars.drawenginesbar = false;
cl.csqc_vidvars.drawcrosshair = false;
PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_y;
break;
case VF_ORIGIN:
- VectorCopy(cl.csqc_origin, PRVM_G_VECTOR(OFS_RETURN));
+ VectorCopy(cl.csqc_vieworigin, PRVM_G_VECTOR(OFS_RETURN));
break;
case VF_ORIGIN_X:
- PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[0];
+ PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[0];
break;
case VF_ORIGIN_Y:
- PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[1];
+ PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[1];
break;
case VF_ORIGIN_Z:
- PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[2];
+ PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[2];
break;
case VF_ANGLES:
- VectorCopy(cl.csqc_angles, PRVM_G_VECTOR(OFS_RETURN));
+ VectorCopy(cl.csqc_viewangles, PRVM_G_VECTOR(OFS_RETURN));
break;
case VF_ANGLES_X:
- PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[0];
+ PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[0];
break;
case VF_ANGLES_Y:
- PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[1];
+ PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[1];
break;
case VF_ANGLES_Z:
- PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[2];
+ PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[2];
break;
case VF_DRAWWORLD:
PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawworld;
r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
break;
case VF_ORIGIN:
- VectorCopy(f, cl.csqc_origin);
+ VectorCopy(f, cl.csqc_vieworigin);
CSQC_R_RecalcView();
break;
case VF_ORIGIN_X:
- cl.csqc_origin[0] = k;
+ cl.csqc_vieworigin[0] = k;
CSQC_R_RecalcView();
break;
case VF_ORIGIN_Y:
- cl.csqc_origin[1] = k;
+ cl.csqc_vieworigin[1] = k;
CSQC_R_RecalcView();
break;
case VF_ORIGIN_Z:
- cl.csqc_origin[2] = k;
+ cl.csqc_vieworigin[2] = k;
CSQC_R_RecalcView();
break;
case VF_ANGLES:
- VectorCopy(f, cl.csqc_angles);
+ VectorCopy(f, cl.csqc_viewangles);
CSQC_R_RecalcView();
break;
case VF_ANGLES_X:
- cl.csqc_angles[0] = k;
+ cl.csqc_viewangles[0] = k;
CSQC_R_RecalcView();
break;
case VF_ANGLES_Y:
- cl.csqc_angles[1] = k;
+ cl.csqc_viewangles[1] = k;
CSQC_R_RecalcView();
break;
case VF_ANGLES_Z:
- cl.csqc_angles[2] = k;
+ cl.csqc_viewangles[2] = k;
CSQC_R_RecalcView();
break;
case VF_DRAWWORLD:
// texture found and loaded
// skip over the jpeg as we don't need it
for(i = 0; i < size; ++i)
- MSG_ReadByte();
+ (void) MSG_ReadByte();
}
else
{
if (val && val->_float != 0)
scale = val->_float;
- // TODO do we need the same weird angle inverting logic here as in the server side case?
if(viewmatrix)
- Matrix4x4_CreateFromQuakeEntity(out, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], scale * cl_viewmodel_scale.value);
+ *out = r_refdef.view.matrix;
+ else if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && ((int)val->_float & RF_USEAXIS))
+ {
+ vec3_t forward;
+ vec3_t left;
+ vec3_t up;
+ vec3_t origin;
+ VectorScale(prog->globals.client->v_forward, scale, forward);
+ VectorScale(prog->globals.client->v_right, -scale, left);
+ VectorScale(prog->globals.client->v_up, scale, up);
+ VectorCopy(ent->fields.client->origin, origin);
+ Matrix4x4_FromVectors(out, forward, left, up, origin);
+ }
else
{
pitchsign = CL_GetPitchSign(ent);
start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
stop[2] = start[2] - 2*sv_stepheight.value;
- trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false);
if (trace.fraction == 1.0)
return false;
start[0] = stop[0] = x ? maxs[0] : mins[0];
start[1] = stop[1] = y ? maxs[1] : mins[1];
- trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false);
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
bottom = trace.endpos[2];
PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
}
+void VM_CL_RotateMoves(void)
+{
+ /*
+ * Obscure builtin used by GAME_XONOTIC.
+ *
+ * Edits the input history of cl_movement by rotating all move commands
+ * currently in the queue using the given transform.
+ *
+ * The vector passed is an "angles transform" as used by warpzonelib, i.e.
+ * v_angle-like (non-inverted) euler angles that perform the rotation
+ * of the space that is to be done.
+ *
+ * This is meant to be used as a fixangle replacement after passing
+ * through a warpzone/portal: the client is told about the warp transform,
+ * and calls this function in the same frame as the one on which the
+ * client's origin got changed by the serverside teleport. Then this code
+ * transforms the pre-warp input (which matches the empty space behind
+ * the warp plane) into post-warp input (which matches the target area
+ * of the warp). Also, at the same time, the client has to use
+ * R_SetView to adjust VF_CL_VIEWANGLES according to the same transform.
+ *
+ * This together allows warpzone motion to be perfectly predicted by
+ * the client!
+ *
+ * Furthermore, for perfect warpzone behaviour, the server side also
+ * has to detect input the client sent before it received the origin
+ * update, but after the warp occurred on the server, and has to adjust
+ * input appropriately.
+ */
+ matrix4x4_t m;
+ vec3_t v = {0, 0, 0};
+ vec3_t x, y, z;
+ VM_SAFEPARMCOUNT(1, VM_CL_RotateMoves);
+ AngleVectorsFLU(PRVM_G_VECTOR(OFS_PARM0), x, y, z);
+ Matrix4x4_FromVectors(&m, x, y, z, v);
+ CL_RotateMoves(&m);
+}
+
//============================================================================
// To create a almost working builtin file from this replace:
NULL, // #537
NULL, // #538
NULL, // #539
-NULL, // #540
-NULL, // #541
-NULL, // #542
+VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
+VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
+VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
NULL, // #543
NULL, // #544
NULL, // #545
VM_getbindmaps, // #631 vector(void) getbindmap
VM_setbindmaps, // #632 float(vector bm) setbindmap
NULL, // #633
+NULL, // #634
+NULL, // #635
+NULL, // #636
+NULL, // #637
+VM_CL_RotateMoves, // #638
+NULL, // #639
};
const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);