]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/physics/movetypes/push.qc
Some minor adjustments to the push movetype, fix QC physics entities not running...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / physics / movetypes / push.qc
1 #include "push.qh"
2 void _Movetype_PushMove(entity this, float dt) // SV_PushMove
3 {
4         if(this.velocity == '0 0 0' && this.avelocity == '0 0 0')
5         {
6                 this.ltime += dt;
7                 return;
8         }
9
10         switch(this.solid)
11         {
12                 // LadyHavoc: valid pusher types
13                 case SOLID_BSP:
14                 case SOLID_BBOX:
15                 case SOLID_SLIDEBOX:
16                 case SOLID_CORPSE: // LadyHavoc: this would be weird...
17                         break;
18                 // LadyHavoc: no collisions
19                 case SOLID_NOT:
20                 case SOLID_TRIGGER:
21                 {
22                         this.origin = this.origin + dt * this.velocity;
23                         this.angles = this.angles + dt * this.avelocity;
24                         this.angles_x -= 360.0 * floor(this.angles_x * (1.0 / 360.0));
25                         this.angles_y -= 360.0 * floor(this.angles_y * (1.0 / 360.0));
26                         this.angles_z -= 360.0 * floor(this.angles_z * (1.0 / 360.0));
27                         this.ltime += dt;
28                         _Movetype_LinkEdict(this, false);
29                         return;
30                 }
31                 default:
32                 {
33                         LOG_INFOF("_Movetype_Physics_Push: entity #%d, unrecognized solid type %d", etof(this), this.solid);
34                         return;
35                 }
36         }
37         if(!this.modelindex)
38         {
39                 LOG_INFOF("_Movetype_Physics_Push: entity #%d has an invalid modelindex %d", etof(this), this.modelindex);
40                 return;
41         }
42
43         bool rotated = ((vlen2(this.angles) + vlen2(this.avelocity)) > 0);
44
45         vector move1 = this.velocity * dt;
46         vector moveangle = this.avelocity * dt;
47
48         vector a = -moveangle;
49         vector forward, left, up;
50         MAKE_VECTORS(a, forward, left, up);
51         left *= -1; // actually make it left!
52
53         vector pushorig = this.origin;
54         vector pushang = this.angles;
55         float pushltime = this.ltime;
56
57         // move the pusher to its final position
58
59         this.origin = this.origin + dt * this.velocity;
60         this.angles = this.angles + dt * this.avelocity;
61         this.ltime += dt;
62         _Movetype_LinkEdict(this, false); // pulls absmin/absmax from the engine
63
64         if(this.move_movetype == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
65         {
66                 this.angles_x -= 360.0 * floor(this.angles_x * (1.0 / 360.0));
67                 this.angles_y -= 360.0 * floor(this.angles_y * (1.0 / 360.0));
68                 this.angles_z -= 360.0 * floor(this.angles_z * (1.0 / 360.0));
69                 return;
70         }
71
72         IL_CLEAR(g_pushmove_moved); // make sure it's not somehow uncleared
73
74         for(entity check = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); check; check = check.chain)
75         {
76                 switch(check.move_movetype)
77                 {
78                         case MOVETYPE_NONE:
79                         case MOVETYPE_PUSH:
80                         case MOVETYPE_FOLLOW:
81                         case MOVETYPE_NOCLIP:
82                         case MOVETYPE_FLY_WORLDONLY:
83                                 continue;
84                         default:
85                                 break;
86                 }
87
88                 if(check.owner == this || this.owner == check)
89                         continue;
90
91                 // if the entity is standing on the pusher, it will definitely be moved
92                 // if the entity is not standing on the pusher, but is in the pusher's
93                 // final position, move it
94                 if (!IS_ONGROUND(check) || check.groundentity != this)
95                 {
96                         tracebox(check.origin, check.mins, check.maxs, check.origin, MOVE_NORMAL, check);
97                         if(!trace_startsolid)
98                                 continue;
99                 }
100                 vector pivot = check.mins + 0.5 * check.maxs;
101                 vector move;
102
103                 if(rotated)
104                 {
105                         vector org = check.origin - this.origin;
106                         org = org + pivot;
107
108                         vector org2;
109                         org2.x = (org * forward);
110                         org2.y = (org * left);
111                         org2.z = (org * up);
112                         move = org2 - org;
113                         move = move + move1;
114                 }
115                 else
116                         move = move1;
117
118                 check.moved_from = check.origin;
119                 check.moved_fromangles = check.angles;
120                 IL_PUSH(g_pushmove_moved, check);
121
122                 // physics objects need better collisions than this code can do
123                 if(check.move_movetype == MOVETYPE_PHYSICS)
124                 {
125                         check.origin = check.origin + move;
126                         _Movetype_LinkEdict(check, true);
127                         continue;
128                 }
129
130                 // try moving the contacted entity
131                 int savesolid = this.solid;
132                 this.solid = SOLID_NOT;
133                 if(!_Movetype_PushEntity(check, move, true, true))
134                 {
135                         // entity "check" got teleported
136                         check.angles_y += trace_fraction * moveangle.y;
137                         this.solid = savesolid;
138                         continue; // pushed enough
139                 }
140                 // FIXME: turn players specially
141                 check.angles_y += trace_fraction * moveangle.y;
142                 this.solid = savesolid;
143
144                 // this trace.fraction < 1 check causes items to fall off of pushers
145                 // if they pass under or through a wall
146                 // the groundentity check causes items to fall off of ledges
147                 if(check.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || check.groundentity != this))
148                         UNSET_ONGROUND(check);
149
150                 // if it is still inside the pusher, block
151                 tracebox(check.origin, check.mins, check.maxs, check.origin, MOVE_HITMODEL, check);
152                 if(trace_startsolid)
153                 {
154                         if(_Movetype_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
155                         {
156                                 // hack to invoke all necessary movement triggers
157                                 vector move2 = '0 0 0';
158                                 if(!_Movetype_PushEntity(check, move2, true, true))
159                                 {
160                                         // entity "check" got teleported
161                                         continue;
162                                 }
163                                 // we could fix it
164                                 continue;
165                         }
166
167                         // still inside pusher, so it's really blocked
168
169                         // fail the move
170                         if(check.mins_x == check.maxs_x)
171                                 continue;
172                         if(check.solid == SOLID_NOT || check.solid == SOLID_TRIGGER)
173                         {
174                                 // corpse
175                                 check.mins_x = check.mins_y = 0;
176                                 check.maxs = check.mins;
177                                 continue;
178                         }
179
180                         this.origin = pushorig;
181                         this.angles = pushang;
182                         this.ltime = pushltime;
183                         _Movetype_LinkEdict(this, false);
184
185                         // move back any entities we already moved
186                         IL_EACH(g_pushmove_moved, true,
187                         {
188                                 check.origin = check.moved_from;
189                                 check.angles = check.moved_fromangles;
190                                 _Movetype_LinkEdict(check, false);
191                         });
192
193                         // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
194                         if(getblocked(this))
195                                 getblocked(this)(this, check);
196                         break;
197                 }
198         }
199         this.angles_x -= 360.0 * floor(this.angles_x * (1.0 / 360.0));
200         this.angles_y -= 360.0 * floor(this.angles_y * (1.0 / 360.0));
201         this.angles_z -= 360.0 * floor(this.angles_z * (1.0 / 360.0));
202         IL_CLEAR(g_pushmove_moved); // clean up
203 }
204
205 void _Movetype_Physics_Push(entity this, float dt) // SV_Physics_Pusher
206 {
207         float oldltime = this.ltime;
208         float movetime = dt;
209         if(this.nextthink < this.ltime + dt)
210         {
211                 movetime = this.nextthink - this.ltime;
212                 if(movetime < 0)
213                         movetime = 0;
214         }
215
216         if(movetime)
217         {
218                 // advances this.ltime if not blocked
219                 _Movetype_PushMove(this, movetime);
220         }
221
222         if(this.nextthink > oldltime && this.nextthink <= this.ltime)
223         {
224                 this.nextthink = 0;
225                 getthink(this)(this);
226         }
227 }