diff options
Diffstat (limited to 'apps/plugins/sdl/progs/quake/sv_move.c')
-rw-r--r-- | apps/plugins/sdl/progs/quake/sv_move.c | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/sv_move.c b/apps/plugins/sdl/progs/quake/sv_move.c new file mode 100644 index 0000000000..a0078b941a --- /dev/null +++ b/apps/plugins/sdl/progs/quake/sv_move.c | |||
@@ -0,0 +1,427 @@ | |||
1 | /* | ||
2 | Copyright (C) 1996-1997 Id Software, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License | ||
6 | as published by the Free Software Foundation; either version 2 | ||
7 | of the License, or (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
12 | |||
13 | See the GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | |||
19 | */ | ||
20 | // sv_move.c -- monster movement | ||
21 | |||
22 | #include "quakedef.h" | ||
23 | |||
24 | #define STEPSIZE 18 | ||
25 | |||
26 | /* | ||
27 | ============= | ||
28 | SV_CheckBottom | ||
29 | |||
30 | Returns false if any part of the bottom of the entity is off an edge that | ||
31 | is not a staircase. | ||
32 | |||
33 | ============= | ||
34 | */ | ||
35 | int c_yes, c_no; | ||
36 | |||
37 | qboolean SV_CheckBottom (edict_t *ent) | ||
38 | { | ||
39 | vec3_t mins, maxs, start, stop; | ||
40 | trace_t trace; | ||
41 | int x, y; | ||
42 | float mid, bottom; | ||
43 | |||
44 | VectorAdd (ent->v.origin, ent->v.mins, mins); | ||
45 | VectorAdd (ent->v.origin, ent->v.maxs, maxs); | ||
46 | |||
47 | // if all of the points under the corners are solid world, don't bother | ||
48 | // with the tougher checks | ||
49 | // the corners must be within 16 of the midpoint | ||
50 | start[2] = mins[2] - 1; | ||
51 | for (x=0 ; x<=1 ; x++) | ||
52 | for (y=0 ; y<=1 ; y++) | ||
53 | { | ||
54 | start[0] = x ? maxs[0] : mins[0]; | ||
55 | start[1] = y ? maxs[1] : mins[1]; | ||
56 | if (SV_PointContents (start) != CONTENTS_SOLID) | ||
57 | goto realcheck; | ||
58 | } | ||
59 | |||
60 | c_yes++; | ||
61 | return true; // we got out easy | ||
62 | |||
63 | realcheck: | ||
64 | c_no++; | ||
65 | // | ||
66 | // check it for real... | ||
67 | // | ||
68 | start[2] = mins[2]; | ||
69 | |||
70 | // the midpoint must be within 16 of the bottom | ||
71 | start[0] = stop[0] = (mins[0] + maxs[0])*0.5; | ||
72 | start[1] = stop[1] = (mins[1] + maxs[1])*0.5; | ||
73 | stop[2] = start[2] - 2*STEPSIZE; | ||
74 | trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); | ||
75 | |||
76 | if (trace.fraction == 1.0) | ||
77 | return false; | ||
78 | mid = bottom = trace.endpos[2]; | ||
79 | |||
80 | // the corners must be within 16 of the midpoint | ||
81 | for (x=0 ; x<=1 ; x++) | ||
82 | for (y=0 ; y<=1 ; y++) | ||
83 | { | ||
84 | start[0] = stop[0] = x ? maxs[0] : mins[0]; | ||
85 | start[1] = stop[1] = y ? maxs[1] : mins[1]; | ||
86 | |||
87 | trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); | ||
88 | |||
89 | if (trace.fraction != 1.0 && trace.endpos[2] > bottom) | ||
90 | bottom = trace.endpos[2]; | ||
91 | if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) | ||
92 | return false; | ||
93 | } | ||
94 | |||
95 | c_yes++; | ||
96 | return true; | ||
97 | } | ||
98 | |||
99 | |||
100 | /* | ||
101 | ============= | ||
102 | SV_movestep | ||
103 | |||
104 | Called by monster program code. | ||
105 | The move will be adjusted for slopes and stairs, but if the move isn't | ||
106 | possible, no move is done, false is returned, and | ||
107 | pr_global_struct->trace_normal is set to the normal of the blocking wall | ||
108 | ============= | ||
109 | */ | ||
110 | qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) | ||
111 | { | ||
112 | float dz; | ||
113 | vec3_t oldorg, neworg, end; | ||
114 | trace_t trace; | ||
115 | int i; | ||
116 | edict_t *enemy; | ||
117 | |||
118 | // try the move | ||
119 | VectorCopy (ent->v.origin, oldorg); | ||
120 | VectorAdd (ent->v.origin, move, neworg); | ||
121 | |||
122 | // flying monsters don't step up | ||
123 | if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) ) | ||
124 | { | ||
125 | // try one move with vertical motion, then one without | ||
126 | for (i=0 ; i<2 ; i++) | ||
127 | { | ||
128 | VectorAdd (ent->v.origin, move, neworg); | ||
129 | enemy = PROG_TO_EDICT(ent->v.enemy); | ||
130 | if (i == 0 && enemy != sv.edicts) | ||
131 | { | ||
132 | dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2]; | ||
133 | if (dz > 40) | ||
134 | neworg[2] -= 8; | ||
135 | if (dz < 30) | ||
136 | neworg[2] += 8; | ||
137 | } | ||
138 | trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent); | ||
139 | |||
140 | if (trace.fraction == 1) | ||
141 | { | ||
142 | if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) | ||
143 | return false; // swim monster left water | ||
144 | |||
145 | VectorCopy (trace.endpos, ent->v.origin); | ||
146 | if (relink) | ||
147 | SV_LinkEdict (ent, true); | ||
148 | return true; | ||
149 | } | ||
150 | |||
151 | if (enemy == sv.edicts) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | return false; | ||
156 | } | ||
157 | |||
158 | // push down from a step height above the wished position | ||
159 | neworg[2] += STEPSIZE; | ||
160 | VectorCopy (neworg, end); | ||
161 | end[2] -= STEPSIZE*2; | ||
162 | |||
163 | trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); | ||
164 | |||
165 | if (trace.allsolid) | ||
166 | return false; | ||
167 | |||
168 | if (trace.startsolid) | ||
169 | { | ||
170 | neworg[2] -= STEPSIZE; | ||
171 | trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); | ||
172 | if (trace.allsolid || trace.startsolid) | ||
173 | return false; | ||
174 | } | ||
175 | if (trace.fraction == 1) | ||
176 | { | ||
177 | // if monster had the ground pulled out, go ahead and fall | ||
178 | if ( (int)ent->v.flags & FL_PARTIALGROUND ) | ||
179 | { | ||
180 | VectorAdd (ent->v.origin, move, ent->v.origin); | ||
181 | if (relink) | ||
182 | SV_LinkEdict (ent, true); | ||
183 | ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; | ||
184 | // Con_Printf ("fall down\n"); | ||
185 | return true; | ||
186 | } | ||
187 | |||
188 | return false; // walked off an edge | ||
189 | } | ||
190 | |||
191 | // check point traces down for dangling corners | ||
192 | VectorCopy (trace.endpos, ent->v.origin); | ||
193 | |||
194 | if (!SV_CheckBottom (ent)) | ||
195 | { | ||
196 | if ( (int)ent->v.flags & FL_PARTIALGROUND ) | ||
197 | { // entity had floor mostly pulled out from underneath it | ||
198 | // and is trying to correct | ||
199 | if (relink) | ||
200 | SV_LinkEdict (ent, true); | ||
201 | return true; | ||
202 | } | ||
203 | VectorCopy (oldorg, ent->v.origin); | ||
204 | return false; | ||
205 | } | ||
206 | |||
207 | if ( (int)ent->v.flags & FL_PARTIALGROUND ) | ||
208 | { | ||
209 | // Con_Printf ("back on ground\n"); | ||
210 | ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND; | ||
211 | } | ||
212 | ent->v.groundentity = EDICT_TO_PROG(trace.ent); | ||
213 | |||
214 | // the move is ok | ||
215 | if (relink) | ||
216 | SV_LinkEdict (ent, true); | ||
217 | return true; | ||
218 | } | ||
219 | |||
220 | |||
221 | //============================================================================ | ||
222 | |||
223 | /* | ||
224 | ====================== | ||
225 | SV_StepDirection | ||
226 | |||
227 | Turns to the movement direction, and walks the current distance if | ||
228 | facing it. | ||
229 | |||
230 | ====================== | ||
231 | */ | ||
232 | void PF_changeyaw (void); | ||
233 | qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) | ||
234 | { | ||
235 | vec3_t move, oldorigin; | ||
236 | float delta; | ||
237 | |||
238 | ent->v.ideal_yaw = yaw; | ||
239 | PF_changeyaw(); | ||
240 | |||
241 | yaw = yaw*M_PI*2 / 360; | ||
242 | move[0] = cos(yaw)*dist; | ||
243 | move[1] = sin(yaw)*dist; | ||
244 | move[2] = 0; | ||
245 | |||
246 | VectorCopy (ent->v.origin, oldorigin); | ||
247 | if (SV_movestep (ent, move, false)) | ||
248 | { | ||
249 | delta = ent->v.angles[YAW] - ent->v.ideal_yaw; | ||
250 | if (delta > 45 && delta < 315) | ||
251 | { // not turned far enough, so don't take the step | ||
252 | VectorCopy (oldorigin, ent->v.origin); | ||
253 | } | ||
254 | SV_LinkEdict (ent, true); | ||
255 | return true; | ||
256 | } | ||
257 | SV_LinkEdict (ent, true); | ||
258 | |||
259 | return false; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | ====================== | ||
264 | SV_FixCheckBottom | ||
265 | |||
266 | ====================== | ||
267 | */ | ||
268 | void SV_FixCheckBottom (edict_t *ent) | ||
269 | { | ||
270 | // Con_Printf ("SV_FixCheckBottom\n"); | ||
271 | |||
272 | ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND; | ||
273 | } | ||
274 | |||
275 | |||
276 | |||
277 | /* | ||
278 | ================ | ||
279 | SV_NewChaseDir | ||
280 | |||
281 | ================ | ||
282 | */ | ||
283 | #define DI_NODIR -1 | ||
284 | void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) | ||
285 | { | ||
286 | float deltax,deltay; | ||
287 | float d[3]; | ||
288 | float tdir, olddir, turnaround; | ||
289 | |||
290 | olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 ); | ||
291 | turnaround = anglemod(olddir - 180); | ||
292 | |||
293 | deltax = enemy->v.origin[0] - actor->v.origin[0]; | ||
294 | deltay = enemy->v.origin[1] - actor->v.origin[1]; | ||
295 | if (deltax>10) | ||
296 | d[1]= 0; | ||
297 | else if (deltax<-10) | ||
298 | d[1]= 180; | ||
299 | else | ||
300 | d[1]= DI_NODIR; | ||
301 | if (deltay<-10) | ||
302 | d[2]= 270; | ||
303 | else if (deltay>10) | ||
304 | d[2]= 90; | ||
305 | else | ||
306 | d[2]= DI_NODIR; | ||
307 | |||
308 | // try direct route | ||
309 | if (d[1] != DI_NODIR && d[2] != DI_NODIR) | ||
310 | { | ||
311 | if (d[1] == 0) | ||
312 | tdir = d[2] == 90 ? 45 : 315; | ||
313 | else | ||
314 | tdir = d[2] == 90 ? 135 : 215; | ||
315 | |||
316 | if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | // try other directions | ||
321 | if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax)) | ||
322 | { | ||
323 | tdir=d[1]; | ||
324 | d[1]=d[2]; | ||
325 | d[2]=tdir; | ||
326 | } | ||
327 | |||
328 | if (d[1]!=DI_NODIR && d[1]!=turnaround | ||
329 | && SV_StepDirection(actor, d[1], dist)) | ||
330 | return; | ||
331 | |||
332 | if (d[2]!=DI_NODIR && d[2]!=turnaround | ||
333 | && SV_StepDirection(actor, d[2], dist)) | ||
334 | return; | ||
335 | |||
336 | /* there is no direct path to the player, so pick another direction */ | ||
337 | |||
338 | if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) | ||
339 | return; | ||
340 | |||
341 | if (rand()&1) /*randomly determine direction of search*/ | ||
342 | { | ||
343 | for (tdir=0 ; tdir<=315 ; tdir += 45) | ||
344 | if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) | ||
345 | return; | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | for (tdir=315 ; tdir >=0 ; tdir -= 45) | ||
350 | if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) | ||
351 | return; | ||
352 | } | ||
353 | |||
354 | if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) | ||
355 | return; | ||
356 | |||
357 | actor->v.ideal_yaw = olddir; // can't move | ||
358 | |||
359 | // if a bridge was pulled out from underneath a monster, it may not have | ||
360 | // a valid standing position at all | ||
361 | |||
362 | if (!SV_CheckBottom (actor)) | ||
363 | SV_FixCheckBottom (actor); | ||
364 | |||
365 | } | ||
366 | |||
367 | /* | ||
368 | ====================== | ||
369 | SV_CloseEnough | ||
370 | |||
371 | ====================== | ||
372 | */ | ||
373 | qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) | ||
374 | { | ||
375 | int i; | ||
376 | |||
377 | for (i=0 ; i<3 ; i++) | ||
378 | { | ||
379 | if (goal->v.absmin[i] > ent->v.absmax[i] + dist) | ||
380 | return false; | ||
381 | if (goal->v.absmax[i] < ent->v.absmin[i] - dist) | ||
382 | return false; | ||
383 | } | ||
384 | return true; | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | ====================== | ||
389 | SV_MoveToGoal | ||
390 | |||
391 | ====================== | ||
392 | */ | ||
393 | void SV_MoveToGoal (void) | ||
394 | { | ||
395 | edict_t *ent, *goal; | ||
396 | float dist; | ||
397 | #ifdef QUAKE2 | ||
398 | edict_t *enemy; | ||
399 | #endif | ||
400 | |||
401 | ent = PROG_TO_EDICT(pr_global_struct->self); | ||
402 | goal = PROG_TO_EDICT(ent->v.goalentity); | ||
403 | dist = G_FLOAT(OFS_PARM0); | ||
404 | |||
405 | if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) | ||
406 | { | ||
407 | G_FLOAT(OFS_RETURN) = 0; | ||
408 | return; | ||
409 | } | ||
410 | |||
411 | // if the next step hits the enemy, return immediately | ||
412 | #ifdef QUAKE2 | ||
413 | enemy = PROG_TO_EDICT(ent->v.enemy); | ||
414 | if (enemy != sv.edicts && SV_CloseEnough (ent, enemy, dist) ) | ||
415 | #else | ||
416 | if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) ) | ||
417 | #endif | ||
418 | return; | ||
419 | |||
420 | // bump around... | ||
421 | if ( (rand()&3)==1 || | ||
422 | !SV_StepDirection (ent, ent->v.ideal_yaw, dist)) | ||
423 | { | ||
424 | SV_NewChaseDir (ent, goal, dist); | ||
425 | } | ||
426 | } | ||
427 | |||