|
|
1.1 root 1: // m_move.c -- monster movement
2:
3: #include "g_local.h"
4:
5: #define STEPSIZE 18
6:
7: // this is used for communications out of sv_movestep to say what entity
8: // is blocking us
9: edict_t *new_bad; //pmm
10:
11: /*
12: =============
13: M_CheckBottom
14:
15: Returns false if any part of the bottom of the entity is off an edge that
16: is not a staircase.
17:
18: =============
19: */
20: int c_yes, c_no;
21:
22: qboolean M_CheckBottom (edict_t *ent)
23: {
24: vec3_t mins, maxs, start, stop;
25: trace_t trace;
26: int x, y;
27: float mid, bottom;
28:
29: VectorAdd (ent->s.origin, ent->mins, mins);
30: VectorAdd (ent->s.origin, ent->maxs, maxs);
31:
32: // if all of the points under the corners are solid world, don't bother
33: // with the tougher checks
34: // the corners must be within 16 of the midpoint
35:
36: //PGM
37: #ifdef ROGUE_GRAVITY
38: // FIXME - this will only handle 0,0,1 and 0,0,-1 gravity vectors
39: start[2] = mins[2] - 1;
40: if(ent->gravityVector[2] > 0)
41: start[2] = maxs[2] + 1;
42: #else
43: start[2] = mins[2] - 1;
44: #endif
45: //PGM
46:
47: for (x=0 ; x<=1 ; x++)
48: for (y=0 ; y<=1 ; y++)
49: {
50: start[0] = x ? maxs[0] : mins[0];
51: start[1] = y ? maxs[1] : mins[1];
52: if (gi.pointcontents (start) != CONTENTS_SOLID)
53: goto realcheck;
54: }
55:
56: c_yes++;
57: return true; // we got out easy
58:
59: realcheck:
60: c_no++;
61: //
62: // check it for real...
63: //
64: start[2] = mins[2];
65:
66: // the midpoint must be within 16 of the bottom
67: start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
68: start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
69:
70: //PGM
71: #ifdef ROGUE_GRAVITY
72: if(ent->gravityVector[2] < 0)
73: {
74: start[2] = mins[2];
75: stop[2] = start[2] - STEPSIZE - STEPSIZE;
76: }
77: else
78: {
79: start[2] = maxs[2];
80: stop[2] = start[2] + STEPSIZE + STEPSIZE;
81: }
82: #else
83: stop[2] = start[2] - 2*STEPSIZE;
84: #endif
85: //PGM
86:
87: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
88:
89: if (trace.fraction == 1.0)
90: return false;
91: mid = bottom = trace.endpos[2];
92:
93: // the corners must be within 16 of the midpoint
94: for (x=0 ; x<=1 ; x++)
95: for (y=0 ; y<=1 ; y++)
96: {
97: start[0] = stop[0] = x ? maxs[0] : mins[0];
98: start[1] = stop[1] = y ? maxs[1] : mins[1];
99:
100: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
101:
102: //PGM
103: #ifdef ROGUE_GRAVITY
104: // FIXME - this will only handle 0,0,1 and 0,0,-1 gravity vectors
105: if(ent->gravityVector[2] > 0)
106: {
107: if (trace.fraction != 1.0 && trace.endpos[2] < bottom)
108: bottom = trace.endpos[2];
109: if (trace.fraction == 1.0 || trace.endpos[2] - mid > STEPSIZE)
110: return false;
111: }
112: else
113: {
114: if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
115: bottom = trace.endpos[2];
116: if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
117: return false;
118: }
119: #else
120: if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
121: bottom = trace.endpos[2];
122: if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
123: return false;
124: #endif
125: //PGM
126: }
127:
128: c_yes++;
129: return true;
130: }
131:
132: //============
133: // ROGUE
134: qboolean IsBadAhead (edict_t *self, edict_t *bad)
135: {
136: vec3_t dir;
137: vec3_t forward;
138:
139: VectorSubtract (bad->s.origin, self->s.origin, dir);
140: VectorNormalize (dir);
141: AngleVectors (self->s.angles, forward, NULL, NULL);
142: if(DotProduct(forward, dir) > 0)
143: {
144: // gi.dprintf ("bad ahead...\n");
145: return true;
146: }
147:
148: // gi.dprintf ("bad behind...\n");
149: return false;
150: }
151: // ROGUE
152: //============
153:
154: /*
155: =============
156: SV_movestep
157:
158: Called by monster program code.
159: The move will be adjusted for slopes and stairs, but if the move isn't
160: possible, no move is done, false is returned, and
161: pr_global_struct->trace_normal is set to the normal of the blocking wall
162: =============
163: */
164: //FIXME since we need to test end position contents here, can we avoid doing
165: //it again later in catagorize position?
166: qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
167: {
168: float dz;
169: vec3_t oldorg, neworg, end;
170: trace_t trace;
171: int i;
172: float stepsize;
173: vec3_t test;
174: int contents;
175: edict_t *current_bad; // PGM
176: float minheight; // pmm
177:
178: //======
179: //PGM
180:
181: // PMM - who cares about bad areas if you're dead?
182: if (ent->health > 0)
183: {
184: current_bad = CheckForBadArea(ent);
185: if(current_bad)
186: {
187: ent->bad_area = current_bad;
188:
189: if(ent->enemy && !strcmp(ent->enemy->classname, "tesla"))
190: {
191: // if the tesla is in front of us, back up...
192: if (IsBadAhead (ent, current_bad))
193: VectorScale(move, -1, move);
194: }
195: }
196: else if(ent->bad_area)
197: {
198: // if we're no longer in a bad area, get back to business.
199: ent->bad_area = NULL;
200: if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy)
201: {
202: // gi.dprintf("resuming being pissed at %s\n", ent->oldenemy->classname);
203: ent->enemy = ent->oldenemy;
204: ent->goalentity = ent->oldenemy;
205: FoundTarget(ent);
206: // FIXME - remove this when ready!!!
207: if (ent->lastMoveTime == level.time)
208: if ((g_showlogic) && (g_showlogic->value))
209: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
210: ent->lastMoveTime = level.time;
211: // FIXME
212:
213: return true;
214: }
215: }
216: }
217: //PGM
218: //======
219:
220: // try the move
221: VectorCopy (ent->s.origin, oldorg);
222: VectorAdd (ent->s.origin, move, neworg);
223:
224: // flying monsters don't step up
225: if ( ent->flags & (FL_SWIM | FL_FLY) )
226: {
227: // try one move with vertical motion, then one without
228: for (i=0 ; i<2 ; i++)
229: {
230: VectorAdd (ent->s.origin, move, neworg);
231: if (i == 0 && ent->enemy)
232: {
233: if (!ent->goalentity)
234: ent->goalentity = ent->enemy;
235: dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
236: if (ent->goalentity->client)
237: {
238: // we want the carrier to stay a certain distance off the ground, to help prevent him
239: // from shooting his fliers, who spawn in below him
240: //
241: if (!strcmp(ent->classname, "monster_carrier"))
242: minheight = 104;
243: else
244: minheight = 40;
245: // if (dz > 40)
246: if (dz > minheight)
247: // pmm
248: neworg[2] -= 8;
249: if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
250: if (dz < (minheight - 10))
251: neworg[2] += 8;
252: }
253: else
254: {
255: if (dz > 8)
256: neworg[2] -= 8;
257: else if (dz > 0)
258: neworg[2] -= dz;
259: else if (dz < -8)
260: neworg[2] += 8;
261: else
262: neworg[2] += dz;
263: }
264: }
265:
266: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
267:
268: // fly monsters don't enter water voluntarily
269: if (ent->flags & FL_FLY)
270: {
271: if (!ent->waterlevel)
272: {
273: test[0] = trace.endpos[0];
274: test[1] = trace.endpos[1];
275: test[2] = trace.endpos[2] + ent->mins[2] + 1;
276: contents = gi.pointcontents(test);
277: if (contents & MASK_WATER)
278: return false;
279: }
280: }
281:
282: // swim monsters don't exit water voluntarily
283: if (ent->flags & FL_SWIM)
284: {
285: if (ent->waterlevel < 2)
286: {
287: test[0] = trace.endpos[0];
288: test[1] = trace.endpos[1];
289: test[2] = trace.endpos[2] + ent->mins[2] + 1;
290: contents = gi.pointcontents(test);
291: if (!(contents & MASK_WATER))
292: return false;
293: }
294: }
295:
296: // if (trace.fraction == 1)
297:
298: // PMM - changed above to this
299: if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid))
300: {
301: VectorCopy (trace.endpos, ent->s.origin);
302: //=====
303: //PGM
304: if(!current_bad && CheckForBadArea(ent))
305: {
306: // gi.dprintf("Oooh! Bad Area!\n");
307: VectorCopy (oldorg, ent->s.origin);
308: }
309: else
310: {
311: if (relink)
312: {
313: gi.linkentity (ent);
314: G_TouchTriggers (ent);
315: }
316: // FIXME - remove this when ready!!!
317: if (ent->lastMoveTime == level.time)
318: if ((g_showlogic) && (g_showlogic->value))
319: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
320: ent->lastMoveTime = level.time;
321: // FIXME
322:
323: return true;
324: }
325: //PGM
326: //=====
327: }
328:
329: if (!ent->enemy)
330: break;
331: }
332:
333: return false;
334: }
335:
336: // push down from a step height above the wished position
337: if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
338: stepsize = STEPSIZE;
339: else
340: stepsize = 1;
341:
342: //PGM
343: #ifdef ROGUE_GRAVITY
344: // trace from 1 stepsize gravityUp to 2 stepsize gravityDown.
345: VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg);
346: VectorMA(neworg, 2 * stepsize, ent->gravityVector, end);
347: #else
348: neworg[2] += stepsize;
349: VectorCopy (neworg, end);
350: end[2] -= stepsize*2;
351: #endif
352: //PGM
353:
354: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
355:
356: if (trace.allsolid)
357: return false;
358:
359: if (trace.startsolid)
360: {
361: neworg[2] -= stepsize;
362: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
363: if (trace.allsolid || trace.startsolid)
364: return false;
365: }
366:
367:
368: // don't go in to water
369: if (ent->waterlevel == 0)
370: {
371: //PGM
372: #ifdef ROGUE_GRAVITY
373: test[0] = trace.endpos[0];
374: test[1] = trace.endpos[1];
375: if(ent->gravityVector[2] > 0)
376: test[2] = trace.endpos[2] + ent->maxs[2] - 1;
377: else
378: test[2] = trace.endpos[2] + ent->mins[2] + 1;
379: #else
380: test[0] = trace.endpos[0];
381: test[1] = trace.endpos[1];
382: test[2] = trace.endpos[2] + ent->mins[2] + 1;
383: #endif
384: //PGM
385:
386: contents = gi.pointcontents(test);
387:
388: if (contents & MASK_WATER)
389: return false;
390: }
391:
392: if (trace.fraction == 1)
393: {
394: // if monster had the ground pulled out, go ahead and fall
395: if ( ent->flags & FL_PARTIALGROUND )
396: {
397: VectorAdd (ent->s.origin, move, ent->s.origin);
398: if (relink)
399: {
400: gi.linkentity (ent);
401: G_TouchTriggers (ent);
402: }
403: ent->groundentity = NULL;
404: // FIXME - remove this when ready!!!
405: if (ent->lastMoveTime == level.time)
406: if ((g_showlogic) && (g_showlogic->value))
407: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
408: ent->lastMoveTime = level.time;
409: // FIXME
410:
411: return true;
412: }
413:
414: return false; // walked off an edge
415: }
416:
417: // check point traces down for dangling corners
418: VectorCopy (trace.endpos, ent->s.origin);
419:
420: //PGM
421: // PMM - don't bother with bad areas if we're dead
422: if (ent->health > 0)
423: {
424: // use AI_BLOCKED to tell the calling layer that we're now mad at a tesla
425: new_bad = CheckForBadArea(ent);
426: if(!current_bad && new_bad)
427: {
428: if (new_bad->owner)
429: {
430: if ((g_showlogic) && (g_showlogic->value))
431: gi.dprintf("Blocked -");
432: if (!strcmp(new_bad->owner->classname, "tesla"))
433: {
434: if ((g_showlogic) && (g_showlogic->value))
435: gi.dprintf ("it's a tesla -");
436: if ((!(ent->enemy)) || (!(ent->enemy->inuse)))
437: {
438: if ((g_showlogic) && (g_showlogic->value))
439: gi.dprintf ("I don't have a valid enemy, attacking tesla!\n");
440: TargetTesla (ent, new_bad->owner);
441: ent->monsterinfo.aiflags |= AI_BLOCKED;
442: }
443: else if (!strcmp(ent->enemy->classname, "telsa"))
444: {
445: if ((g_showlogic) && (g_showlogic->value))
446: gi.dprintf ("but we're already mad at a tesla\n");
447: }
448: else if ((ent->enemy) && (ent->enemy->client))
449: {
450: if ((g_showlogic) && (g_showlogic->value))
451: gi.dprintf ("we have a player enemy -");
452: if (visible(ent, ent->enemy))
453: {
454: if ((g_showlogic) && (g_showlogic->value))
455: gi.dprintf ("we can see him -");
456: }
457: else
458: {
459: if ((g_showlogic) && (g_showlogic->value))
460: gi.dprintf ("can't see him, kill the tesla! -");
461: TargetTesla (ent, new_bad->owner);
462: ent->monsterinfo.aiflags |= AI_BLOCKED;
463: }
464: }
465: else
466: {
467: if ((g_showlogic) && (g_showlogic->value))
468: gi.dprintf ("the enemy isn't a player, killing tesla -");
469: TargetTesla (ent, new_bad->owner);
470: ent->monsterinfo.aiflags |= AI_BLOCKED;
471: }
472: }
473: else if ((g_showlogic) && (g_showlogic->value))
474: {
475: gi.dprintf(" by non-tesla bad area!");
476: }
477: }
478: gi.dprintf ("\n");
479:
480: VectorCopy (oldorg, ent->s.origin);
481: return false;
482: }
483: }
484: //PGM
485:
486: if (!M_CheckBottom (ent))
487: {
488: if ( ent->flags & FL_PARTIALGROUND )
489: { // entity had floor mostly pulled out from underneath it
490: // and is trying to correct
491: if (relink)
492: {
493: gi.linkentity (ent);
494: G_TouchTriggers (ent);
495: }
496: // FIXME - remove this when ready!!!
497: if (ent->lastMoveTime == level.time)
498: if ((g_showlogic) && (g_showlogic->value))
499: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
500: ent->lastMoveTime = level.time;
501: // FIXME
502:
503: return true;
504: }
505: VectorCopy (oldorg, ent->s.origin);
506: return false;
507: }
508:
509: if ( ent->flags & FL_PARTIALGROUND )
510: {
511: ent->flags &= ~FL_PARTIALGROUND;
512: }
513: ent->groundentity = trace.ent;
514: ent->groundentity_linkcount = trace.ent->linkcount;
515:
516: // the move is ok
517: if (relink)
518: {
519: gi.linkentity (ent);
520: G_TouchTriggers (ent);
521: }
522: // FIXME - remove this when ready!!!
523: if (ent->lastMoveTime == level.time)
524: if ((g_showlogic) && (g_showlogic->value))
525: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname);
526: ent->lastMoveTime = level.time;
527: // FIXME
528:
529: return true;
530: }
531:
532:
533: //============================================================================
534:
535: /*
536: ===============
537: M_ChangeYaw
538:
539: ===============
540: */
541: void M_ChangeYaw (edict_t *ent)
542: {
543: float ideal;
544: float current;
545: float move;
546: float speed;
547:
548: current = anglemod(ent->s.angles[YAW]);
549: ideal = ent->ideal_yaw;
550:
551: if (current == ideal)
552: return;
553:
554: move = ideal - current;
555: speed = ent->yaw_speed;
556: if (ideal > current)
557: {
558: if (move >= 180)
559: move = move - 360;
560: }
561: else
562: {
563: if (move <= -180)
564: move = move + 360;
565: }
566: if (move > 0)
567: {
568: if (move > speed)
569: move = speed;
570: }
571: else
572: {
573: if (move < -speed)
574: move = -speed;
575: }
576:
577: ent->s.angles[YAW] = anglemod (current + move);
578: }
579:
580:
581: /*
582: ======================
583: SV_StepDirection
584:
585: Turns to the movement direction, and walks the current distance if
586: facing it.
587:
588: ======================
589: */
590: qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
591: {
592: vec3_t move, oldorigin;
593: float delta;
594:
595: if(!ent->inuse) return true; // PGM g_touchtrigger free problem
596:
597: ent->ideal_yaw = yaw;
598: M_ChangeYaw (ent);
599:
600: yaw = yaw*M_PI*2 / 360;
601: move[0] = cos(yaw)*dist;
602: move[1] = sin(yaw)*dist;
603: move[2] = 0;
604:
605: VectorCopy (ent->s.origin, oldorigin);
606: if (SV_movestep (ent, move, false))
607: {
608: ent->monsterinfo.aiflags &= ~AI_BLOCKED;
609: if(!ent->inuse) return true; // PGM g_touchtrigger free problem
610:
611: delta = ent->s.angles[YAW] - ent->ideal_yaw;
612: if (strncmp(ent->classname, "monster_widow", 13))
613: {
614: if (delta > 45 && delta < 315)
615: { // not turned far enough, so don't take the step
616: VectorCopy (oldorigin, ent->s.origin);
617: }
618: }
619: gi.linkentity (ent);
620: G_TouchTriggers (ent);
621: return true;
622: }
623: gi.linkentity (ent);
624: G_TouchTriggers (ent);
625: return false;
626: }
627:
628: /*
629: ======================
630: SV_FixCheckBottom
631:
632: ======================
633: */
634: void SV_FixCheckBottom (edict_t *ent)
635: {
636: ent->flags |= FL_PARTIALGROUND;
637: }
638:
639:
640:
641: /*
642: ================
643: SV_NewChaseDir
644:
645: ================
646: */
647: #define DI_NODIR -1
648: void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
649: {
650: float deltax,deltay;
651: float d[3];
652: float tdir, olddir, turnaround;
653:
654: //FIXME: how did we get here with no enemy
655: if (!enemy)
656: return;
657:
658: olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
659: turnaround = anglemod(olddir - 180);
660:
661: deltax = enemy->s.origin[0] - actor->s.origin[0];
662: deltay = enemy->s.origin[1] - actor->s.origin[1];
663: if (deltax>10)
664: d[1]= 0;
665: else if (deltax<-10)
666: d[1]= 180;
667: else
668: d[1]= DI_NODIR;
669: if (deltay<-10)
670: d[2]= 270;
671: else if (deltay>10)
672: d[2]= 90;
673: else
674: d[2]= DI_NODIR;
675:
676: // try direct route
677: if (d[1] != DI_NODIR && d[2] != DI_NODIR)
678: {
679: if (d[1] == 0)
680: tdir = d[2] == 90 ? 45 : 315;
681: else
682: tdir = d[2] == 90 ? 135 : 215;
683:
684: if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
685: return;
686: }
687:
688: // try other directions
689: if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
690: {
691: tdir=d[1];
692: d[1]=d[2];
693: d[2]=tdir;
694: }
695:
696: if (d[1]!=DI_NODIR && d[1]!=turnaround
697: && SV_StepDirection(actor, d[1], dist))
698: return;
699:
700: if (d[2]!=DI_NODIR && d[2]!=turnaround
701: && SV_StepDirection(actor, d[2], dist))
702: return;
703:
704: //ROGUE
705: if(actor->monsterinfo.blocked)
706: {
707: if ((actor->inuse) && (actor->health > 0))
708: {
709: if((actor->monsterinfo.blocked)(actor, dist))
710: return;
711: }
712: }
713: //ROGUE
714:
715: /* there is no direct path to the player, so pick another direction */
716:
717: if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
718: return;
719:
720: if (rand()&1) /*randomly determine direction of search*/
721: {
722: for (tdir=0 ; tdir<=315 ; tdir += 45)
723: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
724: return;
725: }
726: else
727: {
728: for (tdir=315 ; tdir >=0 ; tdir -= 45)
729: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
730: return;
731: }
732:
733: if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
734: return;
735:
736: actor->ideal_yaw = olddir; // can't move
737:
738: // if a bridge was pulled out from underneath a monster, it may not have
739: // a valid standing position at all
740:
741: if (!M_CheckBottom (actor))
742: SV_FixCheckBottom (actor);
743: }
744:
745: /*
746: ======================
747: SV_CloseEnough
748:
749: ======================
750: */
751: qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
752: {
753: int i;
754:
755: for (i=0 ; i<3 ; i++)
756: {
757: if (goal->absmin[i] > ent->absmax[i] + dist)
758: return false;
759: if (goal->absmax[i] < ent->absmin[i] - dist)
760: return false;
761: }
762: return true;
763: }
764:
765: /*
766: ======================
767: M_MoveToGoal
768: ======================
769: */
770: void M_MoveToGoal (edict_t *ent, float dist)
771: {
772: edict_t *goal;
773:
774: goal = ent->goalentity;
775:
776: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
777: return;
778:
779: // if the next step hits the enemy, return immediately
780: if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) )
781: return;
782:
783: // bump around...
784: // if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
785: // PMM - charging monsters (AI_CHARGING) don't deflect unless they have to
786: if ( (((rand()&3)==1) && !(ent->monsterinfo.aiflags & AI_CHARGING)) || !SV_StepDirection (ent, ent->ideal_yaw, dist))
787: {
788: if (ent->monsterinfo.aiflags & AI_BLOCKED)
789: {
790: if ((g_showlogic) && (g_showlogic->value))
791: gi.dprintf ("tesla attack detected, not changing direction!\n");
792: ent->monsterinfo.aiflags &= ~AI_BLOCKED;
793: return;
794: }
795: if (ent->inuse)
796: SV_NewChaseDir (ent, goal, dist);
797: }
798: }
799:
800:
801: /*
802: ===============
803: M_walkmove
804: ===============
805: */
806: qboolean M_walkmove (edict_t *ent, float yaw, float dist)
807: {
808: vec3_t move;
809: // PMM
810: qboolean retval;
811:
812: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
813: return false;
814:
815: yaw = yaw*M_PI*2 / 360;
816:
817: move[0] = cos(yaw)*dist;
818: move[1] = sin(yaw)*dist;
819: move[2] = 0;
820:
821: // PMM
822: retval = SV_movestep(ent, move, true);
823: ent->monsterinfo.aiflags &= ~AI_BLOCKED;
824: return retval;
825: // pmm
826: //return SV_movestep(ent, move, true);
827: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.