]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/movetypes.qc
Move more stuff around
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / movetypes.qc
index 88e921cbeace695f5875776708a4da35e0e3cf8d..2a46de11213e37cbc81df6659ff38073e0ea26d9 100644 (file)
@@ -1,5 +1,16 @@
-const float STAT_MOVEFLAGS = 225;
-const float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
+#if defined(CSQC)
+       #include "../dpdefs/csprogsdefs.qh"
+       #include "defs.qh"
+       #include "../common/stats.qh"
+       #include "../common/util.qh"
+       #include "movetypes.qh"
+       #include "../csqcmodellib/common.qh"
+       #include "../server/t_items.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+
 #define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
 
 .entity move_groundentity; // FIXME add move_groundnetworkentity?
@@ -10,51 +21,12 @@ void _Movetype_CheckVelocity() // SV_CheckVelocity
 {
 }
 
-float Mod_Q1BSP_SuperContentsFromNativeContents(float nativecontents)
-{
-       switch(nativecontents)
-       {
-               case CONTENT_EMPTY:
-                       return 0;
-               case CONTENT_SOLID:
-                       return DPCONTENTS_SOLID | DPCONTENTS_OPAQUE;
-               case CONTENT_WATER:
-                       return DPCONTENTS_WATER;
-               case CONTENT_SLIME:
-                       return DPCONTENTS_SLIME;
-               case CONTENT_LAVA:
-                       return DPCONTENTS_LAVA | DPCONTENTS_NODROP;
-               case CONTENT_SKY:
-                       return DPCONTENTS_SKY | DPCONTENTS_NODROP | DPCONTENTS_OPAQUE; // to match behaviour of Q3 maps, let sky count as opaque
-       }
-       return 0;
-}
-
-float Mod_Q1BSP_NativeContentsFromSuperContents(float supercontents)
-{
-       if(supercontents & (DPCONTENTS_SOLID | DPCONTENTS_BODY))
-               return CONTENT_SOLID;
-       if(supercontents & DPCONTENTS_SKY)
-               return CONTENT_SKY;
-       if(supercontents & DPCONTENTS_LAVA)
-               return CONTENT_LAVA;
-       if(supercontents & DPCONTENTS_SLIME)
-               return CONTENT_SLIME;
-       if(supercontents & DPCONTENTS_WATER)
-               return CONTENT_WATER;
-       return CONTENT_EMPTY;
-}
-
 float _Movetype_CheckWater(entity ent) // SV_CheckWater
 {
-       float supercontents;
-       float nativecontents;
-       vector point;
-
-       point = ent.move_origin;
+       vector point = ent.move_origin;
        point_z += (ent.mins_z + 1);
 
-       nativecontents = pointcontents(point);
+       int nativecontents = pointcontents(point);
 
        if(ent.move_watertype)
        if(ent.move_watertype != nativecontents)
@@ -67,7 +39,7 @@ float _Movetype_CheckWater(entity ent) // SV_CheckWater
        ent.move_waterlevel = 0;
        ent.move_watertype = CONTENT_EMPTY;
 
-       supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
+       int supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
        if(supercontents & DPCONTENTS_LIQUIDSMASK)
        {
                ent.move_watertype = nativecontents;
@@ -88,7 +60,7 @@ float _Movetype_CheckWater(entity ent) // SV_CheckWater
 void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
 {
        float contents = pointcontents(ent.move_origin);
-       
+
        if(!ent.move_watertype)
        {
                // just spawned here
@@ -161,11 +133,11 @@ void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
                        self = e;
                        other = oldself;
 
-                       trace_allsolid = FALSE;
-                       trace_startsolid = FALSE;
+                       trace_allsolid = false;
+                       trace_startsolid = false;
                        trace_fraction = 1;
-                       trace_inwater = FALSE;
-                       trace_inopen = TRUE;
+                       trace_inwater = false;
+                       trace_inopen = true;
                        trace_endpos = e.origin;
                        trace_plane_normal = '0 0 1';
                        trace_plane_dist = 0;
@@ -225,26 +197,25 @@ void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
 float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
 {
        vector org;
-       float cont;
        org = self.move_origin + ofs;
 
-       cont = self.dphitcontentsmask;
+       int cont = self.dphitcontentsmask;
        self.dphitcontentsmask = DPCONTENTS_SOLID;
        tracebox(self.move_origin, self.mins, self.maxs, self.move_origin, MOVE_NOMONSTERS, self);
        self.dphitcontentsmask = cont;
 
        if(trace_startsolid)
-               return TRUE;
+               return true;
 
        if(vlen(trace_endpos - self.move_origin) > 0.0001)
                self.move_origin = trace_endpos;
-       return FALSE;
+       return false;
 }
 
 float _Movetype_UnstickEntity() // SV_UnstickEntity
 {
        if(!_Movetype_TestEntityPosition('0 0 0'))
-               return TRUE;
+               return true;
        if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
        if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
        if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
@@ -259,12 +230,12 @@ float _Movetype_UnstickEntity() // SV_UnstickEntity
                if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
                if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
        }
-       dprintf(_("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.move_origin));
-       return FALSE;
+       dprintf("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
+       return false;
 :success
-       dprintf(_("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.move_origin));
-       _Movetype_LinkEdict(TRUE);
-       return TRUE;
+       dprintf("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
+       _Movetype_LinkEdict(true);
+       return true;
 }
 
 vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
@@ -313,7 +284,337 @@ float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
        return trace_fraction;
 }
 
-#define MAX_CLIP_PLANES 5
+
+.float ltime;
+.void() blocked;
+void _Movetype_AngleVectorsFLU(vector myangles) // AngleVectorsFLU
+{
+       float angle, sr, sp, sy, cr, cp, cy;
+
+       angle = myangles_y * (M_PI*2 / 360);
+       sy = sin(angle);
+       cy = cos(angle);
+       angle = myangles_x * (M_PI*2 / 360);
+       sp = sin(angle);
+       cp = cos(angle);
+       if(v_forward)
+       {
+               v_forward_x = cp*cy;
+               v_forward_y = cp*sy;
+               v_forward_z = -sp;
+       }
+       if(v_right || v_up)
+       {
+               if(myangles_z)
+               {
+                       angle = myangles_z * (M_PI*2 / 360);
+                       sr = sin(angle);
+                       cr = cos(angle);
+                       if(v_right)
+                       {
+                               v_right_x = sr*sp*cy+cr*-sy;
+                               v_right_y = sr*sp*sy+cr*cy;
+                               v_right_z = sr*cp;
+                       }
+                       if(v_up)
+                       {
+                               v_up_x = cr*sp*cy+-sr*-sy;
+                               v_up_y = cr*sp*sy+-sr*cy;
+                               v_up_z = cr*cp;
+                       }
+               }
+               else
+               {
+                       if(v_right)
+                       {
+                               v_right_x = -sy;
+                               v_right_y = cy;
+                               v_right_z = 0;
+                       }
+                       if(v_up)
+                       {
+                               v_up_x = sp*cy;
+                               v_up_y = sp*sy;
+                               v_up_z = cp;
+                       }
+               }
+       }
+}
+
+void _Movetype_PushMove(float dt) // SV_PushMove
+{
+       float pushltime;
+       //int pusherowner;
+       //int i;
+       //int num_moved;
+       //int numcheckentities;
+       int savesolid;
+       bool rotated;
+       vector move1, moveangle;
+       vector a;
+       vector pushorig, pushang;
+       vector org;
+       vector move;
+       entity oldself;
+
+       if(!vlen(self.move_velocity) && !vlen(self.move_avelocity))
+       {
+               self.ltime += dt;
+               return;
+       }
+
+       switch(self.solid)
+       {
+       // LordHavoc: valid pusher types
+       case SOLID_BSP:
+       case SOLID_BBOX:
+       case SOLID_SLIDEBOX:
+       case SOLID_CORPSE: // LordHavoc: this would be weird...
+               break;
+       // LordHavoc: no collisions
+       case SOLID_NOT:
+       case SOLID_TRIGGER:
+               
+               self.move_origin = self.move_origin + self.move_velocity * dt;
+               self.move_angles_x -= 360.0 * floor(self.move_angles_x * (1.0 / 360.0));
+               self.move_angles_y -= 360.0 * floor(self.move_angles_y * (1.0 / 360.0));
+               self.move_angles_z -= 360.0 * floor(self.move_angles_z * (1.0 / 360.0));
+               self.ltime += dt;
+               _Movetype_LinkEdict(true);
+               return;
+       default:
+               printf("_Movetype_PushMove: entity %e with classname %s, unrecognized solid type %d\n", num_for_edict(self), self.classname, self.solid);
+               return;
+       }
+       if(!self.modelindex || self.model == "null")
+       {
+               printf("_Movetype_PushMove: entity %e with classname %s, unusable modelindex %f\n", num_for_edict(self), self.classname, self.modelindex);
+               return;
+       }
+       //pusherowner = self.owner;
+
+       rotated = (self.move_angles * self.move_avelocity) > 0;
+
+       move1 = self.move_velocity * dt;
+       moveangle = self.move_avelocity * dt;
+
+       a = -moveangle;
+
+       // sets v_forward, v_right and v_up
+       _Movetype_AngleVectorsFLU(a);
+
+       pushorig = self.move_origin;
+       pushang = self.move_angles;
+       pushltime = self.ltime;
+
+// move the pusher to its final position
+
+       self.move_origin = self.move_origin + self.move_velocity * dt;
+       self.move_angles = self.move_angles + self.move_avelocity * dt;
+       self.ltime += dt;
+       _Movetype_LinkEdict(true);
+
+       //pushermodel = SV_GetModelFromEdict(pusher);
+       //Matrix4x4_CreateFromQuakeEntity(&pusherfinalmatrix, PRVM_serveredictvector(pusher, origin)[0], PRVM_serveredictvector(pusher, origin)[1], PRVM_serveredictvector(pusher, origin)[2],
+         //PRVM_serveredictvector(pusher, angles)[0], PRVM_serveredictvector(pusher, angles)[1], PRVM_serveredictvector(pusher, angles)[2], 1);
+       //Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
+
+       savesolid = self.solid;
+
+// see if any solid entities are inside the final position
+       //num_moved = 0;
+
+       entity e;
+       if(self.move_movetype != MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
+       for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
+       {
+               if(e.owner == self)
+                       continue;
+
+               if(self.owner == e)
+                       continue;
+
+               //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
+
+               // tell any MOVETYPE_STEP entity that it may need to check for water transitions
+               //check->priv.server->waterposition_forceupdate = true;
+
+               //int checkcontents = pointcontents(e.move_origin);
+
+               // if the entity is standing on the pusher, it will definitely be moved
+               // if the entity is not standing on the pusher, but is in the pusher's
+               // final position, move it
+               if(!(e.move_flags & FL_ONGROUND) || e.move_groundentity != self)
+               {
+                       //vector pushermins = self.mins;
+                       //vector pushermaxs = self.maxs;
+                       //vector checkorigin = e.origin;
+                       //vector checkmins = e.mins;
+                       //vector checkmaxs = e.maxs;
+                       //Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, 
+                               //&pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, collision_extendmovelength.value);
+                       tracebox(e.move_origin, e.mins, e.maxs, self.move_origin, MOVE_NOMONSTERS, e);
+                       if(!trace_startsolid)
+                       {
+                               //Con_Printf("- not in solid\n");
+                               continue;
+                       }
+               }
+               vector pivot = e.mins + 0.5 * (e.maxs - e.mins);
+               //VectorClear(pivot);
+
+               if(rotated)
+               {
+                       vector org2;
+                       org = e.move_origin - self.move_origin;
+                       org += pivot;
+                       org2_x = (org * v_forward);
+                       org2_y = (org * v_right);
+                       org2_z = (org * v_up);
+                       move = org2 - org;
+                       move += move1;
+               }
+               else
+                       move = move1;
+
+               //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
+
+               //VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
+               //VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
+               //moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
+
+               // physics objects need better collisions than this code can do
+               /*if(e.move_movetype == MOVETYPE_PHYSICS)
+               {
+                       e.move_origin += move;
+                       oldself = self;
+                       self = e;
+                       _Movetype_LinkEdict(false);
+                       _Movetype_LinkEdict_TouchAreaGrid();
+                       self = oldself;
+                       continue;
+               }*/
+
+               // try moving the contacted entity
+               self.solid = SOLID_NOT;
+               oldself = self;
+               self = e;
+               if(!_Movetype_PushEntity(move, true))
+               {
+                       // entity "check" got teleported
+                       self.angles_y += trace_fraction * moveangle_y;
+                       oldself.solid = savesolid;
+                       continue; // pushed enough
+               }
+               self = oldself;
+               // FIXME: turn players specially
+               e.angles_y += trace_fraction * moveangle_y;
+               self.solid = savesolid;
+               //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
+
+               // this trace.fraction < 1 check causes items to fall off of pushers
+               // if they pass under or through a wall
+               // the groundentity check causes items to fall off of ledges
+               if(e.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || e.move_groundentity != self))
+                       e.move_flags &= ~FL_ONGROUND;
+
+               // if it is still inside the pusher, block
+               //vector pushermins = self.mins;
+               //vector pushermaxs = self.maxs;
+               //vector checkorigin = e.move_origin;
+               //vector checkmins = e.mins;
+               //vector checkmaxs = e.maxs; 
+               //Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, 
+                               //&pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, collision_extendmovelength.value);
+               tracebox(e.move_origin, e.mins, e.maxs, self.move_origin, MOVE_NOMONSTERS, e);
+               if(trace_startsolid)
+               {
+                       /*vector move2;
+                       if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
+                       {
+                               // hack to invoke all necessary movement triggers
+                               move2 = '0 0 0';
+                               if(!_Movetype_PushEntity(move2, true))
+                               {
+                                       // entity "check" got teleported
+                                       continue;
+                               }
+                               // we could fix it
+                               continue;
+                       }*/
+
+                       // still inside pusher, so it's really blocked
+
+                       // fail the move
+                       if(e.mins_x == e.maxs_x)
+                               continue;
+                       if(e.solid == SOLID_NOT || e.solid == SOLID_TRIGGER)
+                       {
+                               // corpse
+                               e.mins_x = e.mins_y = 0;
+                               e.maxs = e.mins;
+                               continue;
+                       }
+
+                       self.move_origin = pushorig;
+                       self.move_angles = pushang;
+                       self.ltime = pushltime;
+                       _Movetype_LinkEdict(true);
+
+                       // move back any entities we already moved
+                       /*for (i = 0;i < num_moved;i++)
+                       {
+                               prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
+                               VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
+                               VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
+                               SV_LinkEdict(ed);
+                       }*/
+
+                       // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
+                       if(self.blocked)
+                       {
+                               self.move_time = time;
+                               other = e;
+                               self.blocked();
+                       }
+                       break;
+               }
+       }
+       self.move_angles_x -= 360.0 * floor(self.move_angles_x * (1.0 / 360.0));
+       self.move_angles_y -= 360.0 * floor(self.move_angles_y * (1.0 / 360.0));
+       self.move_angles_z -= 360.0 * floor(self.move_angles_z * (1.0 / 360.0));
+}
+
+void _Movetype_Physics_Pusher(float dt) // SV_Physics_Pusher
+{
+       float oldltime, movetime;
+
+       oldltime = self.ltime;
+
+       if (self.nextthink < self.ltime + dt)
+       {
+               movetime = self.nextthink - self.ltime;
+               if (movetime < 0)
+                       movetime = 0;
+       }
+       else
+               movetime = dt;
+
+       if (movetime)
+               // advances PRVM_serveredictfloat(ent, ltime) if not blocked
+               _Movetype_PushMove(movetime);
+
+       if (self.nextthink > oldltime && self.nextthink <= self.ltime)
+       {
+               self.nextthink = 0;
+               //time = dt;
+               self.move_time = time;
+               other = world;
+               if(self.think)
+                       self.think();
+       }
+}
+
 void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
 {
        if(self.move_flags & FL_ONGROUND)
@@ -329,7 +630,7 @@ void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
                }
        }
 
-       self.move_suspendedinair = FALSE;
+       self.move_suspendedinair = false;
 
        _Movetype_CheckVelocity();
 
@@ -360,14 +661,14 @@ void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
        {
                vector move;
                move = self.move_velocity * movetime;
-               _Movetype_PushEntity(move, TRUE);
+               _Movetype_PushEntity(move, true);
                if(wasfreed(self))
                        return;
 
                if(trace_startsolid)
                {
                        _Movetype_UnstickEntity();
-                       _Movetype_PushEntity(move, FALSE);
+                       _Movetype_PushEntity(move, false);
                        if(wasfreed(self))
                                return;
                }
@@ -414,7 +715,7 @@ void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
                                self.move_flags |= FL_ONGROUND;
                                self.move_groundentity = trace_ent;
                                if(trace_ent.solid == SOLID_BSP)
-                                       self.move_suspendedinair = TRUE;
+                                       self.move_suspendedinair = true;
                                self.move_velocity = '0 0 0';
                                self.move_avelocity = '0 0 0';
                        }
@@ -451,7 +752,7 @@ void _Movetype_Physics_Frame(float movedt)
        {
                case MOVETYPE_PUSH:
                case MOVETYPE_FAKEPUSH:
-                       error("SV_Physics_Pusher not implemented");
+                       _Movetype_Physics_Pusher(movedt);
                        break;
                case MOVETYPE_NONE:
                        break;
@@ -462,7 +763,7 @@ void _Movetype_Physics_Frame(float movedt)
                        _Movetype_CheckWater(self);
                        self.move_origin = self.move_origin + ticrate * self.move_velocity;
                        self.move_angles = self.move_angles + ticrate * self.move_avelocity;
-                       _Movetype_LinkEdict(FALSE);
+                       _Movetype_LinkEdict(false);
                        break;
                case MOVETYPE_STEP:
                        error("SV_Physics_Step not implemented");
@@ -497,12 +798,12 @@ void Movetype_Physics_NoMatchServer() // optimized
        setorigin(self, self.move_origin);
 }
 
-void Movetype_Physics_MatchServer(float sloppy)
+void Movetype_Physics_MatchServer(bool sloppy)
 {
        Movetype_Physics_MatchTicrate(ticrate, sloppy);
 }
 
-void Movetype_Physics_MatchTicrate(float tr, float sloppy) // SV_Physics_Entity
+void Movetype_Physics_MatchTicrate(float tr, bool sloppy) // SV_Physics_Entity
 {
        float n, i, dt, movedt;