Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 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 | }>3>=315>-10) |
||
427 |