void setanim(entity e, vector anim, float looping, float override, float restart)
{
+ if (!anim)
+ return; // no animation was given to us! We can't use this.
+
if (anim_x == e.animstate_startframe)
if (anim_y == e.animstate_numframes)
if (anim_z == e.animstate_framerate)
e.animstate_looping = looping;
e.animstate_override = override;
e.frame = e.animstate_startframe;
+ e.frame1time = servertime;
};
void updateanim(entity e)
self.think1 ();
}
+void SUB_CalcMove_controller_think (void)
+{
+ entity oldself;
+ float traveltime;
+ float phasepos;
+ float nexttick;
+ vector delta;
+ vector veloc;
+ vector nextpos;
+ if(time < self.animstate_endtime) {
+ delta = self.destvec;
+ nexttick = time + sys_frametime;
+
+ if(nexttick < self.animstate_endtime) {
+ traveltime = self.animstate_endtime - self.animstate_starttime;
+ phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
+ phasepos = 3.14159265 + (phasepos * 3.14159265); // range: [pi, 2pi]
+ phasepos = cos(phasepos); // cos [pi, 2pi] is in [-1, 1]
+ phasepos = phasepos + 1; // correct range to [0, 2]
+ phasepos = phasepos / 2; // correct range to [0, 1]
+ nextpos = self.origin + (delta * phasepos);
+
+ veloc = nextpos - self.owner.origin;
+ veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
+
+ } else {
+ veloc = self.finaldest - self.owner.origin;
+ veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
+ }
+ self.owner.velocity = veloc;
+ self.nextthink = nexttick;
+ } else {
+ oldself = self;
+ self.owner.think = self.think1;
+ self = self.owner;
+ remove(oldself);
+ self.think();
+ }
+}
+
void SUB_CalcMove (vector tdest, float tspeed, void() func)
{
vector delta;
float traveltime;
+ entity controller;
if (!tspeed)
objerror ("No speed is defined!");
return;
}
- self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
+ // Very short animations don't really show off the effect
+ // of controlled animation, so let's just use linear movement.
+ // Alternatively entities can choose to specify non-controlled movement.
+ // The only currently implemented alternative movement is linear (value 1)
+ if (traveltime < 0.15 || self.platmovetype == 1)
+ {
+ self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
+ self.nextthink = self.ltime + traveltime;
+ return;
+ }
+ controller = spawn();
+ controller.classname = "SUB_CalcMove_controller";
+ controller.owner = self;
+ controller.origin = self.origin; // starting point
+ controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
+ controller.destvec = delta;
+ controller.animstate_starttime = time;
+ controller.animstate_endtime = time + traveltime;
+ controller.think = SUB_CalcMove_controller_think;
+ controller.think1 = self.think;
+
+ // the thinking is now done by the controller
+ self.think = SUB_Null;
self.nextthink = self.ltime + traveltime;
+
+ // invoke controller
+ self = controller;
+ self.think();
+ self = self.owner;
}
void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
}
void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
{
- if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag)
+ if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
lag = 0;
traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
}
void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
{
- if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag)
+ if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
lag = 0;
tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, FALSE);
}
}
void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
{
- if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag)
+ if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
lag = 0;
WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
}
void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
{
- if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag)
+ if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
lag = 0;
tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, TRUE);
}
.float loddistance1;
.float loddistance2;
-vector NearestPointOnBox(entity box, vector org);
float LOD_customize()
{
float d;
- if(cvar("loddebug"))
+ if(autocvar_loddebug)
{
- d = cvar("loddebug");
+ d = autocvar_loddebug;
if(d == 1)
self.modelindex = self.lodmodelindex0;
- else if(d == 2)
+ else if(d == 2 || !self.lodmodelindex2)
self.modelindex = self.lodmodelindex1;
else // if(d == 3)
self.modelindex = self.lodmodelindex2;
}
}
- if(cvar("loddebug") < 0)
+ if(autocvar_loddebug < 0)
{
self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize
}
}
if(self.lodmodelindex1)
- SetCustomizer(self, LOD_customize, LOD_uncustomize);
+ if not(self.SendEntity)
+ SetCustomizer(self, LOD_customize, LOD_uncustomize);
+}
+
+void ApplyMinMaxScaleAngles(entity e)
+{
+ if(e.angles_x != 0 || e.angles_z != 0 || self.avelocity_x != 0 || self.avelocity_z != 0) // "weird" rotation
+ {
+ e.maxs = '1 1 1' * vlen(
+ '1 0 0' * max(-e.mins_x, e.maxs_x) +
+ '0 1 0' * max(-e.mins_y, e.maxs_y) +
+ '0 0 1' * max(-e.mins_z, e.maxs_z)
+ );
+ e.mins = -e.maxs;
+ }
+ else if(e.angles_y != 0 || self.avelocity_y != 0) // yaw only is a bit better
+ {
+ e.maxs_x = vlen(
+ '1 0 0' * max(-e.mins_x, e.maxs_x) +
+ '0 1 0' * max(-e.mins_y, e.maxs_y)
+ );
+ e.maxs_y = e.maxs_x;
+ e.mins_x = -e.maxs_x;
+ e.mins_y = -e.maxs_x;
+ }
+ if(e.scale)
+ setsize(e, e.mins * e.scale, e.maxs * e.scale);
+ else
+ setsize(e, e.mins, e.maxs);
}
void SetBrushEntityModel()
InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
}
setorigin(self, self.origin);
- if(self.scale)
- setsize(self, self.mins * self.scale, self.maxs * self.scale);
- else
- setsize(self, self.mins, self.maxs);
+ ApplyMinMaxScaleAngles(self);
}
void SetBrushEntityModelNoLOD()
setmodel(self, self.model); // no precision needed
}
setorigin(self, self.origin);
- if(self.scale)
- setsize(self, self.mins * self.scale, self.maxs * self.scale);
- else
- setsize(self, self.mins, self.maxs);
+ ApplyMinMaxScaleAngles(self);
}
/*
{
// trigger angles are used for one-way touches. An angle of 0 is assumed
// to mean no restrictions, so use a yaw of 360 instead.
- if (self.movedir == '0 0 0')
- if (self.angles != '0 0 0')
- SetMovedir ();
+ SetMovedir ();
self.solid = SOLID_TRIGGER;
SetBrushEntityModel();
self.movetype = MOVETYPE_NONE;
{
// trigger angles are used for one-way touches. An angle of 0 is assumed
// to mean no restrictions, so use a yaw of 360 instead.
- if (self.movedir == '0 0 0')
- if (self.angles != '0 0 0')
- SetMovedir ();
+ SetMovedir ();
self.solid = SOLID_BSP;
SetBrushEntityModel();
self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0