]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/steerlib.qc
Better walker and ewheel.
[divverent/nexuiz.git] / data / qcsrc / server / steerlib.qc
1 .vector steerto;\r
2 \r
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_waner(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_waner(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 }\r
266
267 /**\r
268     Steer towards the direction least obstructed.\r
269     Run two tracelines in a forward trident, bias each diretion negative if something is found there.\r
270 **/\r
271 vector steerlib_traceavoid_flat(float pitch, float length, vector vofs)\r
272 {\r
273     vector vt_left, vt_right,vt_front;\r
274     float f_left, f_right,f_front;\r
275     vector leftwish, rightwish,frontwish, v_left;\r
276 \r
277     v_left = v_right * -1;\r
278 \r
279 \r
280     vt_front = v_forward * length;\r
281     traceline(self.origin + vofs, self.origin + vofs + vt_front,MOVE_NOMONSTERS,self);\r
282     f_front = trace_fraction;\r
283 \r
284     vt_left = (v_forward + (v_left * pitch)) * length;\r
285     traceline(self.origin + vofs, self.origin + vofs + vt_left,MOVE_NOMONSTERS,self);\r
286     f_left = trace_fraction;\r
287 \r
288     //te_lightning1(world,self.origin, trace_endpos);\r
289 \r
290     vt_right = (v_forward + (v_right * pitch)) * length;\r
291     traceline(self.origin + vofs, self.origin + vofs + vt_right ,MOVE_NOMONSTERS,self);\r
292     f_right = trace_fraction;\r
293 \r
294     //te_lightning1(world,self.origin, trace_endpos);\r
295 \r
296     leftwish  = v_left    * f_left;\r
297     rightwish = v_right   * f_right;\r
298     frontwish = v_forward * f_front;\r
299 \r
300     return normalize(leftwish + rightwish + frontwish);\r
301 \r
302 }\r
303 \r
304
305
306
307 //////////////////////////////////////////////
308 //     Testting                             //
309 // Everything below this point is a mess :D //
310 //////////////////////////////////////////////
311 //#define TLIBS_TETSLIBS
312 #ifdef TLIBS_TETSLIBS
313 void flocker_die()
314 {
315         sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
316
317         pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
318
319     self.owner.cnt += 1;
320     self.owner = world;
321
322     self.nextthink = time;
323     self.think = SUB_Remove;
324 }
325
326
327 void flocker_think()
328 {
329     vector dodgemove,swarmmove;
330     vector reprellmove,wandermove,newmove;
331
332     self.angles_x = self.angles_x * -1;
333     makevectors(self.angles);
334     self.angles_x = self.angles_x * -1;
335
336     dodgemove   = steerlib_traceavoid(0.35,1000);
337     swarmmove   = steerlib_flock(500,75,700,500);
338     reprellmove = steerlib_repell(self.owner.enemy.origin+self.enemy.velocity,2000) * 700;
339
340     if(vlen(dodgemove) == 0)
341     {
342         self.pos1 = steerlib_waner(0.5,0.1,self.pos1);
343         wandermove  = self.pos1 * 50;
344     }
345     else
346         self.pos1 = normalize(self.velocity);
347
348     dodgemove = dodgemove * vlen(self.velocity) * 5;
349
350     newmove = swarmmove + reprellmove + wandermove + dodgemove;
351     self.velocity = movelib_inertmove_byspeed(newmove,300,0.2,0.9);
352     //self.velocity  = movelib_inertmove(dodgemove,0.65);
353
354     self.velocity = movelib_dragvec(0.01,0.6);
355
356     self.angles = vectoangles(self.velocity);
357
358     if(self.health <= 0)
359         flocker_die();
360     else
361         self.nextthink = time + 0.1;
362 }
363
364
365 void spawn_flocker()
366 {
367     entity flocker;
368
369     flocker = spawn ();
370
371     setorigin(flocker, self.origin + '0 0 32');
372     setmodel (flocker, "models/turrets/rocket.md3");
373     setsize (flocker, '-3 -3 -3', '3 3 3');
374
375     flocker.flock_id   = self.flock_id;
376     flocker.classname  = "flocker";
377     flocker.owner      = self;
378     flocker.think      = flocker_think;
379     flocker.nextthink  = time + random() * 5;
380     flocker.solid      = SOLID_BBOX;
381     flocker.movetype   = MOVETYPE_BOUNCEMISSILE;
382     flocker.effects    = EF_LOWPRECISION;
383     flocker.velocity   = randomvec() * 300;
384     flocker.angles     = vectoangles(flocker.velocity);
385     flocker.health     = 10;
386     flocker.pos1      = normalize(flocker.velocity + randomvec() * 0.1);
387
388     self.cnt = self.cnt -1;
389
390 }
391
392 void flockerspawn_think()
393 {
394
395
396     if(self.cnt > 0)
397         spawn_flocker();
398
399     self.nextthink = time + self.delay;
400
401 }
402
403 void flocker_hunter_think()
404 {
405     vector dodgemove,attractmove,newmove;
406     entity e,ee;
407     float d,bd;
408
409     self.angles_x = self.angles_x * -1;
410     makevectors(self.angles);
411     self.angles_x = self.angles_x * -1;
412
413     if(self.enemy)
414     if(vlen(self.enemy.origin - self.origin) < 64)
415     {
416         ee = self.enemy;
417         ee.health = -1;
418         self.enemy = world;
419
420     }
421
422     if(!self.enemy)
423     {
424         e = findchainfloat(flock_id,self.flock_id);
425         while(e)
426         {
427             d = vlen(self.origin - e.origin);
428
429             if(e != self.owner)
430             if(e != ee)
431             if(d > bd)
432             {
433                 self.enemy = e;
434                 bd = d;
435             }
436             e = e.chain;
437         }
438     }
439
440     if(self.enemy)
441         attractmove = steerlib_attract(self.enemy.origin+self.enemy.velocity * 0.1,5000) * 1250;
442     else
443         attractmove = normalize(self.velocity) * 200;
444
445     dodgemove = steerlib_traceavoid(0.35,1500) * vlen(self.velocity);
446
447     newmove = dodgemove + attractmove;
448     self.velocity = movelib_inertmove_byspeed(newmove,1250,0.3,0.7);
449     self.velocity = movelib_dragvec(0.01,0.5);
450
451
452     self.angles = vectoangles(self.velocity);
453     self.nextthink = time + 0.1;
454 }
455
456
457 float globflockcnt;
458 void spawnfunc_flockerspawn()
459 {
460     precache_model ( "models/turrets/rocket.md3");
461     precache_model("models/turrets/c512.md3");
462     ++globflockcnt;
463
464     if(!self.cnt)      self.cnt = 20;
465     if(!self.delay)    self.delay = 0.25;
466     if(!self.flock_id) self.flock_id = globflockcnt;
467
468     self.think     = flockerspawn_think;
469     self.nextthink = time + 0.25;
470
471     self.enemy = spawn();
472
473     setmodel(self.enemy, "models/turrets/rocket.md3");
474     setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
475
476     self.enemy.classname = "FLock Hunter";
477     self.enemy.scale     = 3;
478     self.enemy.effects   = EF_LOWPRECISION;
479     self.enemy.movetype  = MOVETYPE_BOUNCEMISSILE;
480     self.enemy.solid     = SOLID_BBOX;
481     self.enemy.think     = flocker_hunter_think;
482     self.enemy.nextthink = time + 10;
483     self.enemy.flock_id  = self.flock_id;
484     self.enemy.owner     = self;
485 }
486 #endif
487
488