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