]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/steerlib.qc
added dpm weapon support
[divverent/nexuiz.git] / data / qcsrc / server / steerlib.qc
1 /**
2     Uniform pull towards a point
3 **/
4 vector steerlib_pull(vector point)
5 {
6     return normalize(point - self.origin);
7 }
8
9 /**
10     Uniform push from a point
11 **/
12 vector steerlib_push(vector point)
13 {
14     return normalize(self.origin - point);
15 }
16
17 /**
18     Pull toward a point, The further away, the stronger the pull.
19 **/
20 vector steerlib_arrive(vector point,float maximal_distance)
21 {
22     float distance;
23     vector direction;
24
25     distance = bound(0.001,vlen(self.origin - point),maximal_distance);
26     direction = normalize(point - self.origin);
27     return  direction * (distance / maximal_distance);
28 }
29
30 /**
31     Pull toward a point increasing the pull the closer we get
32 **/
33 vector steerlib_attract(vector point, float maximal_distance)
34 {
35     float distance;
36     vector direction;
37
38     distance = bound(0.001,vlen(self.origin - point),maximal_distance);
39     direction = normalize(point - self.origin);
40
41     return  direction * (1-(distance / maximal_distance));
42 }
43
44 vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense)
45 {
46     float distance;
47     vector direction;
48     float influense;
49
50     distance  = bound(0.00001,vlen(self.origin - point),max_distance);
51     direction = normalize(point - self.origin);
52
53     influense = 1 - (distance / max_distance);
54     influense = min_influense + (influense * (max_influense - min_influense));
55
56     return  direction * influense;
57 }
58
59 /*
60 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
61 {
62     //float distance;
63     vector current_direction;
64     vector target_direction;
65     float i_target,i_current;
66
67     if(!distance)
68         distance = vlen(self.origin - point);
69
70     distance = bound(0.001,distance,maximal_distance);
71
72     target_direction = normalize(point - self.origin);
73     current_direction = normalize(self.velocity);
74
75     i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
76     i_current = 1 - i_target;
77
78     // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
79
80     string s;
81     s = ftos(i_target);
82     bprint("IT: ",s,"\n");
83     s = ftos(i_current);
84     bprint("IC  : ",s,"\n");
85
86     return  normalize((target_direction * i_target) + (current_direction * i_current));
87 }
88 */
89 /**
90     Move away from a point.
91 **/
92 vector steerlib_repell(vector point,float maximal_distance)
93 {
94     float distance;
95     vector direction;
96
97     distance = bound(0.001,vlen(self.origin - point),maximal_distance);
98     direction = normalize(self.origin - point);
99
100     return  direction * (1-(distance / maximal_distance));
101 }
102
103 /**
104     Try to keep at ideal_distance away from point
105 **/
106 vector steerlib_standoff(vector point,float ideal_distance)
107 {
108     float distance;
109     vector direction;
110
111     distance = vlen(self.origin - point);
112
113
114     if(distance < ideal_distance)
115     {
116         direction = normalize(self.origin - point);
117         return direction * (distance / ideal_distance);
118     }
119
120     direction = normalize(point - self.origin);
121     return direction * (ideal_distance / distance);
122
123 }
124
125 /**
126     A random heading in a forward halfcicrle
127
128     use like:
129     self.target = steerlib_waner(256,32,self.target)
130
131     where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
132 **/
133 vector steerlib_waner(float range,float tresh,vector oldpoint)
134 {
135     vector wander_point;
136     wander_point = v_forward - oldpoint;
137
138     if (vlen(wander_point) > tresh)
139         return oldpoint;
140
141     range = bound(0,range,1);
142
143     wander_point = self.origin + v_forward * 128;
144     wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
145
146     return normalize(wander_point - self.origin);
147 }
148
149 /**
150     Dodge a point. dont work to well.
151 **/
152 vector steerlib_dodge(vector point,vector dodge_dir,float min_distance)
153 {
154     float distance;
155
156     distance = max(vlen(self.origin - point),min_distance);
157
158     return dodge_dir * (min_distance/distance);
159 }
160
161 /**
162     flocking by .flock_id
163     Group will move towards the unified direction while keeping close to eachother.
164 **/
165 .float flock_id;
166 vector steerlib_flock(float radius, float standoff,float separation_force,float flock_force)
167 {
168     entity flock_member;
169     vector push,pull;
170     float ccount;
171
172     flock_member = findradius(self.origin,radius);
173     while(flock_member)
174     {
175         if(flock_member != self)
176         if(flock_member.flock_id == self.flock_id)
177         {
178             ++ccount;
179             push = push + (steerlib_repell(flock_member.origin,standoff) * separation_force);
180             pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity,radius) * flock_force);
181         }
182         flock_member = flock_member.chain;
183     }
184     return push + (pull* (1 / ccount));
185 }
186
187 /**
188     All members want to be in the center, and keep away from eachother.
189     The furtehr form the center the more they want to be there.
190
191     This results in a aligned movement (?!) much like flocking.
192 **/
193 vector steerlib_swarm(float radius, float standoff,float separation_force,float swarm_force)
194 {
195     entity swarm_member;
196     vector force,center;
197     float ccount;
198
199     swarm_member = findradius(self.origin,radius);
200
201     while(swarm_member)
202     {
203         if(swarm_member.flock_id == self.flock_id)
204         {
205             ++ccount;
206             center = center + swarm_member.origin;
207             force = force + (steerlib_repell(swarm_member.origin,standoff) * separation_force);
208         }
209         swarm_member = swarm_member.chain;
210     }
211
212     center = center * (1 / ccount);
213     force = force + (steerlib_arrive(center,radius) * swarm_force);
214
215     return force;
216 }
217
218 /**
219     Steer towards the direction least obstructed.
220     Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
221 **/
222 vector steerlib_traceavoid(float pitch,float length)
223 {
224     vector vup_left,vup_right,vdown_left,vdown_right;
225     float fup_left,fup_right,fdown_left,fdown_right;
226     vector upwish,downwish,leftwish,rightwish;
227     vector v_left,v_down;
228
229     v_left = v_right * -1;
230     v_down = v_up * -1;
231
232     vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
233     traceline(self.origin, self.origin +  vup_left,MOVE_NOMONSTERS,self);
234     fup_left = trace_fraction;
235
236     //te_lightning1(world,self.origin, trace_endpos);
237
238     vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
239     traceline(self.origin,self.origin + vup_right ,MOVE_NOMONSTERS,self);
240     fup_right = trace_fraction;
241
242     //te_lightning1(world,self.origin, trace_endpos);
243
244     vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
245     traceline(self.origin,self.origin + vdown_left,MOVE_NOMONSTERS,self);
246     fdown_left = trace_fraction;
247
248     //te_lightning1(world,self.origin, trace_endpos);
249
250     vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
251     traceline(self.origin,self.origin + vdown_right,MOVE_NOMONSTERS,self);
252     fdown_right = trace_fraction;
253
254     //te_lightning1(world,self.origin, trace_endpos);
255
256     upwish    = v_up    * (fup_left   + fup_right);
257     downwish  = v_down  * (fdown_left + fdown_right);
258     leftwish  = v_left  * (fup_left   + fdown_left);
259     rightwish = v_right * (fup_right  + fdown_right);
260
261     return (upwish+leftwish+downwish+rightwish) * 0.25;
262
263 }
264
265
266
267 //////////////////////////////////////////////
268 //     Testting                             //
269 // Everything below this point is a mess :D //
270 //////////////////////////////////////////////
271 //#define TLIBS_TETSLIBS
272 #ifdef TLIBS_TETSLIBS
273 void flocker_die()
274 {
275         sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
276
277         pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
278
279     self.owner.cnt += 1;
280     self.owner = world;
281
282     self.nextthink = time;
283     self.think = SUB_Remove;
284 }
285
286
287 void flocker_think()
288 {
289     vector dodgemove,swarmmove;
290     vector reprellmove,wandermove,newmove;
291
292     self.angles_x = self.angles_x * -1;
293     makevectors(self.angles);
294     self.angles_x = self.angles_x * -1;
295
296     dodgemove   = steerlib_traceavoid(0.35,1000);
297     swarmmove   = steerlib_flock(500,75,700,500);
298     reprellmove = steerlib_repell(self.owner.enemy.origin+self.enemy.velocity,2000) * 700;
299
300     if(vlen(dodgemove) == 0)
301     {
302         self.pos1 = steerlib_waner(0.5,0.1,self.pos1);
303         wandermove  = self.pos1 * 50;
304     }
305     else
306         self.pos1 = normalize(self.velocity);
307
308     dodgemove = dodgemove * vlen(self.velocity) * 5;
309
310     newmove = swarmmove + reprellmove + wandermove + dodgemove;
311     self.velocity = movelib_inertmove_byspeed(newmove,300,0.2,0.9);
312     //self.velocity  = movelib_inertmove(dodgemove,0.65);
313
314     self.velocity = movelib_dragvec(0.01,0.6);
315
316     self.angles = vectoangles(self.velocity);
317
318     if(self.health <= 0)
319         flocker_die();
320     else
321         self.nextthink = time + 0.1;
322 }
323
324
325 void spawn_flocker()
326 {
327     entity flocker;
328
329     flocker = spawn ();
330
331     setorigin(flocker, self.origin + '0 0 32');
332     setmodel (flocker, "models/turrets/rocket.md3");
333     setsize (flocker, '-3 -3 -3', '3 3 3');
334
335     flocker.flock_id   = self.flock_id;
336     flocker.classname  = "flocker";
337     flocker.owner      = self;
338     flocker.think      = flocker_think;
339     flocker.nextthink  = time + random() * 5;
340     flocker.solid      = SOLID_BBOX;
341     flocker.movetype   = MOVETYPE_BOUNCEMISSILE;
342     flocker.effects    = EF_LOWPRECISION;
343     flocker.velocity   = randomvec() * 300;
344     flocker.angles     = vectoangles(flocker.velocity);
345     flocker.health     = 10;
346     flocker.pos1      = normalize(flocker.velocity + randomvec() * 0.1);
347
348     self.cnt = self.cnt -1;
349
350 }
351
352 void flockerspawn_think()
353 {
354
355
356     if(self.cnt > 0)
357         spawn_flocker();
358
359     self.nextthink = time + self.delay;
360
361 }
362
363 void flocker_hunter_think()
364 {
365     vector dodgemove,attractmove,newmove;
366     entity e,ee;
367     float d,bd;
368
369     self.angles_x = self.angles_x * -1;
370     makevectors(self.angles);
371     self.angles_x = self.angles_x * -1;
372
373     if(self.enemy)
374     if(vlen(self.enemy.origin - self.origin) < 64)
375     {
376         ee = self.enemy;
377         ee.health = -1;
378         self.enemy = world;
379
380     }
381
382     if(!self.enemy)
383     {
384         e = findchainfloat(flock_id,self.flock_id);
385         while(e)
386         {
387             d = vlen(self.origin - e.origin);
388
389             if(e != self.owner)
390             if(e != ee)
391             if(d > bd)
392             {
393                 self.enemy = e;
394                 bd = d;
395             }
396             e = e.chain;
397         }
398     }
399
400     if(self.enemy)
401         attractmove = steerlib_attract(self.enemy.origin+self.enemy.velocity * 0.1,5000) * 1250;
402     else
403         attractmove = normalize(self.velocity) * 200;
404
405     dodgemove = steerlib_traceavoid(0.35,1500) * vlen(self.velocity);
406
407     newmove = dodgemove + attractmove;
408     self.velocity = movelib_inertmove_byspeed(newmove,1250,0.3,0.7);
409     self.velocity = movelib_dragvec(0.01,0.5);
410
411
412     self.angles = vectoangles(self.velocity);
413     self.nextthink = time + 0.1;
414 }
415
416
417 float globflockcnt;
418 void spawnfunc_flockerspawn()
419 {
420     precache_model ( "models/turrets/rocket.md3");
421     precache_model("models/turrets/c512.md3");
422     ++globflockcnt;
423
424     if(!self.cnt)      self.cnt = 20;
425     if(!self.delay)    self.delay = 0.25;
426     if(!self.flock_id) self.flock_id = globflockcnt;
427
428     self.think     = flockerspawn_think;
429     self.nextthink = time + 0.25;
430
431     self.enemy = spawn();
432
433     setmodel(self.enemy, "models/turrets/rocket.md3");
434     setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
435
436     self.enemy.classname = "FLock Hunter";
437     self.enemy.scale     = 3;
438     self.enemy.effects   = EF_LOWPRECISION;
439     self.enemy.movetype  = MOVETYPE_BOUNCEMISSILE;
440     self.enemy.solid     = SOLID_BBOX;
441     self.enemy.think     = flocker_hunter_think;
442     self.enemy.nextthink = time + 10;
443     self.enemy.flock_id  = self.flock_id;
444     self.enemy.owner     = self;
445 }
446 #endif
447
448