Quake II RTX doxygen  1.0 dev
m_move.c File Reference
#include "g_local.h"

Go to the source code of this file.

Macros

#define STEPSIZE   18
 
#define DI_NODIR   -1
 

Functions

qboolean M_CheckBottom (edict_t *ent)
 
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
 
void M_ChangeYaw (edict_t *ent)
 
qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
 
void SV_FixCheckBottom (edict_t *ent)
 
void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
 
qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
 
void M_MoveToGoal (edict_t *ent, float dist)
 
qboolean M_walkmove (edict_t *ent, float yaw, float dist)
 

Variables

int c_yes
 
int c_no
 

Macro Definition Documentation

◆ DI_NODIR

#define DI_NODIR   -1

Definition at line 370 of file m_move.c.

◆ STEPSIZE

#define STEPSIZE   18

Definition at line 22 of file m_move.c.

Function Documentation

◆ M_ChangeYaw()

void M_ChangeYaw ( edict_t *  ent)

Definition at line 279 of file m_move.c.

280 {
281  float ideal;
282  float current;
283  float move;
284  float speed;
285 
286  current = anglemod(ent->s.angles[YAW]);
287  ideal = ent->ideal_yaw;
288 
289  if (current == ideal)
290  return;
291 
292  move = ideal - current;
293  speed = ent->yaw_speed;
294  if (ideal > current) {
295  if (move >= 180)
296  move = move - 360;
297  } else {
298  if (move <= -180)
299  move = move + 360;
300  }
301  if (move > 0) {
302  if (move > speed)
303  move = speed;
304  } else {
305  if (move < -speed)
306  move = -speed;
307  }
308 
309  ent->s.angles[YAW] = anglemod(current + move);
310 }

Referenced by ai_charge(), ai_run_melee(), ai_run_missile(), ai_run_slide(), ai_stand(), ai_turn(), FindTarget(), and SV_StepDirection().

◆ M_CheckBottom()

qboolean M_CheckBottom ( edict_t *  ent)

Definition at line 35 of file m_move.c.

36 {
37  vec3_t mins, maxs, start, stop;
38  trace_t trace;
39  int x, y;
40  float mid, bottom;
41 
42  VectorAdd(ent->s.origin, ent->mins, mins);
43  VectorAdd(ent->s.origin, ent->maxs, maxs);
44 
45 // if all of the points under the corners are solid world, don't bother
46 // with the tougher checks
47 // the corners must be within 16 of the midpoint
48  start[2] = mins[2] - 1;
49  for (x = 0 ; x <= 1 ; x++)
50  for (y = 0 ; y <= 1 ; y++) {
51  start[0] = x ? maxs[0] : mins[0];
52  start[1] = y ? maxs[1] : mins[1];
53  if (gi.pointcontents(start) != CONTENTS_SOLID)
54  goto realcheck;
55  }
56 
57  c_yes++;
58  return qtrue; // we got out easy
59 
60 realcheck:
61  c_no++;
62 //
63 // check it for real...
64 //
65  start[2] = mins[2];
66 
67 // the midpoint must be within 16 of the bottom
68  start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5;
69  start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5;
70  stop[2] = start[2] - 2 * STEPSIZE;
71  trace = gi.trace(start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
72 
73  if (trace.fraction == 1.0)
74  return qfalse;
75  mid = bottom = trace.endpos[2];
76 
77 // the corners must be within 16 of the midpoint
78  for (x = 0 ; x <= 1 ; x++)
79  for (y = 0 ; y <= 1 ; y++) {
80  start[0] = stop[0] = x ? maxs[0] : mins[0];
81  start[1] = stop[1] = y ? maxs[1] : mins[1];
82 
83  trace = gi.trace(start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
84 
85  if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
86  bottom = trace.endpos[2];
87  if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
88  return qfalse;
89  }
90 
91  c_yes++;
92  return qtrue;
93 }

Referenced by mutant_jump_touch(), SV_movestep(), SV_NewChaseDir(), and SV_Physics_Step().

◆ M_MoveToGoal()

void M_MoveToGoal ( edict_t *  ent,
float  dist 
)

Definition at line 477 of file m_move.c.

478 {
479  edict_t *goal;
480 
481  goal = ent->goalentity;
482 
483  if (!ent->groundentity && !(ent->flags & (FL_FLY | FL_SWIM)))
484  return;
485 
486 // if the next step hits the enemy, return immediately
487  if (ent->enemy && SV_CloseEnough(ent, ent->enemy, dist))
488  return;
489 
490 // bump around...
491  if ((rand() & 3) == 1 || !SV_StepDirection(ent, ent->ideal_yaw, dist)) {
492  if (ent->inuse)
493  SV_NewChaseDir(ent, goal, dist);
494  }
495 }

Referenced by ai_run(), and ai_walk().

◆ M_walkmove()

qboolean M_walkmove ( edict_t *  ent,
float  yaw,
float  dist 
)

Definition at line 503 of file m_move.c.

504 {
505  vec3_t move;
506 
507  if (!ent->groundentity && !(ent->flags & (FL_FLY | FL_SWIM)))
508  return qfalse;
509 
510  yaw = yaw * M_PI * 2 / 360;
511 
512  move[0] = cos(yaw) * dist;
513  move[1] = sin(yaw) * dist;
514  move[2] = 0;
515 
516  return SV_movestep(ent, move, qtrue);
517 }

Referenced by ai_charge(), ai_move(), ai_run_slide(), ai_stand(), ai_turn(), barrel_touch(), flymonster_start_go(), and walkmonster_start_go().

◆ SV_CloseEnough()

qboolean SV_CloseEnough ( edict_t *  ent,
edict_t *  goal,
float  dist 
)

Definition at line 458 of file m_move.c.

459 {
460  int i;
461 
462  for (i = 0 ; i < 3 ; i++) {
463  if (goal->absmin[i] > ent->absmax[i] + dist)
464  return qfalse;
465  if (goal->absmax[i] < ent->absmin[i] - dist)
466  return qfalse;
467  }
468  return qtrue;
469 }

Referenced by M_MoveToGoal().

◆ SV_FixCheckBottom()

void SV_FixCheckBottom ( edict_t *  ent)

Definition at line 357 of file m_move.c.

358 {
359  ent->flags |= FL_PARTIALGROUND;
360 }

Referenced by SV_NewChaseDir().

◆ SV_movestep()

qboolean SV_movestep ( edict_t *  ent,
vec3_t  move,
qboolean  relink 
)

Definition at line 108 of file m_move.c.

109 {
110  float dz;
111  vec3_t oldorg, neworg, end;
112  trace_t trace;
113  int i;
114  float stepsize;
115  vec3_t test;
116  int contents;
117 
118 // try the move
119  VectorCopy(ent->s.origin, oldorg);
120  VectorAdd(ent->s.origin, move, neworg);
121 
122 // flying monsters don't step up
123  if (ent->flags & (FL_SWIM | FL_FLY)) {
124  // try one move with vertical motion, then one without
125  for (i = 0 ; i < 2 ; i++) {
126  VectorAdd(ent->s.origin, move, neworg);
127  if (i == 0 && ent->enemy) {
128  if (!ent->goalentity)
129  ent->goalentity = ent->enemy;
130  dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
131  if (ent->goalentity->client) {
132  if (dz > 40)
133  neworg[2] -= 8;
134  if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
135  if (dz < 30)
136  neworg[2] += 8;
137  } else {
138  if (dz > 8)
139  neworg[2] -= 8;
140  else if (dz > 0)
141  neworg[2] -= dz;
142  else if (dz < -8)
143  neworg[2] += 8;
144  else
145  neworg[2] += dz;
146  }
147  }
148  trace = gi.trace(ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
149 
150  // fly monsters don't enter water voluntarily
151  if (ent->flags & FL_FLY) {
152  if (!ent->waterlevel) {
153  test[0] = trace.endpos[0];
154  test[1] = trace.endpos[1];
155  test[2] = trace.endpos[2] + ent->mins[2] + 1;
156  contents = gi.pointcontents(test);
157  if (contents & MASK_WATER)
158  return qfalse;
159  }
160  }
161 
162  // swim monsters don't exit water voluntarily
163  if (ent->flags & FL_SWIM) {
164  if (ent->waterlevel < 2) {
165  test[0] = trace.endpos[0];
166  test[1] = trace.endpos[1];
167  test[2] = trace.endpos[2] + ent->mins[2] + 1;
168  contents = gi.pointcontents(test);
169  if (!(contents & MASK_WATER))
170  return qfalse;
171  }
172  }
173 
174  if (trace.fraction == 1) {
175  VectorCopy(trace.endpos, ent->s.origin);
176  if (relink) {
177  gi.linkentity(ent);
178  G_TouchTriggers(ent);
179  }
180  return qtrue;
181  }
182 
183  if (!ent->enemy)
184  break;
185  }
186 
187  return qfalse;
188  }
189 
190 // push down from a step height above the wished position
191  if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
192  stepsize = STEPSIZE;
193  else
194  stepsize = 1;
195 
196  neworg[2] += stepsize;
197  VectorCopy(neworg, end);
198  end[2] -= stepsize * 2;
199 
200  trace = gi.trace(neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
201 
202  if (trace.allsolid)
203  return qfalse;
204 
205  if (trace.startsolid) {
206  neworg[2] -= stepsize;
207  trace = gi.trace(neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
208  if (trace.allsolid || trace.startsolid)
209  return qfalse;
210  }
211 
212 
213  // don't go in to water
214  if (ent->waterlevel == 0) {
215  test[0] = trace.endpos[0];
216  test[1] = trace.endpos[1];
217  test[2] = trace.endpos[2] + ent->mins[2] + 1;
218  contents = gi.pointcontents(test);
219 
220  if (contents & MASK_WATER)
221  return qfalse;
222  }
223 
224  if (trace.fraction == 1) {
225  // if monster had the ground pulled out, go ahead and fall
226  if (ent->flags & FL_PARTIALGROUND) {
227  VectorAdd(ent->s.origin, move, ent->s.origin);
228  if (relink) {
229  gi.linkentity(ent);
230  G_TouchTriggers(ent);
231  }
232  ent->groundentity = NULL;
233  return qtrue;
234  }
235 
236  return qfalse; // walked off an edge
237  }
238 
239 // check point traces down for dangling corners
240  VectorCopy(trace.endpos, ent->s.origin);
241 
242  if (!M_CheckBottom(ent)) {
243  if (ent->flags & FL_PARTIALGROUND) {
244  // entity had floor mostly pulled out from underneath it
245  // and is trying to correct
246  if (relink) {
247  gi.linkentity(ent);
248  G_TouchTriggers(ent);
249  }
250  return qtrue;
251  }
252  VectorCopy(oldorg, ent->s.origin);
253  return qfalse;
254  }
255 
256  if (ent->flags & FL_PARTIALGROUND) {
257  ent->flags &= ~FL_PARTIALGROUND;
258  }
259  ent->groundentity = trace.ent;
260  ent->groundentity_linkcount = trace.ent->linkcount;
261 
262 // the move is ok
263  if (relink) {
264  gi.linkentity(ent);
265  G_TouchTriggers(ent);
266  }
267  return qtrue;
268 }

Referenced by M_walkmove(), and SV_StepDirection().

◆ SV_NewChaseDir()

void SV_NewChaseDir ( edict_t *  actor,
edict_t *  enemy,
float  dist 
)

Definition at line 371 of file m_move.c.

372 {
373  float deltax, deltay;
374  float d[3];
375  float tdir, olddir, turnaround;
376 
377  //FIXME: how did we get here with no enemy
378  if (!enemy)
379  return;
380 
381  olddir = anglemod((int)(actor->ideal_yaw / 45) * 45);
382  turnaround = anglemod(olddir - 180);
383 
384  deltax = enemy->s.origin[0] - actor->s.origin[0];
385  deltay = enemy->s.origin[1] - actor->s.origin[1];
386  if (deltax > 10)
387  d[1] = 0;
388  else if (deltax < -10)
389  d[1] = 180;
390  else
391  d[1] = DI_NODIR;
392  if (deltay < -10)
393  d[2] = 270;
394  else if (deltay > 10)
395  d[2] = 90;
396  else
397  d[2] = DI_NODIR;
398 
399 // try direct route
400  if (d[1] != DI_NODIR && d[2] != DI_NODIR) {
401  if (d[1] == 0)
402  tdir = d[2] == 90 ? 45 : 315;
403  else
404  tdir = d[2] == 90 ? 135 : 215;
405 
406  if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
407  return;
408  }
409 
410 // try other directions
411  if (((rand() & 3) & 1) || fabsf(deltay) > fabsf(deltax)) {
412  tdir = d[1];
413  d[1] = d[2];
414  d[2] = tdir;
415  }
416 
417  if (d[1] != DI_NODIR && d[1] != turnaround
418  && SV_StepDirection(actor, d[1], dist))
419  return;
420 
421  if (d[2] != DI_NODIR && d[2] != turnaround
422  && SV_StepDirection(actor, d[2], dist))
423  return;
424 
425  /* there is no direct path to the player, so pick another direction */
426 
427  if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist))
428  return;
429 
430  if (rand() & 1) { /*randomly determine direction of search*/
431  for (tdir = 0 ; tdir <= 315 ; tdir += 45)
432  if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
433  return;
434  } else {
435  for (tdir = 315 ; tdir >= 0 ; tdir -= 45)
436  if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
437  return;
438  }
439 
440  if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist))
441  return;
442 
443  actor->ideal_yaw = olddir; // can't move
444 
445 // if a bridge was pulled out from underneath a monster, it may not have
446 // a valid standing position at all
447 
448  if (!M_CheckBottom(actor))
449  SV_FixCheckBottom(actor);
450 }

Referenced by M_MoveToGoal().

◆ SV_StepDirection()

qboolean SV_StepDirection ( edict_t *  ent,
float  yaw,
float  dist 
)

Definition at line 322 of file m_move.c.

323 {
324  vec3_t move, oldorigin;
325  float delta;
326 
327  ent->ideal_yaw = yaw;
328  M_ChangeYaw(ent);
329 
330  yaw = yaw * M_PI * 2 / 360;
331  move[0] = cos(yaw) * dist;
332  move[1] = sin(yaw) * dist;
333  move[2] = 0;
334 
335  VectorCopy(ent->s.origin, oldorigin);
336  if (SV_movestep(ent, move, qfalse)) {
337  delta = ent->s.angles[YAW] - ent->ideal_yaw;
338  if (delta > 45 && delta < 315) {
339  // not turned far enough, so don't take the step
340  VectorCopy(oldorigin, ent->s.origin);
341  }
342  gi.linkentity(ent);
343  G_TouchTriggers(ent);
344  return qtrue;
345  }
346  gi.linkentity(ent);
347  G_TouchTriggers(ent);
348  return qfalse;
349 }

Referenced by M_MoveToGoal(), and SV_NewChaseDir().

Variable Documentation

◆ c_no

int c_no

Definition at line 33 of file m_move.c.

Referenced by M_CheckBottom().

◆ c_yes

int c_yes

Definition at line 33 of file m_move.c.

Referenced by M_CheckBottom().

gi
game_import_t gi
Definition: g_main.c:23
SV_CloseEnough
qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist)
Definition: m_move.c:458
c_no
int c_no
Definition: m_move.c:33
M_ChangeYaw
void M_ChangeYaw(edict_t *ent)
Definition: m_move.c:279
G_TouchTriggers
void G_TouchTriggers(edict_t *ent)
Definition: g_utils.c:443
FL_SWIM
#define FL_SWIM
Definition: g_local.h:60
vec3_origin
vec3_t vec3_origin
Definition: shared.c:21
FL_PARTIALGROUND
#define FL_PARTIALGROUND
Definition: g_local.h:67
M_CheckBottom
qboolean M_CheckBottom(edict_t *ent)
Definition: m_move.c:35
DI_NODIR
#define DI_NODIR
Definition: m_move.c:370
SV_FixCheckBottom
void SV_FixCheckBottom(edict_t *ent)
Definition: m_move.c:357
SV_movestep
qboolean SV_movestep(edict_t *ent, vec3_t move, qboolean relink)
Definition: m_move.c:108
c_yes
int c_yes
Definition: m_move.c:33
SV_NewChaseDir
void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist)
Definition: m_move.c:371
SV_StepDirection
qboolean SV_StepDirection(edict_t *ent, float yaw, float dist)
Definition: m_move.c:322
FL_FLY
#define FL_FLY
Definition: g_local.h:59
STEPSIZE
#define STEPSIZE
Definition: m_move.c:22
AI_NOSTEP
#define AI_NOSTEP
Definition: g_local.h:136