1 #include "g_local.h"
2 
3 
4 #define Z_RADUISLISTSIZE	2000
5 
6 
7 
8 void ai_run_melee(edict_t *self);
9 qboolean FindTarget (edict_t *self);
10 qboolean SV_StepDirection (edict_t *ent, float yaw, float dist);
11 void SV_NewChaseDir (edict_t *actor, vec3_t eOrigin, float dist);
12 #if 0
13 void z_aiMoveTo(edict_t *self, float dist)
14 {
15 	// sanity check
16 	if (!(self->monsterinfo.scriptState & MSS_AIMOVETO))
17 		return;
18 #if 0
19 	if (!SV_StepDirection (self, self->ideal_yaw, dist))
20 	{
21 		SV_NewChaseDir (self, self->monsterinfo.aiMoveTo, dist);
22 	}
23 #endif
24 }
25 #endif
26 
27 
28 /*
29 =============
30 zSchoolAllVisiable
31 
32 Creates a list of all entities in the raduis of Z_RADUISLISTSIZE
33 ==============
34 */
zCreateRaduisList(edict_t * self)35 void zCreateRaduisList(edict_t *self)
36 {
37 	edict_t *head, *list;
38   vec3_t vec;
39 
40 	if(self->zRaduisList)
41   { // already created for this think, don't bother doing it again...
42   	return;
43   }
44 
45   head = NULL;
46   list = self;
47 
48   while(1)
49   {
50 		head = findradius(head, self->s.origin, Z_RADUISLISTSIZE);
51 		if(head == NULL)
52 			break;
53 
54     if(head != self)
55     {
56 	  	list->zRaduisList = head;
57 		  VectorSubtract(self->s.origin, head->s.origin, vec);
58 		  head->zDistance = VectorLength(vec);
59   	  list = head;
60     }
61   }
62 
63   list->zRaduisList = NULL;
64 };
65 
66 
67 
68 /*
69 =============
70 zSchoolAllVisiable
71 
72 Create list of monsters of the same schooling type that are ahead of you.
73 ==============
74 */
zSchoolAllVisiable(edict_t * self)75 int zSchoolAllVisiable(edict_t *self)
76 {
77   int max;
78   edict_t *head, *list;
79 
80   max = 0;
81 
82   zCreateRaduisList(self);
83 	head = self->zRaduisList;
84   list = self;
85 
86 	while (head)
87 	{
88     if(strcmp(head->classname, self->classname) == 0 && (self->monsterinfo.aiflags & AI_SCHOOLING) && (head->health > 0) &&
89         (head->zDistance <= self->monsterinfo.zSchoolSightRadius) && (visible(self, head)) && (infront(self, head)))
90 		{
91     	list->zSchoolChain = head;
92       list = head;
93       max++;
94 		}
95 		head = head->zRaduisList;
96 	}
97 
98   list->zSchoolChain = NULL;
99 
100   return max;
101 }
102 
103 
104 
105 
106 /*
107 =============
108 zFindRoamYaw
109 
110 Check direction moving in does not hit a wall... if it does change direction.
111 ==============
112 */
zFindRoamYaw(edict_t * self,float distcheck)113 int zFindRoamYaw(edict_t *self, float distcheck)
114 {
115 	vec3_t	forward, end, angles;
116 	trace_t	tr;
117   float current = anglemod(self->s.angles[YAW]);
118 
119   if(current <= self->ideal_yaw - 1 || current > self->ideal_yaw + 1)
120   {
121     if(fabs(current - self->ideal_yaw) <= 359.0)
122     {
123       return 0;
124     }
125   }
126 
127 	AngleVectors (self->s.angles, forward, NULL, NULL);
128   VectorMA (self->s.origin, distcheck, forward, end);
129 
130 	tr = gi.trace (self->s.origin, self->mins, self->maxs, end, self, MASK_SOLID);
131 
132 	if (tr.fraction < 1.0)
133   {
134     if(random() > 0.75)
135     {
136 	    self->ideal_yaw = vectoyaw(forward);
137    	  self->ideal_yaw = self->ideal_yaw + 180;
138     }
139     else
140     {
141       float dir = random() > 0.5 ? -45 : 45;
142       float maxtrys = 100;
143 
144       VectorCopy(self->s.angles, angles);
145 
146       while(tr.fraction < 1.0 && maxtrys)
147       {
148   	    // blocked, change ideal yaw...
149 	      self->ideal_yaw = vectoyaw(forward);
150    	    self->ideal_yaw = self->ideal_yaw + (random() * dir);
151     //   	self->ideal_yaw = self->ideal_yaw + (-45 +  (random() * 90));
152 
153     	  angles[YAW] = anglemod (self->ideal_yaw);
154 	      AngleVectors (angles, forward, NULL, NULL);
155         VectorMA (self->s.origin, distcheck, forward, end);
156 
157     	  tr = gi.trace (self->s.origin, self->mins, self->maxs, end, self, MASK_SOLID);
158         maxtrys--;
159       }
160     }
161 
162     return 1;
163   }
164 
165   return 0;
166 };
167 
168 
169 
170 /*
171 =============
172 zSchoolMonsters
173 
174 Roaming schooling ai.
175 ==============
176 */
zSchoolMonsters(edict_t * self,float dist,int runStyle,float * currentSpeed)177 int zSchoolMonsters(edict_t *self, float dist, int runStyle, float *currentSpeed)
178 {
179   int maxInsight;
180   int newRunStyle;
181 
182   maxInsight = zSchoolAllVisiable(self);
183 
184 	// If you're not out in front
185   if(maxInsight > 0)
186   {
187   	float totalSpeed;
188     float totalBearing;
189     float distanceToNearest, distanceToLeader, dist;
190     edict_t *nearestEntity, *list;
191     vec3_t vec;
192 
193     totalSpeed = 0;
194     totalBearing = 0;
195     distanceToNearest = 10000;
196     distanceToLeader = 0;
197     list = self->zSchoolChain;
198 
199     while(list)
200     {
201 			// Gather data on those you see
202     	totalSpeed += list->speed;
203       totalBearing += anglemod(list->s.angles[YAW]);
204 
205 		  VectorSubtract(self->s.origin, list->s.origin, vec);
206 		  dist = VectorLength(vec);
207 
208       if(dist < distanceToNearest)
209       {
210       	distanceToNearest = dist;
211         nearestEntity = list;
212       }
213 
214       if(dist > distanceToLeader)
215       {
216       	distanceToLeader = dist;
217       }
218 
219       list = list->zSchoolChain;
220 		}
221 
222 		// Rule 1) Match average speed of those in the list
223     self->speed = (totalSpeed / maxInsight) * 1.5;
224 
225 		// Rule 2) Move towards the perceived center of gravity of the herd
226 		self->ideal_yaw = totalBearing / maxInsight;
227 
228     // check if hitting something
229     if(!zFindRoamYaw(self, 10))
230     {
231       // Rule 3) Maintain a minimum distance from those around you
232 		  if(distanceToNearest <= self->monsterinfo.zSchoolMinimumDistance)
233       {
234 			  self->ideal_yaw = nearestEntity->s.angles[YAW];
235         self->speed = nearestEntity->speed;
236       }
237     }
238 
239   }
240   else
241   {	//You are in front, so slow down a bit
242    	edict_t *head;
243 
244     self->speed = (self->speed * self->monsterinfo.zSchoolDecayRate);
245 
246     // check direction
247 	  zFindRoamYaw(self, 100);
248 
249     // change directions of the monsters following you...
250     zCreateRaduisList(self);
251     head = self->zRaduisList;
252 
253     while (head)
254     {
255       if(strcmp(head->classname, self->classname) == 0 && (head->health > 0) &&
256         (head->zDistance <= self->monsterinfo.zSchoolSightRadius) && (visible(self, head)))
257 
258       {
259         head->ideal_yaw = self->ideal_yaw + (-20 +  (random() * 40));
260       }
261       head = head->zRaduisList;
262     }
263   }
264 
265 //  if(self.rm_schoolFlags & 1)
266 //  { // check to see is I keep away from "other" entities...
267 //    zSchoolCheckForOtherEntities(checkOtherRaduis);
268 //  }
269 
270   if(self->speed > self->monsterinfo.zSchoolMaxSpeed)
271   {
272     self->speed = self->monsterinfo.zSchoolMaxSpeed;
273   }
274 
275   if(self->speed < self->monsterinfo.zSchoolMinSpeed)
276   {
277 		self->speed = self->monsterinfo.zSchoolMinSpeed;
278   }
279 
280   if(self->speed <= self->monsterinfo.zSpeedStandMax)
281   {
282     newRunStyle = 0;
283 
284     if(newRunStyle != runStyle)
285     {
286       *currentSpeed = 1;
287     }
288     else
289     {
290       *currentSpeed = (self->speed - self->monsterinfo.zSchoolMinSpeed) + 1;
291     }
292   }
293   else if(self->speed <= self->monsterinfo.zSpeedWalkMax)
294   {
295     newRunStyle = 1;
296 
297     if(newRunStyle  != runStyle)
298     {
299       *currentSpeed = 1;
300     }
301     else
302     {
303       *currentSpeed = (self->speed - self->monsterinfo.zSpeedStandMax) + 1;
304     }
305   }
306   else
307   {
308     newRunStyle = 2;
309 
310     if(newRunStyle  != runStyle)
311     {
312       *currentSpeed = 1;
313     }
314     else
315     {
316       *currentSpeed = (self->speed - self->monsterinfo.zSpeedWalkMax) + 1;
317     }
318   }
319 
320   return newRunStyle;
321 }
322 
323 
324 
325 /*
326 =============
327 ai_schoolStand
328 
329 Used for standing around and looking for players / schooling monsters of the same type.
330 Distance is for slight position adjustments needed by the animations
331 ==============
332 */
ai_schoolStand(edict_t * self,float dist)333 void ai_schoolStand (edict_t *self, float dist)
334 {
335   float speed;
336 
337   if(!(self->monsterinfo.aiflags & AI_SCHOOLING))
338   {
339     ai_stand(self, dist);
340     return;
341   }
342 
343   // init school var's for this frame
344   self->zRaduisList = NULL;
345 
346   if(self->enemy || FindTarget(self))
347   {
348     ai_stand(self, dist);
349     return;
350   }
351   else
352   {
353     // run schooling routines
354     switch(zSchoolMonsters(self, dist, 0, &speed))
355     {
356     case 1:
357 		  self->monsterinfo.walk (self);
358       break;
359 
360     case 2:
361 		  self->monsterinfo.run (self);
362       break;
363     }
364   }
365 
366   // do the normal stand stuff
367   if (dist)
368 		M_walkmove (self, self->ideal_yaw, dist);
369 //		M_walkmove (self, self->ideal_yaw, dist * speed);
370 }
371 
372 
373 
374 
375 
376 /*
377 =============
378 ai_schoolRun
379 
380 The monster has an enemy it is trying to kill
381 =============
382 */
ai_schoolRun(edict_t * self,float dist)383 void ai_schoolRun (edict_t *self, float dist)
384 {
385   float speed;
386 
387   if(!(self->monsterinfo.aiflags & AI_SCHOOLING))
388   {
389     ai_run(self, dist);
390     return;
391   }
392 
393   // init school var's for this frame
394   self->zRaduisList = NULL;
395 
396   if(self->enemy || FindTarget(self))
397   {
398     ai_run(self, dist);
399     return;
400   }
401   else
402   {
403     // run schooling routines
404     switch(zSchoolMonsters(self, dist, 2, &speed))
405     {
406     case 0:
407 		  self->monsterinfo.stand (self);
408       break;
409 
410     case 1:
411 		  self->monsterinfo.walk (self);
412       break;
413     }
414   }
415 
416   // do the normal run stuff
417   SV_StepDirection (self, self->ideal_yaw, dist);
418 //  SV_StepDirection (self, self->ideal_yaw, dist * speed);
419 }
420 
421 
422 
423 /*
424 =============
425 ai_schoolWalk
426 
427 The monster is walking it's beat
428 =============
429 */
ai_schoolWalk(edict_t * self,float dist)430 void ai_schoolWalk (edict_t *self, float dist)
431 {
432   float speed;
433 
434   if(!(self->monsterinfo.aiflags & AI_SCHOOLING))
435   {
436     ai_walk(self, dist);
437     return;
438   }
439 
440   // init school var's for this frame
441   self->zRaduisList = NULL;
442 
443   if(self->enemy || FindTarget(self))
444   {
445     ai_walk(self, dist);
446     return;
447   }
448   else
449   {
450     // run schooling routines
451     switch(zSchoolMonsters(self, dist, 1, &speed))
452     {
453     case 0:
454 		  self->monsterinfo.stand (self);
455       break;
456 
457     case 2:
458 		  self->monsterinfo.run (self);
459       break;
460     }
461   }
462 
463   // do the normal walk stuff
464   SV_StepDirection (self, self->ideal_yaw, dist);
465 //  SV_StepDirection (self, self->ideal_yaw, dist * speed);
466 }
467 
468 
469 
470 /*
471 =============
472 ai_schoolCharge
473 
474 Turns towards target and advances
475 Use this call with a distnace of 0 to replace ai_face
476 ==============
477 */
ai_schoolCharge(edict_t * self,float dist)478 void ai_schoolCharge (edict_t *self, float dist)
479 {
480 /*
481   if(!(self->monsterinfo.aiflags & AI_SCHOOLING))
482   {
483     ai_charge(self, dist);
484     return;
485   }
486 */
487   ai_charge(self, dist);
488 }
489 
490 
491 
492