#include "subs.qh"
+
void SUB_NullThink(entity this) { }
void SUB_CalcMoveDone(entity this);
void SUB_CalcAngleMoveDone(entity this);
+#ifdef SVQC
+spawnfunc(info_null)
+{
+ delete(this);
+ // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
+}
+#endif
+
/*
==================
SUB_Friction
==================
SUB_SetFade
-Fade 'ent' out when time >= 'when'
+Fade ent out when time >= vanish_time
==================
*/
-void SUB_SetFade (entity ent, float when, float fading_time)
+void SUB_SetFade(entity ent, float vanish_time, float fading_time)
{
+ if (fading_time <= 0)
+ fading_time = 0.01;
ent.fade_rate = 1/fading_time;
setthink(ent, SUB_SetFade_Think);
- ent.nextthink = when;
+ ent.nextthink = vanish_time;
}
/*
this.think1 (this);
}
+void SUB_CalcMovePause(entity this)
+{
+ this.move_controller.animstate_starttime += frametime;
+ this.move_controller.animstate_endtime += frametime;
+}
+
.float platmovetype_turn;
void SUB_CalcMove_controller_think (entity this)
{
// 2 * control * t - 2 * control * t * t + destin * t * t
// 2 * control * t + (destin - 2 * control) * t * t
- setorigin(controller, org);
+ //setorigin(controller, org); // don't link to the world
+ controller.origin = org;
control -= org;
destin -= org;
// 2 * control * t - 2 * control * t * t + destin * t * t
// 2 * control * t + (destin - 2 * control) * t * t
- setorigin(controller, org);
+ //setorigin(controller, org); // don't link to the world
+ controller.origin = org;
destin -= org;
controller.destvec = destin; // end point
controller.destvec2 = '0 0 0';
}
-float TSPEED_TIME = -1;
-float TSPEED_LINEAR = 0;
-float TSPEED_START = 1;
-float TSPEED_END = 2;
-// TODO average too?
-
void SUB_CalcMove_Bezier (entity this, vector tcontrol, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
{
float traveltime;
{
delete(this.move_controller);
}
- controller = new(SUB_CalcMove_controller);
+ controller = new_pure(SUB_CalcMove_controller);
controller.owner = this;
this.move_controller = controller;
controller.platmovetype = this.platmovetype;
// 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)
+ // The only currently implemented alternative movement is linear (value 1)
if (traveltime < 0.15 || (this.platmovetype_start == 1 && this.platmovetype_end == 1)) // is this correct?
{
this.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
{
SUB_CalcAngleMove (ent, destangle, tspeedtype, tspeed, func);
}
+
+#ifdef SVQC
+void ApplyMinMaxScaleAngles(entity e)
+{
+ if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.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 || e.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, RoundPerfectVector(e.mins * e.scale), RoundPerfectVector(e.maxs * e.scale));
+ else
+ setsize(e, e.mins, e.maxs);
+}
+
+void SetBrushEntityModel(entity this, bool with_lod)
+{
+ if(this.model != "")
+ {
+ precache_model(this.model);
+ if(this.mins != '0 0 0' || this.maxs != '0 0 0')
+ {
+ vector mi = this.mins;
+ vector ma = this.maxs;
+ _setmodel(this, this.model); // no precision needed
+ setsize(this, mi, ma);
+ }
+ else
+ _setmodel(this, this.model); // no precision needed
+ if(with_lod)
+ InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
+
+ if(endsWith(this.model, ".obj")) // WORKAROUND: darkplaces currently rotates .obj models on entities incorrectly, we need to add 180 degrees to the Y axis
+ this.angles_y = anglemods(this.angles_y - 180);
+ }
+ setorigin(this, this.origin);
+ ApplyMinMaxScaleAngles(this);
+}
+
+bool LOD_customize(entity this, entity client)
+{
+ if(autocvar_loddebug)
+ {
+ int d = autocvar_loddebug;
+ if(d == 1)
+ this.modelindex = this.lodmodelindex0;
+ else if(d == 2 || !this.lodmodelindex2)
+ this.modelindex = this.lodmodelindex1;
+ else // if(d == 3)
+ this.modelindex = this.lodmodelindex2;
+ return true;
+ }
+
+ // TODO csqc network this so it only gets sent once
+ vector near_point = NearestPointOnBox(this, client.origin);
+ if(vdist(near_point - client.origin, <, this.loddistance1))
+ this.modelindex = this.lodmodelindex0;
+ else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
+ this.modelindex = this.lodmodelindex1;
+ else
+ this.modelindex = this.lodmodelindex2;
+
+ return true;
+}
+
+void LOD_uncustomize(entity this)
+{
+ this.modelindex = this.lodmodelindex0;
+}
+
+void LODmodel_attach(entity this)
+{
+ entity e;
+
+ if(!this.loddistance1)
+ this.loddistance1 = 1000;
+ if(!this.loddistance2)
+ this.loddistance2 = 2000;
+ this.lodmodelindex0 = this.modelindex;
+
+ if(this.lodtarget1 != "")
+ {
+ e = find(NULL, targetname, this.lodtarget1);
+ if(e)
+ {
+ this.lodmodel1 = e.model;
+ delete(e);
+ }
+ }
+ if(this.lodtarget2 != "")
+ {
+ e = find(NULL, targetname, this.lodtarget2);
+ if(e)
+ {
+ this.lodmodel2 = e.model;
+ delete(e);
+ }
+ }
+
+ if(autocvar_loddebug < 0)
+ {
+ this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
+ }
+
+ if(this.lodmodel1 != "")
+ {
+ vector mi, ma;
+ mi = this.mins;
+ ma = this.maxs;
+
+ precache_model(this.lodmodel1);
+ _setmodel(this, this.lodmodel1);
+ this.lodmodelindex1 = this.modelindex;
+
+ if(this.lodmodel2 != "")
+ {
+ precache_model(this.lodmodel2);
+ _setmodel(this, this.lodmodel2);
+ this.lodmodelindex2 = this.modelindex;
+ }
+
+ this.modelindex = this.lodmodelindex0;
+ setsize(this, mi, ma);
+ }
+
+ if(this.lodmodelindex1)
+ if (!getSendEntity(this))
+ SetCustomizer(this, LOD_customize, LOD_uncustomize);
+}
+
+/*
+================
+InitTrigger
+================
+*/
+
+void SetMovedir(entity this)
+{
+ if(this.movedir != '0 0 0')
+ this.movedir = normalize(this.movedir);
+ else
+ {
+ makevectors(this.angles);
+ this.movedir = v_forward;
+ }
+
+ this.angles = '0 0 0';
+}
+
+void InitTrigger(entity this)
+{
+// 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.
+ SetMovedir(this);
+ this.solid = SOLID_TRIGGER;
+ SetBrushEntityModel(this, false);
+ set_movetype(this, MOVETYPE_NONE);
+ this.modelindex = 0;
+ this.model = "";
+}
+
+void InitSolidBSPTrigger(entity this)
+{
+// 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.
+ SetMovedir(this);
+ this.solid = SOLID_BSP;
+ SetBrushEntityModel(this, false);
+ set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
+// this.modelindex = 0;
+ this.model = "";
+}
+
+bool InitMovingBrushTrigger(entity this)
+{
+// 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.
+ this.solid = SOLID_BSP;
+ SetBrushEntityModel(this, true);
+ set_movetype(this, MOVETYPE_PUSH);
+ if(this.modelindex == 0)
+ {
+ objerror(this, "InitMovingBrushTrigger: no brushes found!");
+ return false;
+ }
+ return true;
+}
+#endif