]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_subs.qc
Merge remote branch 'origin/terencehill/physics_panel_updates'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_subs.qc
index 47f3a5a699b8daa78b7d9a896304a5ae681a6a0c..e119e5aba40040a359eca73d26d6a909f6f5d128 100644 (file)
@@ -1,4 +1,4 @@
-void SUB_Null() {};
+void SUB_Null() {}
 float SUB_True() { return 1; }
 float SUB_False() { return 0; }
 
@@ -16,6 +16,9 @@ void spawnfunc_info_null (void)
 
 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)
@@ -38,7 +41,7 @@ void setanim(entity e, vector anim, float looping, float override, float restart
        e.animstate_override = override;
        e.frame = e.animstate_startframe;
        e.frame1time = servertime;
-};
+}
 
 void updateanim(entity e)
 {
@@ -53,31 +56,20 @@ void updateanim(entity e)
        }
        e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, e.animstate_numframes - 1);
        //print(ftos(time), " -> ", ftos(e.frame), "\n");
-};
-
-float animparseerror;
-vector animparseline(float animfile)
-{
-       local string line;
-       local float c;
-       local vector anim;
-       if (animfile < 0)
-               return '0 1 2';
-       line = fgets(animfile);
-       c = tokenize_console(line);
-       if (c < 3)
+}
+
+vector animfixfps(entity e, vector a)
+{
+       // multi-frame anim: keep as-is
+       if(a_y == 1)
        {
-               animparseerror = TRUE;
-               return '0 1 2';
+               float dur;
+               dur = frameduration(e.modelindex, a_x);
+               if(dur > 0)
+                       a_z = 1.0 / dur;
        }
-       anim_x = stof(argv(0));
-       anim_y = stof(argv(1));
-       anim_z = stof(argv(2));
-       // don't allow completely bogus values
-       if (anim_x < 0 || anim_y < 1 || anim_z < 0.001)
-               anim = '0 1 2';
-       return anim;
-};
+       return a;
+}
 
 /*
 ==================
@@ -118,7 +110,7 @@ void SUB_VanishOrRemove (entity ent)
        if (ent.flags & FL_CLIENT)
        {
                // vanish
-               ent.model = "";
+               ent.alpha = -1;
                ent.effects = 0;
                ent.glow_size = 0;
                ent.pflags = 0;
@@ -132,12 +124,15 @@ void SUB_VanishOrRemove (entity ent)
 
 void SUB_SetFade_Think (void)
 {
+       if(self.alpha == 0)
+               self.alpha = 1;
        self.think = SUB_SetFade_Think;
-       self.nextthink = self.fade_time;
-       self.alpha = 1 - (time - self.fade_time) * self.fade_rate;
+       self.nextthink = time;
+       self.alpha -= frametime * self.fade_rate;
        if (self.alpha < 0.01)
                SUB_VanishOrRemove(self);
-       self.alpha = bound(0.01, self.alpha, 1);
+       else
+               self.nextthink = time;
 }
 
 /*
@@ -153,7 +148,6 @@ void SUB_SetFade (entity ent, float when, float fadetime)
        //      return;
        //ent.alpha = 1;
        ent.fade_rate = 1/fadetime;
-       ent.fade_time = when;
        ent.think = SUB_SetFade_Think;
        ent.nextthink = when;
 }
@@ -177,10 +171,51 @@ void SUB_CalcMoveDone (void)
                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!");
@@ -206,9 +241,36 @@ void SUB_CalcMove (vector tdest, float tspeed, void() func)
                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)
@@ -310,8 +372,8 @@ Additionally it moves players back into the past before the trace and restores t
 */
 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
 {
-       local entity player;
-       local float oldsolid;
+       entity player;
+       float oldsolid;
 
        // check whether antilagged traces are enabled
        if (lag < 0.001)
@@ -329,12 +391,9 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma,
        if (lag)
        {
                // take players back into the past
-               player = player_list;
-               while (player)
-               {
-                       antilag_takeback(player, time - lag);
-                       player = player.nextplayer;
-               }
+               FOR_EACH_PLAYER(player)
+                       if(player != forent)
+                               antilag_takeback(player, time - lag);
        }
 
        // do the trace
@@ -346,12 +405,9 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma,
        // restore players to current positions
        if (lag)
        {
-               player = player_list;
-               while (player)
-               {
-                       antilag_restore(player);
-                       player = player.nextplayer;
-               }
+               FOR_EACH_PLAYER(player)
+                       if(player != forent)
+                               antilag_restore(player);
        }
 
        // restore shooter solid type
@@ -698,6 +754,33 @@ void LODmodel_attach()
                        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()
 {
        if(self.model != "")
@@ -707,10 +790,7 @@ 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()
@@ -721,10 +801,7 @@ 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);
 }
 
 /*
@@ -744,7 +821,7 @@ void SetMovedir()
        }
 
        self.angles = '0 0 0';
-};
+}
 
 void InitTrigger()
 {
@@ -756,7 +833,7 @@ void InitTrigger()
        self.movetype = MOVETYPE_NONE;
        self.modelindex = 0;
        self.model = "";
-};
+}
 
 void InitSolidBSPTrigger()
 {
@@ -768,7 +845,7 @@ void InitSolidBSPTrigger()
        self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
 //     self.modelindex = 0;
        self.model = "";
-};
+}
 
 float InitMovingBrushTrigger()
 {
@@ -783,4 +860,4 @@ float InitMovingBrushTrigger()
                return 0;
        }
        return 1;
-};
+}