]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/steerlib.qc
Fix removal of the locked waypoint
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / steerlib.qc
1 #include "steerlib.qh"
2 #if defined(CSQC)
3 #elif defined(MENUQC)
4 #elif defined(SVQC)
5     #include "pathlib/utility.qh"
6 #endif
7
8 /**
9     Uniform pull towards a point
10 **/
11 #define steerlib_pull(ent,point) normalize(point - (ent).origin)
12 /*vector steerlib_pull(entity this, vector point)
13 {
14     return normalize(point - this.origin);
15 }*/
16
17 /**
18     Uniform push from a point
19 **/
20 #define steerlib_push(ent,point) normalize(ent.origin - point)
21 /*
22 vector steerlib_push(entity this, vector point)
23 {
24     return normalize(this.origin - point);
25 }
26 */
27 /**
28     Pull toward a point, The further away, the stronger the pull.
29 **/
30 vector steerlib_arrive(entity this, vector point, float maximal_distance)
31 {
32     float distance = bound(0.001,vlen(this.origin - point),maximal_distance);
33     vector direction = normalize(point - this.origin);
34     return  direction * (distance / maximal_distance);
35 }
36
37 /**
38     Pull toward a point increasing the pull the closer we get
39 **/
40 vector steerlib_attract(entity this, vector point, float maximal_distance)
41 {
42     float distance = bound(0.001,vlen(this.origin - point),maximal_distance);
43     vector direction = normalize(point - this.origin);
44
45     return  direction * (1-(distance / maximal_distance));
46 }
47
48 vector steerlib_attract2(entity this, vector point, float min_influense,float max_distance,float max_influense)
49 {
50     float distance  = bound(0.00001,vlen(this.origin - point),max_distance);
51     vector direction = normalize(point - this.origin);
52
53     float 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(this.origin - point);
69
70     distance = bound(0.001,distance,maximal_distance);
71
72     target_direction = normalize(point - this.origin);
73     current_direction = normalize(this.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(entity this, vector point,float maximal_distance)
93 {
94     float distance;
95     vector direction;
96
97     distance = bound(0.001,vlen(this.origin - point),maximal_distance);
98     direction = normalize(this.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(entity this, vector point,float ideal_distance)
107 {
108     float distance;
109     vector direction;
110
111     distance = vlen(this.origin - point);
112
113
114     if(distance < ideal_distance)
115     {
116         direction = normalize(this.origin - point);
117         return direction * (distance / ideal_distance);
118     }
119
120     direction = normalize(point - this.origin);
121     return direction * (ideal_distance / distance);
122
123 }
124
125 /**
126     A random heading in a forward halfcicrle
127
128     use like:
129     this.target = steerlib_wander(256,32,this.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_wander(entity this, float range, float tresh, vector oldpoint)
134 {
135     vector wander_point;
136     wander_point = v_forward - oldpoint;
137
138     if (vdist(wander_point, >, tresh))
139         return oldpoint;
140
141     range = bound(0,range,1);
142
143     wander_point = this.origin + v_forward * 128;
144     wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
145
146     return normalize(wander_point - this.origin);
147 }
148
149 /**
150     Dodge a point. dont work to well.
151 **/
152 vector steerlib_dodge(entity this, vector point, vector dodge_dir, float min_distance)
153 {
154     float distance;
155
156     distance = max(vlen(this.origin - point),min_distance);
157     if (min_distance < distance)
158         return '0 0 0';
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(entity this, float _radius, float standoff,float separation_force,float flock_force)
169 {
170     entity flock_member;
171     vector push = '0 0 0', pull = '0 0 0';
172     float ccount = 0;
173
174     flock_member = findradius(this.origin, _radius);
175     while(flock_member)
176     {
177         if(flock_member != this)
178         if(flock_member.flock_id == this.flock_id)
179         {
180             ++ccount;
181             push = push + (steerlib_repell(this, flock_member.origin,standoff) * separation_force);
182             pull = pull + (steerlib_arrive(this, 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     flocking by .flock_id
191     Group will move towards the unified direction while keeping close to eachother.
192     xy only version (for ground movers).
193 **/
194 vector steerlib_flock2d(entity this, float _radius, float standoff,float separation_force,float flock_force)
195 {
196     entity flock_member;
197     vector push = '0 0 0', pull = '0 0 0';
198     float ccount = 0;
199
200     flock_member = findradius(this.origin,_radius);
201     while(flock_member)
202     {
203         if(flock_member != this)
204         if(flock_member.flock_id == this.flock_id)
205         {
206             ++ccount;
207             push = push + (steerlib_repell(this, flock_member.origin, standoff) * separation_force);
208             pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
209         }
210         flock_member = flock_member.chain;
211     }
212
213     push.z = 0;
214     pull.z = 0;
215
216     return push + (pull * (1 / ccount));
217 }
218
219 /**
220     All members want to be in the center, and keep away from eachother.
221     The furtehr form the center the more they want to be there.
222
223     This results in a aligned movement (?!) much like flocking.
224 **/
225 vector steerlib_swarm(entity this, float _radius, float standoff,float separation_force,float swarm_force)
226 {
227     entity swarm_member;
228     vector force = '0 0 0', center = '0 0 0';
229     float ccount = 0;
230
231     swarm_member = findradius(this.origin,_radius);
232
233     while(swarm_member)
234     {
235         if(swarm_member.flock_id == this.flock_id)
236         {
237             ++ccount;
238             center = center + swarm_member.origin;
239             force = force + (steerlib_repell(this, swarm_member.origin,standoff) * separation_force);
240         }
241         swarm_member = swarm_member.chain;
242     }
243
244     center = center * (1 / ccount);
245     force = force + (steerlib_arrive(this, center,_radius) * swarm_force);
246
247     return force;
248 }
249
250 /**
251     Steer towards the direction least obstructed.
252     Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
253     You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
254 **/
255 vector steerlib_traceavoid(entity this, float pitch,float length)
256 {
257     vector vup_left,vup_right,vdown_left,vdown_right;
258     float fup_left,fup_right,fdown_left,fdown_right;
259     vector upwish,downwish,leftwish,rightwish;
260     vector v_left,v_down;
261
262
263     v_left = v_right * -1;
264     v_down = v_up * -1;
265
266     vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
267     traceline(this.origin, this.origin +  vup_left,MOVE_NOMONSTERS,this);
268     fup_left = trace_fraction;
269
270     //te_lightning1(NULL,this.origin, trace_endpos);
271
272     vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
273     traceline(this.origin,this.origin + vup_right ,MOVE_NOMONSTERS,this);
274     fup_right = trace_fraction;
275
276     //te_lightning1(NULL,this.origin, trace_endpos);
277
278     vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
279     traceline(this.origin,this.origin + vdown_left,MOVE_NOMONSTERS,this);
280     fdown_left = trace_fraction;
281
282     //te_lightning1(NULL,this.origin, trace_endpos);
283
284     vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
285     traceline(this.origin,this.origin + vdown_right,MOVE_NOMONSTERS,this);
286     fdown_right = trace_fraction;
287
288     //te_lightning1(NULL,this.origin, trace_endpos);
289     upwish    = v_up    * (fup_left   + fup_right);
290     downwish  = v_down  * (fdown_left + fdown_right);
291     leftwish  = v_left  * (fup_left   + fdown_left);
292     rightwish = v_right * (fup_right  + fdown_right);
293
294     return (upwish+leftwish+downwish+rightwish) * 0.25;
295
296 }
297
298 /**
299     Steer towards the direction least obstructed.
300     Run tracelines in a forward trident, bias each direction negative if something is found there.
301 **/
302 vector steerlib_traceavoid_flat(entity this, float pitch, float length, vector vofs)
303 {
304     vector vt_left, vt_right,vt_front;
305     float f_left, f_right,f_front;
306     vector leftwish, rightwish,frontwish, v_left;
307
308     v_left = v_right * -1;
309
310
311     vt_front = v_forward * length;
312     traceline(this.origin + vofs, this.origin + vofs + vt_front,MOVE_NOMONSTERS,this);
313     f_front = trace_fraction;
314
315     vt_left = (v_forward + (v_left * pitch)) * length;
316     traceline(this.origin + vofs, this.origin + vofs + vt_left,MOVE_NOMONSTERS,this);
317     f_left = trace_fraction;
318
319     //te_lightning1(NULL,this.origin, trace_endpos);
320
321     vt_right = (v_forward + (v_right * pitch)) * length;
322     traceline(this.origin + vofs, this.origin + vofs + vt_right ,MOVE_NOMONSTERS,this);
323     f_right = trace_fraction;
324
325     //te_lightning1(NULL,this.origin, trace_endpos);
326
327     leftwish  = v_left    * f_left;
328     rightwish = v_right   * f_right;
329     frontwish = v_forward * f_front;
330
331     return normalize(leftwish + rightwish + frontwish);
332 }
333
334 //#define BEAMSTEER_VISUAL
335 float beamsweep(entity this, vector from, vector dir,float length, float step,float step_up, float step_down)
336 {
337     float i;
338     vector a, b, u, d;
339
340     u = '0 0 1' * step_up;
341     d = '0 0 1' * step_down;
342
343     traceline(from + u, from - d,MOVE_NORMAL,this);
344     if(trace_fraction == 1.0)
345         return 0;
346
347     if(!location_isok(trace_endpos, false, false))
348         return 0;
349
350     a = trace_endpos;
351     for(i = 0; i < length; i += step)
352     {
353
354         b = a + dir * step;
355         tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,this);
356         if(trace_fraction != 1.0)
357             return i / length;
358
359         traceline(b + u, b - d,MOVE_NORMAL,this);
360         if(trace_fraction == 1.0)
361             return i / length;
362
363         if(!location_isok(trace_endpos, false, false))
364             return i / length;
365 #ifdef BEAMSTEER_VISUAL
366         te_lightning1(NULL,a+u,b+u);
367         te_lightning1(NULL,b+u,b-d);
368 #endif
369         a = trace_endpos;
370     }
371
372     return 1;
373 }
374
375 vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
376 {
377     float bm_forward, bm_right, bm_left,p;
378     vector vr,vl;
379
380     dir.z *= 0.15;
381     vr = vectoangles(dir);
382     //vr_x *= -1;
383
384     tracebox(this.origin + '0 0 1' * step_up, this.mins, this.maxs, ('0 0 1' * step_up) + this.origin +  (dir * length), MOVE_NOMONSTERS, this);
385     if(trace_fraction == 1.0)
386     {
387         //te_lightning1(this,this.origin,this.origin +  (dir * length));
388         return dir;
389     }
390
391     makevectors(vr);
392     bm_forward = beamsweep(this, this.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(this, this.origin, vr, length, step, step_up, step_down);
398     bm_left  = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
399
400
401     p = bm_left + bm_right;
402     if(p == 2)
403     {
404         //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
405         //te_lightning1(this.tur_head,this.origin + '0 0 32',this.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(this, this.origin, vr, length, step, step_up, step_down);
415     bm_left  = beamsweep(this, this.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.90);
421         vl = normalize((v_forward*-1) - v_right * 0.90);
422
423         bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
424         bm_left  = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
425     }
426
427     //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
428     //te_lightning1(this.tur_head,this.origin + '0 0 32',this.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 }