]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/steerlib.qc
shadowmapping menu option
[divverent/nexuiz.git] / data / qcsrc / server / steerlib.qc
1 .vector steerto;
2
3 /**
4     Uniform pull towards a point
5 **/
6 vector steerlib_pull(vector point)
7 {
8     return normalize(point - self.origin);
9 }
10
11 /**
12     Uniform push from a point
13 **/
14 vector steerlib_push(vector point)
15 {
16     return normalize(self.origin - point);
17 }
18
19 /**
20     Pull toward a point, The further away, the stronger the pull.
21 **/
22 vector steerlib_arrive(vector point,float maximal_distance)
23 {
24     float distance;
25     vector direction;
26
27     distance = bound(0.001,vlen(self.origin - point),maximal_distance);
28     direction = normalize(point - self.origin);
29     return  direction * (distance / maximal_distance);
30 }
31
32 /**
33     Pull toward a point increasing the pull the closer we get
34 **/
35 vector steerlib_attract(vector point, float maximal_distance)
36 {
37     float distance;
38     vector direction;
39
40     distance = bound(0.001,vlen(self.origin - point),maximal_distance);
41     direction = normalize(point - self.origin);
42
43     return  direction * (1-(distance / maximal_distance));
44 }
45
46 vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense)
47 {
48     float distance;
49     vector direction;
50     float influense;
51
52     distance  = bound(0.00001,vlen(self.origin - point),max_distance);
53     direction = normalize(point - self.origin);
54
55     influense = 1 - (distance / max_distance);
56     influense = min_influense + (influense * (max_influense - min_influense));
57
58     return  direction * influense;
59 }
60
61 /*
62 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
63 {
64     //float distance;
65     vector current_direction;
66     vector target_direction;
67     float i_target,i_current;
68
69     if(!distance)
70         distance = vlen(self.origin - point);
71
72     distance = bound(0.001,distance,maximal_distance);
73
74     target_direction = normalize(point - self.origin);
75     current_direction = normalize(self.velocity);
76
77     i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
78     i_current = 1 - i_target;
79
80     // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
81
82     string s;
83     s = ftos(i_target);
84     bprint("IT: ",s,"\n");
85     s = ftos(i_current);
86     bprint("IC  : ",s,"\n");
87
88     return  normalize((target_direction * i_target) + (current_direction * i_current));
89 }
90 */
91 /**
92     Move away from a point.
93 **/
94 vector steerlib_repell(vector point,float maximal_distance)
95 {
96     float distance;
97     vector direction;
98
99     distance = bound(0.001,vlen(self.origin - point),maximal_distance);
100     direction = normalize(self.origin - point);
101
102     return  direction * (1-(distance / maximal_distance));
103 }
104
105 /**
106     Try to keep at ideal_distance away from point
107 **/
108 vector steerlib_standoff(vector point,float ideal_distance)
109 {
110     float distance;
111     vector direction;
112
113     distance = vlen(self.origin - point);
114
115
116     if(distance < ideal_distance)
117     {
118         direction = normalize(self.origin - point);
119         return direction * (distance / ideal_distance);
120     }
121
122     direction = normalize(point - self.origin);
123     return direction * (ideal_distance / distance);
124
125 }
126
127 /**
128     A random heading in a forward halfcicrle
129
130     use like:
131     self.target = steerlib_wander(256,32,self.target)
132
133     where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
134 **/
135 vector steerlib_wander(float range,float tresh,vector oldpoint)
136 {
137     vector wander_point;
138     wander_point = v_forward - oldpoint;
139
140     if (vlen(wander_point) > tresh)
141         return oldpoint;
142
143     range = bound(0,range,1);
144
145     wander_point = self.origin + v_forward * 128;
146     wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
147
148     return normalize(wander_point - self.origin);
149 }
150
151 /**
152     Dodge a point. dont work to well.
153 **/
154 vector steerlib_dodge(vector point,vector dodge_dir,float min_distance)
155 {
156     float distance;
157
158     distance = max(vlen(self.origin - point),min_distance);
159
160     return dodge_dir * (min_distance/distance);
161 }
162
163 /**
164     flocking by .flock_id
165     Group will move towards the unified direction while keeping close to eachother.
166 **/
167 .float flock_id;
168 vector steerlib_flock(float radius, float standoff,float separation_force,float flock_force)
169 {
170     entity flock_member;
171     vector push,pull;
172     float ccount;
173
174     flock_member = findradius(self.origin,radius);
175     while(flock_member)
176     {
177         if(flock_member != self)
178         if(flock_member.flock_id == self.flock_id)
179         {
180             ++ccount;
181             push = push + (steerlib_repell(flock_member.origin,standoff) * separation_force);
182             pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity,radius) * flock_force);
183         }
184         flock_member = flock_member.chain;
185     }
186     return push + (pull* (1 / ccount));
187 }
188
189 /**
190     All members want to be in the center, and keep away from eachother.
191     The furtehr form the center the more they want to be there.
192
193     This results in a aligned movement (?!) much like flocking.
194 **/
195 vector steerlib_swarm(float radius, float standoff,float separation_force,float swarm_force)
196 {
197     entity swarm_member;
198     vector force,center;
199     float ccount;
200
201     swarm_member = findradius(self.origin,radius);
202
203     while(swarm_member)
204     {
205         if(swarm_member.flock_id == self.flock_id)
206         {
207             ++ccount;
208             center = center + swarm_member.origin;
209             force = force + (steerlib_repell(swarm_member.origin,standoff) * separation_force);
210         }
211         swarm_member = swarm_member.chain;
212     }
213
214     center = center * (1 / ccount);
215     force = force + (steerlib_arrive(center,radius) * swarm_force);
216
217     return force;
218 }
219
220 /**
221     Steer towards the direction least obstructed.
222     Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
223 **/
224 vector steerlib_traceavoid(float pitch,float length)
225 {
226     vector vup_left,vup_right,vdown_left,vdown_right;
227     float fup_left,fup_right,fdown_left,fdown_right;
228     vector upwish,downwish,leftwish,rightwish;
229     vector v_left,v_down;
230
231     v_left = v_right * -1;
232     v_down = v_up * -1;
233
234     vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
235     traceline(self.origin, self.origin +  vup_left,MOVE_NOMONSTERS,self);
236     fup_left = trace_fraction;
237
238     //te_lightning1(world,self.origin, trace_endpos);
239
240     vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
241     traceline(self.origin,self.origin + vup_right ,MOVE_NOMONSTERS,self);
242     fup_right = trace_fraction;
243
244     //te_lightning1(world,self.origin, trace_endpos);
245
246     vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
247     traceline(self.origin,self.origin + vdown_left,MOVE_NOMONSTERS,self);
248     fdown_left = trace_fraction;
249
250     //te_lightning1(world,self.origin, trace_endpos);
251
252     vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
253     traceline(self.origin,self.origin + vdown_right,MOVE_NOMONSTERS,self);
254     fdown_right = trace_fraction;
255
256     //te_lightning1(world,self.origin, trace_endpos);
257
258     upwish    = v_up    * (fup_left   + fup_right);
259     downwish  = v_down  * (fdown_left + fdown_right);
260     leftwish  = v_left  * (fup_left   + fdown_left);
261     rightwish = v_right * (fup_right  + fdown_right);
262
263     return (upwish+leftwish+downwish+rightwish) * 0.25;
264
265 }
266
267 /**
268     Steer towards the direction least obstructed.
269     Run two tracelines in a forward trident, bias each diretion negative if something is found there.
270 **/
271 vector steerlib_traceavoid_flat(float pitch, float length, vector vofs)
272 {
273     vector vt_left, vt_right,vt_front;
274     float f_left, f_right,f_front;
275     vector leftwish, rightwish,frontwish, v_left;
276
277     v_left = v_right * -1;
278
279
280     vt_front = v_forward * length;
281     traceline(self.origin + vofs, self.origin + vofs + vt_front,MOVE_NOMONSTERS,self);
282     f_front = trace_fraction;
283
284     vt_left = (v_forward + (v_left * pitch)) * length;
285     traceline(self.origin + vofs, self.origin + vofs + vt_left,MOVE_NOMONSTERS,self);
286     f_left = trace_fraction;
287
288     //te_lightning1(world,self.origin, trace_endpos);
289
290     vt_right = (v_forward + (v_right * pitch)) * length;
291     traceline(self.origin + vofs, self.origin + vofs + vt_right ,MOVE_NOMONSTERS,self);
292     f_right = trace_fraction;
293
294     //te_lightning1(world,self.origin, trace_endpos);
295
296     leftwish  = v_left    * f_left;
297     rightwish = v_right   * f_right;
298     frontwish = v_forward * f_front;
299
300     return normalize(leftwish + rightwish + frontwish);
301 }
302
303 float beamsweep_badpoint(vector point,float waterok)
304 {
305     float pc,pc2;
306
307     if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
308         return 1;
309
310     pc  = pointcontents(point);
311     pc2 = pointcontents(point - '0 0 1');
312
313     switch(pc)
314     {
315         case CONTENT_SOLID: break;
316         case CONTENT_SLIME: break;
317         case CONTENT_LAVA:  break;
318
319         case CONTENT_SKY:
320             return 1;
321
322         case CONTENT_EMPTY:
323             if (pc2 == CONTENT_SOLID)
324                 return 0;
325
326             if (pc2 == CONTENT_WATER)
327                 if(waterok)
328                     return 0;
329
330             break;
331
332         case CONTENT_WATER:
333             if(waterok)
334                 return 0;
335
336             break;
337     }
338
339     return 1;
340 }
341
342 float beamsweep(vector from, vector dir,float length, float step,float step_up, float step_down)
343 {
344     float i;
345     vector a,b,u,d;
346
347     u = '0 0 1' * step_up;
348     d = '0 0 1' * step_down;
349
350     traceline(from + u, from - d,MOVE_NORMAL,self);
351     if(trace_fraction == 1.0)
352         return 0;
353
354     if(beamsweep_badpoint(trace_endpos,0))
355         return 0;
356
357     a = trace_endpos;
358     for(i = 0; i < length; i += step)
359     {
360
361         b = a + dir * step;
362         tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,self);
363         if(trace_fraction != 1.0)
364             return i / length;
365
366         traceline(b + u, b - d,MOVE_NORMAL,self);
367         if(trace_fraction == 1.0)
368             return i / length;
369
370         if(beamsweep_badpoint(trace_endpos,0))
371             return i / length;
372
373         //te_lightning1(world,a+u,b+u);
374         //te_lightning1(world,b+u,b-d);
375
376         a = trace_endpos;
377     }
378
379     return 1;
380 }
381
382 vector steerlib_beamsteer(vector dir, float length, float step, float step_up, float step_down)
383 {
384     float bm_forward, bm_right, bm_left,p;
385     vector vr,vl;
386
387     dir_z *= 0.15;
388     vr = vectoangles(dir);
389     vr_x *= -1;
390
391     makevectors(vr);
392     bm_forward = beamsweep(self.origin, v_forward, length, step, step_up, step_down);
393
394     vr = normalize(v_forward + v_right * 0.125);
395     vl = normalize(v_forward - v_right * 0.125);
396
397     bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
398     bm_left  = beamsweep(self.origin, vl, length, step, step_up, step_down);
399
400
401     p = bm_left + bm_right;
402     if(p == 2)
403     {
404         //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
405         //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
406
407         return v_forward;
408     }
409
410     p = 2 - p;
411
412     vr = normalize(v_forward + v_right * p);
413     vl = normalize(v_forward - v_right * p);
414     bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
415     bm_left  = beamsweep(self.origin, vl, length, step, step_up, step_down);
416
417
418     if(bm_left + bm_right < 0.15)
419     {
420         vr = normalize((v_forward*-1) + v_right * 0.75);
421         vl = normalize((v_forward*-1) - v_right * 0.75);
422
423         bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
424         bm_left  = beamsweep(self.origin, vl, length, step, step_up, step_down);
425     }
426
427     //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
428     //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
429
430     bm_forward *= bm_forward;
431     bm_right   *= bm_right;
432     bm_left    *= bm_left;
433
434     vr = vr * bm_right;
435     vl = vl * bm_left;
436
437     return normalize(vr + vl);
438
439 }
440
441
442 //////////////////////////////////////////////
443 //     Testting                             //
444 // Everything below this point is a mess :D //
445 //////////////////////////////////////////////
446 //#define TLIBS_TETSLIBS
447 #ifdef TLIBS_TETSLIBS
448 void flocker_die()
449 {
450         sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
451
452         pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
453
454     self.owner.cnt += 1;
455     self.owner = world;
456
457     self.nextthink = time;
458     self.think = SUB_Remove;
459 }
460
461
462 void flocker_think()
463 {
464     vector dodgemove,swarmmove;
465     vector reprellmove,wandermove,newmove;
466
467     self.angles_x = self.angles_x * -1;
468     makevectors(self.angles);
469     self.angles_x = self.angles_x * -1;
470
471     dodgemove   = steerlib_traceavoid(0.35,1000);
472     swarmmove   = steerlib_flock(500,75,700,500);
473     reprellmove = steerlib_repell(self.owner.enemy.origin+self.enemy.velocity,2000) * 700;
474
475     if(vlen(dodgemove) == 0)
476     {
477         self.pos1 = steerlib_wander(0.5,0.1,self.pos1);
478         wandermove  = self.pos1 * 50;
479     }
480     else
481         self.pos1 = normalize(self.velocity);
482
483     dodgemove = dodgemove * vlen(self.velocity) * 5;
484
485     newmove = swarmmove + reprellmove + wandermove + dodgemove;
486     self.velocity = movelib_inertmove_byspeed(newmove,300,0.2,0.9);
487     //self.velocity  = movelib_inertmove(dodgemove,0.65);
488
489     self.velocity = movelib_dragvec(0.01,0.6);
490
491     self.angles = vectoangles(self.velocity);
492
493     if(self.health <= 0)
494         flocker_die();
495     else
496         self.nextthink = time + 0.1;
497 }
498
499
500 void spawn_flocker()
501 {
502     entity flocker;
503
504     flocker = spawn ();
505
506     setorigin(flocker, self.origin + '0 0 32');
507     setmodel (flocker, "models/turrets/rocket.md3");
508     setsize (flocker, '-3 -3 -3', '3 3 3');
509
510     flocker.flock_id   = self.flock_id;
511     flocker.classname  = "flocker";
512     flocker.owner      = self;
513     flocker.think      = flocker_think;
514     flocker.nextthink  = time + random() * 5;
515     PROJECTILE_MAKETRIGGER(flocker);
516     flocker.movetype   = MOVETYPE_BOUNCEMISSILE;
517     flocker.effects    = EF_LOWPRECISION;
518     flocker.velocity   = randomvec() * 300;
519     flocker.angles     = vectoangles(flocker.velocity);
520     flocker.health     = 10;
521     flocker.pos1      = normalize(flocker.velocity + randomvec() * 0.1);
522
523     self.cnt = self.cnt -1;
524
525 }
526
527 void flockerspawn_think()
528 {
529
530
531     if(self.cnt > 0)
532         spawn_flocker();
533
534     self.nextthink = time + self.delay;
535
536 }
537
538 void flocker_hunter_think()
539 {
540     vector dodgemove,attractmove,newmove;
541     entity e,ee;
542     float d,bd;
543
544     self.angles_x = self.angles_x * -1;
545     makevectors(self.angles);
546     self.angles_x = self.angles_x * -1;
547
548     if(self.enemy)
549     if(vlen(self.enemy.origin - self.origin) < 64)
550     {
551         ee = self.enemy;
552         ee.health = -1;
553         self.enemy = world;
554
555     }
556
557     if(!self.enemy)
558     {
559         e = findchainfloat(flock_id,self.flock_id);
560         while(e)
561         {
562             d = vlen(self.origin - e.origin);
563
564             if(e != self.owner)
565             if(e != ee)
566             if(d > bd)
567             {
568                 self.enemy = e;
569                 bd = d;
570             }
571             e = e.chain;
572         }
573     }
574
575     if(self.enemy)
576         attractmove = steerlib_attract(self.enemy.origin+self.enemy.velocity * 0.1,5000) * 1250;
577     else
578         attractmove = normalize(self.velocity) * 200;
579
580     dodgemove = steerlib_traceavoid(0.35,1500) * vlen(self.velocity);
581
582     newmove = dodgemove + attractmove;
583     self.velocity = movelib_inertmove_byspeed(newmove,1250,0.3,0.7);
584     self.velocity = movelib_dragvec(0.01,0.5);
585
586
587     self.angles = vectoangles(self.velocity);
588     self.nextthink = time + 0.1;
589 }
590
591
592 float globflockcnt;
593 void spawnfunc_flockerspawn()
594 {
595     precache_model ( "models/turrets/rocket.md3");
596     precache_model("models/turrets/c512.md3");
597     ++globflockcnt;
598
599     if(!self.cnt)      self.cnt = 20;
600     if(!self.delay)    self.delay = 0.25;
601     if(!self.flock_id) self.flock_id = globflockcnt;
602
603     self.think     = flockerspawn_think;
604     self.nextthink = time + 0.25;
605
606     self.enemy = spawn();
607
608     setmodel(self.enemy, "models/turrets/rocket.md3");
609     setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
610
611     self.enemy.classname = "FLock Hunter";
612     self.enemy.scale     = 3;
613     self.enemy.effects   = EF_LOWPRECISION;
614     self.enemy.movetype  = MOVETYPE_BOUNCEMISSILE;
615     PROJECTILE_MAKETRIGGER(self.enemy);
616     self.enemy.think     = flocker_hunter_think;
617     self.enemy.nextthink = time + 10;
618     self.enemy.flock_id  = self.flock_id;
619     self.enemy.owner     = self;
620 }
621 #endif
622
623
624