|
|
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: // RAFAEL
130: if (strcmp (ent->classname , "monster_fixbot") == 0)
131: {
132: if (ent->s.frame >= 105 && ent->s.frame <= 120)
133: {
134: if (dz > 12)
135: neworg[2] --;
136: else if (dz < -12)
137: neworg[2] ++;
138: }
139: else if (ent->s.frame >= 31 && ent->s.frame <= 88)
140: {
141: if (dz > 12)
142: neworg[2] -= 12;
143: else if (dz < -12)
144: neworg[2] += 12;
145: }
146: else
147: {
148: if (dz > 12)
149: neworg[2] -= 8;
150: else if (dz < -12)
151: neworg[2] += 8;
152: }
153: }
154: // RAFAEL ( else )
155: else
156: {
157: if (dz > 8)
158: neworg[2] -= 8;
159: else if (dz > 0)
160: neworg[2] -= dz;
161: else if (dz < -8)
162: neworg[2] += 8;
163: else
164: neworg[2] += dz;
165: }
166: }
167: }
168: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
169:
170: // fly monsters don't enter water voluntarily
171: if (ent->flags & FL_FLY)
172: {
173: if (!ent->waterlevel)
174: {
175: test[0] = trace.endpos[0];
176: test[1] = trace.endpos[1];
177: test[2] = trace.endpos[2] + ent->mins[2] + 1;
178: contents = gi.pointcontents(test);
179: if (contents & MASK_WATER)
180: return false;
181: }
182: }
183:
184: // swim monsters don't exit water voluntarily
185: if (ent->flags & FL_SWIM)
186: {
187: if (ent->waterlevel < 2)
188: {
189: test[0] = trace.endpos[0];
190: test[1] = trace.endpos[1];
191: test[2] = trace.endpos[2] + ent->mins[2] + 1;
192: contents = gi.pointcontents(test);
193: if (!(contents & MASK_WATER))
194: return false;
195: }
196: }
197:
198: if (trace.fraction == 1)
199: {
200: VectorCopy (trace.endpos, ent->s.origin);
201: if (relink)
202: {
203: gi.linkentity (ent);
204: G_TouchTriggers (ent);
205: }
206: return true;
207: }
208:
209: if (!ent->enemy)
210: break;
211: }
212:
213: return false;
214: }
215:
216: // push down from a step height above the wished position
217: if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
218: stepsize = STEPSIZE;
219: else
220: stepsize = 1;
221:
222: neworg[2] += stepsize;
223: VectorCopy (neworg, end);
224: end[2] -= stepsize*2;
225:
226: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
227:
228: if (trace.allsolid)
229: return false;
230:
231: if (trace.startsolid)
232: {
233: neworg[2] -= stepsize;
234: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
235: if (trace.allsolid || trace.startsolid)
236: return false;
237: }
238:
239:
240: // don't go in to water
241: if (ent->waterlevel == 0)
242: {
243: test[0] = trace.endpos[0];
244: test[1] = trace.endpos[1];
245: test[2] = trace.endpos[2] + ent->mins[2] + 1;
246: contents = gi.pointcontents(test);
247:
248: if (contents & MASK_WATER)
249: return false;
250: }
251:
252: if (trace.fraction == 1)
253: {
254: // if monster had the ground pulled out, go ahead and fall
255: if ( ent->flags & FL_PARTIALGROUND )
256: {
257: VectorAdd (ent->s.origin, move, ent->s.origin);
258: if (relink)
259: {
260: gi.linkentity (ent);
261: G_TouchTriggers (ent);
262: }
263: ent->groundentity = NULL;
264: return true;
265: }
266:
267: return false; // walked off an edge
268: }
269:
270: // check point traces down for dangling corners
271: VectorCopy (trace.endpos, ent->s.origin);
272:
273: if (!M_CheckBottom (ent))
274: {
275: if ( ent->flags & FL_PARTIALGROUND )
276: { // entity had floor mostly pulled out from underneath it
277: // and is trying to correct
278: if (relink)
279: {
280: gi.linkentity (ent);
281: G_TouchTriggers (ent);
282: }
283: return true;
284: }
285: VectorCopy (oldorg, ent->s.origin);
286: return false;
287: }
288:
289: if ( ent->flags & FL_PARTIALGROUND )
290: {
291: ent->flags &= ~FL_PARTIALGROUND;
292: }
293: ent->groundentity = trace.ent;
294: ent->groundentity_linkcount = trace.ent->linkcount;
295:
296: // the move is ok
297: if (relink)
298: {
299: gi.linkentity (ent);
300: G_TouchTriggers (ent);
301: }
302: return true;
303: }
304:
305:
306: //============================================================================
307:
308: /*
309: ===============
310: M_ChangeYaw
311:
312: ===============
313: */
314: void M_ChangeYaw (edict_t *ent)
315: {
316: float ideal;
317: float current;
318: float move;
319: float speed;
320:
321: current = anglemod(ent->s.angles[YAW]);
322: ideal = ent->ideal_yaw;
323:
324: if (current == ideal)
325: return;
326:
327: move = ideal - current;
328: speed = ent->yaw_speed;
329: if (ideal > current)
330: {
331: if (move >= 180)
332: move = move - 360;
333: }
334: else
335: {
336: if (move <= -180)
337: move = move + 360;
338: }
339: if (move > 0)
340: {
341: if (move > speed)
342: move = speed;
343: }
344: else
345: {
346: if (move < -speed)
347: move = -speed;
348: }
349:
350: ent->s.angles[YAW] = anglemod (current + move);
351: }
352:
353:
354: /*
355: ======================
356: SV_StepDirection
357:
358: Turns to the movement direction, and walks the current distance if
359: facing it.
360:
361: ======================
362: */
363: qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
364: {
365: vec3_t move, oldorigin;
366: float delta;
367:
368: ent->ideal_yaw = yaw;
369: M_ChangeYaw (ent);
370:
371: yaw = yaw*M_PI*2 / 360;
372: move[0] = cos(yaw)*dist;
373: move[1] = sin(yaw)*dist;
374: move[2] = 0;
375:
376: VectorCopy (ent->s.origin, oldorigin);
377: if (SV_movestep (ent, move, false))
378: {
379: delta = ent->s.angles[YAW] - ent->ideal_yaw;
380: if (delta > 45 && delta < 315)
381: { // not turned far enough, so don't take the step
382: VectorCopy (oldorigin, ent->s.origin);
383: }
384: gi.linkentity (ent);
385: G_TouchTriggers (ent);
386: return true;
387: }
388: gi.linkentity (ent);
389: G_TouchTriggers (ent);
390: return false;
391: }
392:
393: /*
394: ======================
395: SV_FixCheckBottom
396:
397: ======================
398: */
399: void SV_FixCheckBottom (edict_t *ent)
400: {
401: ent->flags |= FL_PARTIALGROUND;
402: }
403:
404:
405:
406: /*
407: ================
408: SV_NewChaseDir
409:
410: ================
411: */
412: #define DI_NODIR -1
413: void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
414: {
415: float deltax,deltay;
416: float d[3];
417: float tdir, olddir, turnaround;
418:
419: //FIXME: how did we get here with no enemy
420: if (!enemy)
421: return;
422:
423: olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
424: turnaround = anglemod(olddir - 180);
425:
426: deltax = enemy->s.origin[0] - actor->s.origin[0];
427: deltay = enemy->s.origin[1] - actor->s.origin[1];
428: if (deltax>10)
429: d[1]= 0;
430: else if (deltax<-10)
431: d[1]= 180;
432: else
433: d[1]= DI_NODIR;
434: if (deltay<-10)
435: d[2]= 270;
436: else if (deltay>10)
437: d[2]= 90;
438: else
439: d[2]= DI_NODIR;
440:
441: // try direct route
442: if (d[1] != DI_NODIR && d[2] != DI_NODIR)
443: {
444: if (d[1] == 0)
445: tdir = d[2] == 90 ? 45 : 315;
446: else
447: tdir = d[2] == 90 ? 135 : 215;
448:
449: if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
450: return;
451: }
452:
453: // try other directions
454: if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
455: {
456: tdir=d[1];
457: d[1]=d[2];
458: d[2]=tdir;
459: }
460:
461: if (d[1]!=DI_NODIR && d[1]!=turnaround
462: && SV_StepDirection(actor, d[1], dist))
463: return;
464:
465: if (d[2]!=DI_NODIR && d[2]!=turnaround
466: && SV_StepDirection(actor, d[2], dist))
467: return;
468:
469: /* there is no direct path to the player, so pick another direction */
470:
471: if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
472: return;
473:
474: if (rand()&1) /*randomly determine direction of search*/
475: {
476: for (tdir=0 ; tdir<=315 ; tdir += 45)
477: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
478: return;
479: }
480: else
481: {
482: for (tdir=315 ; tdir >=0 ; tdir -= 45)
483: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
484: return;
485: }
486:
487: if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
488: return;
489:
490: actor->ideal_yaw = olddir; // can't move
491:
492: // if a bridge was pulled out from underneath a monster, it may not have
493: // a valid standing position at all
494:
495: if (!M_CheckBottom (actor))
496: SV_FixCheckBottom (actor);
497: }
498:
499: /*
500: ======================
501: SV_CloseEnough
502:
503: ======================
504: */
505: qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
506: {
507: int i;
508:
509: for (i=0 ; i<3 ; i++)
510: {
511: if (goal->absmin[i] > ent->absmax[i] + dist)
512: return false;
513: if (goal->absmax[i] < ent->absmin[i] - dist)
514: return false;
515: }
516: return true;
517: }
518:
519:
520: /*
521: ======================
522: M_MoveToGoal
523: ======================
524: */
525: void M_MoveToGoal (edict_t *ent, float dist)
526: {
527: edict_t *goal;
528:
529: goal = ent->goalentity;
530:
531: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
532: return;
533:
534: // if the next step hits the enemy, return immediately
535: if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) )
536: return;
537:
538: // bump around...
539: if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
540: {
541: if (ent->inuse)
542: SV_NewChaseDir (ent, goal, dist);
543: }
544: }
545:
546:
547: /*
548: ===============
549: M_walkmove
550: ===============
551: */
552: qboolean M_walkmove (edict_t *ent, float yaw, float dist)
553: {
554: vec3_t move;
555:
556: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
557: return false;
558:
559: yaw = yaw*M_PI*2 / 360;
560:
561: move[0] = cos(yaw)*dist;
562: move[1] = sin(yaw)*dist;
563: move[2] = 0;
564:
565: return SV_movestep(ent, move, true);
566: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.