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