|
|
1.1 root 1: // m_move.c -- monster movement
2:
3: #include "g_local.h"
4:
5: #define STEPSIZE 18
6:
7: /*
8: =============
9: M_CheckBottom
10:
11: Returns false if any part of the bottom of the entity is off an edge that
12: is not a staircase.
13:
14: =============
15: */
16: int c_yes, c_no;
17:
18: qboolean M_CheckBottom (edict_t *ent)
19: {
20: vec3_t mins, maxs, start, stop;
21: trace_t trace;
22: int x, y;
23: float mid, bottom;
24:
25: VectorAdd (ent->s.origin, ent->mins, mins);
26: VectorAdd (ent->s.origin, ent->maxs, maxs);
27:
28: // if all of the points under the corners are solid world, don't bother
29: // with the tougher checks
30: // the corners must be within 16 of the midpoint
31: start[2] = mins[2] - 1;
32: for (x=0 ; x<=1 ; x++)
33: for (y=0 ; y<=1 ; y++)
34: {
35: start[0] = x ? maxs[0] : mins[0];
36: start[1] = y ? maxs[1] : mins[1];
37: if (gi.pointcontents (start) != CONTENTS_SOLID)
38: goto realcheck;
39: }
40:
41: c_yes++;
42: return true; // we got out easy
43:
44: realcheck:
45: c_no++;
46: //
47: // check it for real...
48: //
49: start[2] = mins[2];
50:
51: // the midpoint must be within 16 of the bottom
52: start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
53: start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
54: stop[2] = start[2] - 2*STEPSIZE;
55: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
56:
57: if (trace.fraction == 1.0)
58: return false;
59: mid = bottom = trace.endpos[2];
60:
61: // the corners must be within 16 of the midpoint
62: for (x=0 ; x<=1 ; x++)
63: for (y=0 ; y<=1 ; y++)
64: {
65: start[0] = stop[0] = x ? maxs[0] : mins[0];
66: start[1] = stop[1] = y ? maxs[1] : mins[1];
67:
68: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
69:
70: if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
71: bottom = trace.endpos[2];
72: if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
73: return false;
74: }
75:
76: c_yes++;
77: return true;
78: }
79:
80:
81: /*
82: =============
83: SV_movestep
84:
85: Called by monster program code.
86: The move will be adjusted for slopes and stairs, but if the move isn't
87: possible, no move is done, false is returned, and
88: pr_global_struct->trace_normal is set to the normal of the blocking wall
89: =============
90: */
91: //FIXME since we need to test end position contents here, can we avoid doing
92: //it again later in catagorize position?
93: qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
94: {
95: float dz;
96: vec3_t oldorg, neworg, end;
97: trace_t trace;
98: int i;
99: float stepsize;
100: vec3_t test;
101: int contents;
102:
103: // try the move
104: VectorCopy (ent->s.origin, oldorg);
105: VectorAdd (ent->s.origin, move, neworg);
106:
107: // flying monsters don't step up
108: if ( ent->flags & (FL_SWIM | FL_FLY) )
109: {
110: // try one move with vertical motion, then one without
111: for (i=0 ; i<2 ; i++)
112: {
113: VectorAdd (ent->s.origin, move, neworg);
114: if (i == 0 && ent->enemy)
115: {
116: if (!ent->goalentity)
117: ent->goalentity = ent->enemy;
118: dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
119: if (ent->goalentity->client)
120: {
121: if (dz > 40)
122: neworg[2] -= 8;
123: if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
124: if (dz < 30)
125: neworg[2] += 8;
126: }
127: else
128: {
129: if (dz > 8)
130: neworg[2] -= 8;
131: else if (dz > 0)
132: neworg[2] -= dz;
133: else if (dz < -8)
134: neworg[2] += 8;
135: else
136: neworg[2] += dz;
137: }
138: }
139: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
140:
141: // fly monsters don't enter water voluntarily
142: if (ent->flags & FL_FLY)
143: {
144: if (!ent->waterlevel)
145: {
146: test[0] = trace.endpos[0];
147: test[1] = trace.endpos[1];
148: test[2] = trace.endpos[2] + ent->mins[2] + 1;
149: contents = gi.pointcontents(test);
150: if (contents & MASK_WATER)
151: return false;
152: }
153: }
154:
155: // swim monsters don't exit water voluntarily
156: if (ent->flags & FL_SWIM)
157: {
158: if (ent->waterlevel < 2)
159: {
160: test[0] = trace.endpos[0];
161: test[1] = trace.endpos[1];
162: test[2] = trace.endpos[2] + ent->mins[2] + 1;
163: contents = gi.pointcontents(test);
164: if (!(contents & MASK_WATER))
165: return false;
166: }
167: }
168:
169: if (trace.fraction == 1)
170: {
171: VectorCopy (trace.endpos, ent->s.origin);
172: if (relink)
173: {
174: gi.linkentity (ent);
175: G_TouchTriggers (ent);
176: }
177: return true;
178: }
179:
180: if (!ent->enemy)
181: break;
182: }
183:
184: return false;
185: }
186:
187: // push down from a step height above the wished position
188: if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
189: stepsize = STEPSIZE;
190: else
191: stepsize = 1;
192:
193: neworg[2] += stepsize;
194: VectorCopy (neworg, end);
195: end[2] -= stepsize*2;
196:
197: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
198:
199: if (trace.allsolid)
200: return false;
201:
202: if (trace.startsolid)
203: {
204: neworg[2] -= stepsize;
205: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
206: if (trace.allsolid || trace.startsolid)
207: return false;
208: }
209:
210:
211: // don't go in to water
212: if (ent->waterlevel == 0)
213: {
214: test[0] = trace.endpos[0];
215: test[1] = trace.endpos[1];
216: test[2] = trace.endpos[2] + ent->mins[2] + 1;
217: contents = gi.pointcontents(test);
218:
219: if (contents & MASK_WATER)
220: return false;
221: }
222:
223: if (trace.fraction == 1)
224: {
225: // if monster had the ground pulled out, go ahead and fall
226: if ( ent->flags & FL_PARTIALGROUND )
227: {
228: VectorAdd (ent->s.origin, move, ent->s.origin);
229: if (relink)
230: {
231: gi.linkentity (ent);
232: G_TouchTriggers (ent);
233: }
234: ent->groundentity = NULL;
235: return true;
236: }
237:
238: return false; // walked off an edge
239: }
240:
241: // check point traces down for dangling corners
242: VectorCopy (trace.endpos, ent->s.origin);
243:
244: if (!M_CheckBottom (ent))
245: {
246: if ( ent->flags & FL_PARTIALGROUND )
247: { // entity had floor mostly pulled out from underneath it
248: // and is trying to correct
249: if (relink)
250: {
251: gi.linkentity (ent);
252: G_TouchTriggers (ent);
253: }
254: return true;
255: }
256: VectorCopy (oldorg, ent->s.origin);
257: return false;
258: }
259:
260: if ( ent->flags & FL_PARTIALGROUND )
261: {
262: ent->flags &= ~FL_PARTIALGROUND;
263: }
264: ent->groundentity = trace.ent;
265: ent->groundentity_linkcount = trace.ent->linkcount;
266:
267: // the move is ok
268: if (relink)
269: {
270: gi.linkentity (ent);
271: G_TouchTriggers (ent);
272: }
273: return true;
274: }
275:
276:
277: //============================================================================
278:
279: /*
280: ===============
281: M_ChangeYaw
282:
283: ===============
284: */
285: void M_ChangeYaw (edict_t *ent)
286: {
287: float ideal;
288: float current;
289: float move;
290: float speed;
291:
292: current = anglemod(ent->s.angles[YAW]);
293: ideal = ent->ideal_yaw;
294:
295: if (current == ideal)
296: return;
297:
298: move = ideal - current;
299: speed = ent->yaw_speed;
300: if (ideal > current)
301: {
302: if (move >= 180)
303: move = move - 360;
304: }
305: else
306: {
307: if (move <= -180)
308: move = move + 360;
309: }
310: if (move > 0)
311: {
312: if (move > speed)
313: move = speed;
314: }
315: else
316: {
317: if (move < -speed)
318: move = -speed;
319: }
320:
321: ent->s.angles[YAW] = anglemod (current + move);
322: }
323:
324:
325: /*
326: ======================
327: SV_StepDirection
328:
329: Turns to the movement direction, and walks the current distance if
330: facing it.
331:
332: ======================
333: */
334: qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
335: {
336: vec3_t move, oldorigin;
337: float delta;
338:
339: ent->ideal_yaw = yaw;
340: M_ChangeYaw (ent);
341:
342: yaw = yaw*M_PI*2 / 360;
343: move[0] = cos(yaw)*dist;
344: move[1] = sin(yaw)*dist;
345: move[2] = 0;
346:
347: VectorCopy (ent->s.origin, oldorigin);
348: if (SV_movestep (ent, move, false))
349: {
350: delta = ent->s.angles[YAW] - ent->ideal_yaw;
351: if (delta > 45 && delta < 315)
352: { // not turned far enough, so don't take the step
353: VectorCopy (oldorigin, ent->s.origin);
354: }
355: gi.linkentity (ent);
356: G_TouchTriggers (ent);
357: return true;
358: }
359: gi.linkentity (ent);
360: G_TouchTriggers (ent);
361: return false;
362: }
363:
364: /*
365: ======================
366: SV_FixCheckBottom
367:
368: ======================
369: */
370: void SV_FixCheckBottom (edict_t *ent)
371: {
372: ent->flags |= FL_PARTIALGROUND;
373: }
374:
375:
376:
377: /*
378: ================
379: SV_NewChaseDir
380:
381: ================
382: */
383: #define DI_NODIR -1
384: void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
385: {
386: float deltax,deltay;
387: float d[3];
388: float tdir, olddir, turnaround;
389:
390: //FIXME: how did we get here with no enemy
391: if (!enemy)
392: return;
393:
394: olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
395: turnaround = anglemod(olddir - 180);
396:
397: deltax = enemy->s.origin[0] - actor->s.origin[0];
398: deltay = enemy->s.origin[1] - actor->s.origin[1];
399: if (deltax>10)
400: d[1]= 0;
401: else if (deltax<-10)
402: d[1]= 180;
403: else
404: d[1]= DI_NODIR;
405: if (deltay<-10)
406: d[2]= 270;
407: else if (deltay>10)
408: d[2]= 90;
409: else
410: d[2]= DI_NODIR;
411:
412: // try direct route
413: if (d[1] != DI_NODIR && d[2] != DI_NODIR)
414: {
415: if (d[1] == 0)
416: tdir = d[2] == 90 ? 45 : 315;
417: else
418: tdir = d[2] == 90 ? 135 : 215;
419:
420: if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
421: return;
422: }
423:
424: // try other directions
425: if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
426: {
427: tdir=d[1];
428: d[1]=d[2];
429: d[2]=tdir;
430: }
431:
432: if (d[1]!=DI_NODIR && d[1]!=turnaround
433: && SV_StepDirection(actor, d[1], dist))
434: return;
435:
436: if (d[2]!=DI_NODIR && d[2]!=turnaround
437: && SV_StepDirection(actor, d[2], dist))
438: return;
439:
440: /* there is no direct path to the player, so pick another direction */
441:
442: if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
443: return;
444:
445: if (rand()&1) /*randomly determine direction of search*/
446: {
447: for (tdir=0 ; tdir<=315 ; tdir += 45)
448: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
449: return;
450: }
451: else
452: {
453: for (tdir=315 ; tdir >=0 ; tdir -= 45)
454: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
455: return;
456: }
457:
458: if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
459: return;
460:
461: actor->ideal_yaw = olddir; // can't move
462:
463: // if a bridge was pulled out from underneath a monster, it may not have
464: // a valid standing position at all
465:
466: if (!M_CheckBottom (actor))
467: SV_FixCheckBottom (actor);
468: }
469:
470: /*
471: ======================
472: SV_CloseEnough
473:
474: ======================
475: */
476: qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
477: {
478: int i;
479:
480: for (i=0 ; i<3 ; i++)
481: {
482: if (goal->absmin[i] > ent->absmax[i] + dist)
483: return false;
484: if (goal->absmax[i] < ent->absmin[i] - dist)
485: return false;
486: }
487: return true;
488: }
489:
490:
491: /*
492: ======================
493: M_MoveToGoal
494: ======================
495: */
496: void M_MoveToGoal (edict_t *ent, float dist)
497: {
498: edict_t *goal;
499:
500: goal = ent->goalentity;
501:
502: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
503: return;
504:
505: // if the next step hits the enemy, return immediately
506: if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) )
507: return;
508:
509: // bump around...
510: if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
511: {
512: if (ent->inuse)
513: SV_NewChaseDir (ent, goal, dist);
514: }
515: }
516:
517:
518: /*
519: ===============
520: M_walkmove
521: ===============
522: */
523: qboolean M_walkmove (edict_t *ent, float yaw, float dist)
524: {
525: vec3_t move;
526:
527: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
528: return false;
529:
530: yaw = yaw*M_PI*2 / 360;
531:
532: move[0] = cos(yaw)*dist;
533: move[1] = sin(yaw)*dist;
534: move[2] = 0;
535:
536: return SV_movestep(ent, move, true);
537: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.