]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_subs.qc
Fix something I forgot, sine movement is still broken.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_subs.qc
index a331da4f0961676e43a7d0ab90f76b6059322861..8270f847dca68cccba4e995ff4ae9ac257fbcdb5 100644 (file)
@@ -2,7 +2,6 @@ void SUB_Null() {}
 float SUB_True() { return 1; }
 float SUB_False() { return 0; }
 
-void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove;
 void()  SUB_CalcMoveDone;
 void() SUB_CalcAngleMoveDone;
 //void() SUB_UseTargets;
@@ -71,24 +70,6 @@ vector animfixfps(entity e, vector a)
        return a;
 }
 
-vector animfixfps2(entity e, vector a, vector b)
-{
-       // multi-frame anim: keep as-is
-       float dur;
-       dur = frameduration(e.modelindex, a_x);
-       if(dur <= 0)
-       {
-               a = b;
-               dur = frameduration(e.modelindex, a_x);
-       }
-       if(a_y == 1)
-       {
-               if(dur > 0)
-                       a_z = 1.0 / dur;
-       }
-       return a;
-}
-
 /*
 ==================
 SUB_Remove
@@ -128,7 +109,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;
@@ -142,12 +123,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;
 }
 
 /*
@@ -163,7 +147,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;
 }
@@ -187,6 +170,7 @@ void SUB_CalcMoveDone (void)
                self.think1 ();
 }
 
+.float bezier_turn;
 void SUB_CalcMove_controller_think (void)
 {
        entity oldself;
@@ -194,31 +178,57 @@ void SUB_CalcMove_controller_think (void)
        float phasepos;
        float nexttick;
        vector delta;
+       vector delta2;
        vector veloc;
        vector nextpos;
+       delta = self.destvec;
+       delta2 = self.destvec2;
        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);
+               traveltime = self.animstate_endtime - self.animstate_starttime;
+               phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
+               if(!self.platmovetype)
+                       self.platmovetype = 2; // default
+               switch(self.platmovetype)
+               {
+                       case 1: // linear
+                               break;
+                       case 2: // cosine
+                               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]
+                               break;
+                       case 3: // sine
+                               phasepos = 3.14159265 + (phasepos * 3.14159265); // range: [pi, 2pi]
+                               phasepos = sin(phasepos); // sin [pi, 2pi] is in [-1, 1]
+                               phasepos = phasepos + 1; // correct range to [0, 2]
+                               phasepos = phasepos / 2; // correct range to [0, 1]
+                               break;
+               }
+               nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
+               // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
 
+               if(nexttick < self.animstate_endtime) {
                        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;
+               if(self.owner.bezier_turn)
+               {
+                       vector vel;
+                       vel = delta + 2 * delta2 * phasepos;
+                       vel_z = -vel_z; // invert z velocity
+                       vel = vectoangles(vel);
+                       self.owner.angles = vel;
+               }
                self.nextthink = nexttick;
        } else {
+               // derivative: delta + 2 * delta2 (e.g. for angle positioning)
                oldself = self;
                self.owner.think = self.think1;
                self = self.owner;
@@ -227,9 +237,42 @@ void SUB_CalcMove_controller_think (void)
        }
 }
 
-void SUB_CalcMove (vector tdest, float tspeed, void() func)
+void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest)
+{
+       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t
+       // 2 * control * t - 2 * control * t * t + dest * t * t
+       // 2 * control * t + (dest - 2 * control) * t * t
+
+       controller.origin = org; // starting point
+       control -= org;
+       dest -= org;
+
+       controller.destvec = 2 * control; // control point
+       controller.destvec2 = dest - 2 * control; // quadratic part required to reach end point
+       // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (dest - control)
+}
+
+void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest)
+{
+       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t
+       // 2 * control * t - 2 * control * t * t + dest * t * t
+       // 2 * control * t + (dest - 2 * control) * t * t
+
+       controller.origin = org; // starting point
+       dest -= org;
+
+       controller.destvec = dest; // 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 (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
 {
-       vector  delta;
        float   traveltime;
        entity controller;
 
@@ -240,40 +283,36 @@ void SUB_CalcMove (vector tdest, float tspeed, void() func)
        self.finaldest = tdest;
        self.think = SUB_CalcMoveDone;
 
-       if (tdest == self.origin)
+       switch(tspeedtype)
        {
-               self.velocity = '0 0 0';
-               self.nextthink = self.ltime + 0.1;
-               return;
+               default:
+               case TSPEED_START:
+                       traveltime = 2 * vlen(tcontrol - self.origin) / tspeed;
+                       break;
+               case TSPEED_END:
+                       traveltime = 2 * vlen(tcontrol - tdest)       / tspeed;
+                       break;
+               case TSPEED_LINEAR:
+                       traveltime = vlen(tdest - self.origin)        / tspeed;
+                       break;
+               case TSPEED_TIME:
+                       traveltime = tspeed;
+                       break;
        }
 
-       delta = tdest - self.origin;
-       traveltime = vlen (delta) / tspeed;
-
-       if (traveltime < 0.1)
+       if (traveltime < 0.1) // useless anim
        {
                self.velocity = '0 0 0';
                self.nextthink = self.ltime + 0.1;
                return;
        }
 
-       // 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.platmovetype = self.platmovetype;
+       SUB_CalcMove_controller_setbezier(controller, self.origin, tcontrol, tdest);
        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;
@@ -289,14 +328,63 @@ void SUB_CalcMove (vector tdest, float tspeed, void() func)
        self = self.owner;
 }
 
-void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
+void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
+{
+       vector  delta;
+       float   traveltime;
+
+       if (!tspeed)
+               objerror ("No speed is defined!");
+
+       self.think1 = func;
+       self.finaldest = tdest;
+       self.think = SUB_CalcMoveDone;
+
+       if (tdest == self.origin)
+       {
+               self.velocity = '0 0 0';
+               self.nextthink = self.ltime + 0.1;
+               return;
+       }
+
+       delta = tdest - self.origin;
+
+       switch(tspeedtype)
+       {
+               default:
+               case TSPEED_START:
+               case TSPEED_END:
+               case TSPEED_LINEAR:
+                       traveltime = vlen (delta) / tspeed;
+                       break;
+               case TSPEED_TIME:
+                       traveltime = tspeed;
+                       break;
+       }
+
+       // 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 < 2)
+       {
+               self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
+               self.nextthink = self.ltime + traveltime;
+               return;
+       }
+
+       // now just run like a bezier curve...
+       SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
+}
+
+void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
 {
        entity  oldself;
 
        oldself = self;
        self = ent;
 
-       SUB_CalcMove (tdest, tspeed, func);
+       SUB_CalcMove (tdest, tspeedtype, tspeed, func);
 
        self = oldself;
 }
@@ -322,7 +410,7 @@ void SUB_CalcAngleMoveDone (void)
 }
 
 // FIXME: I fixed this function only for rotation around the main axes
-void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
+void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func)
 {
        vector  delta;
        float   traveltime;
@@ -335,7 +423,19 @@ void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
        self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
        self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
        delta = destangle - self.angles;
-       traveltime = vlen (delta) / tspeed;
+
+       switch(tspeedtype)
+       {
+               default:
+               case TSPEED_START:
+               case TSPEED_END:
+               case TSPEED_LINEAR:
+                       traveltime = vlen (delta) / tspeed;
+                       break;
+               case TSPEED_TIME:
+                       traveltime = tspeed;
+                       break;
+       }
 
        self.think1 = func;
        self.finalangle = destangle;
@@ -352,14 +452,14 @@ void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
        self.nextthink = self.ltime + traveltime;
 }
 
-void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeed, void() func)
+void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
 {
        entity  oldself;
 
        oldself = self;
        self = ent;
 
-       SUB_CalcAngleMove (destangle, tspeed, func);
+       SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func);
 
        self = oldself;
 }
@@ -398,11 +498,9 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma,
                lag = 0; // only antilag for clients
 
        // change shooter to SOLID_BBOX so the shot can hit corpses
+       oldsolid = source.dphitcontentsmask;
        if(source)
-       {
-               oldsolid = source.dphitcontentsmask;
                source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
-       }
 
        if (lag)
        {