3 #include <server/pathlib/utility.qh>
6 Uniform pull towards a point
8 #define steerlib_pull(ent,point) normalize(point - (ent).origin)
9 /*vector steerlib_pull(entity this, vector point)
11 return normalize(point - this.origin);
15 Uniform push from a point
17 #define steerlib_push(ent,point) normalize((ent).origin - point)
19 vector steerlib_push(entity this, vector point)
21 return normalize(this.origin - point);
25 Pull toward a point, The further away, the stronger the pull.
27 vector steerlib_arrive(entity this, vector point, float maximal_distance)
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);
35 Pull toward a point increasing the pull the closer we get
37 vector steerlib_attract(entity this, vector point, float maximal_distance)
39 float distance = bound(0.001, vlen(this.origin - point), maximal_distance);
40 vector direction = normalize(point - this.origin);
42 return direction * (1 - (distance / maximal_distance));
45 vector steerlib_attract2(entity this, vector point, float min_influense, float max_distance, float max_influense)
47 float distance = bound(0.00001, vlen(this.origin - point), max_distance);
48 vector direction = normalize(point - this.origin);
50 float influense = 1 - (distance / max_distance);
51 influense = min_influense + (influense * (max_influense - min_influense));
53 return direction * influense;
57 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
60 vector current_direction;
61 vector target_direction;
62 float i_target,i_current;
65 distance = vlen(this.origin - point);
67 distance = bound(0.001,distance,maximal_distance);
69 target_direction = normalize(point - this.origin);
70 current_direction = normalize(this.velocity);
72 i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
73 i_current = 1 - i_target;
75 // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
79 bprint("IT: ",s,"\n");
81 bprint("IC : ",s,"\n");
83 return normalize((target_direction * i_target) + (current_direction * i_current));
87 Move away from a point.
89 vector steerlib_repel(entity this, vector point, float maximal_distance)
91 float distance = bound(0.001, vlen(this.origin - point), maximal_distance);
92 vector direction = normalize(this.origin - point);
94 return direction * (1 - (distance / maximal_distance));
98 Try to keep at ideal_distance away from point
100 vector steerlib_standoff(entity this, vector point, float ideal_distance)
103 float distance = vlen(this.origin - point);
105 if(distance < ideal_distance)
107 direction = normalize(this.origin - point);
108 return direction * (distance / ideal_distance);
111 direction = normalize(point - this.origin);
112 return direction * (ideal_distance / distance);
117 A random heading in a forward semicircle
120 this.target = steerlib_wander(256, 32, this.target)
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
125 vector steerlib_wander(entity this, float range, float threshold, vector oldpoint)
127 vector wander_point = v_forward - oldpoint;
129 if (vdist(wander_point, >, threshold))
132 range = bound(0, range, 1);
134 wander_point = this.origin + v_forward * 128;
135 wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
137 return normalize(wander_point - this.origin);
141 Dodge a point NOTE: doesn't work well
143 vector steerlib_dodge(entity this, vector point, vector dodge_dir, float min_distance)
145 float distance = max(vlen(this.origin - point), min_distance);
146 if (min_distance < distance)
149 return dodge_dir * (min_distance / distance);
153 flocking by .flock_id
154 Group will move towards the unified direction while keeping close to eachother.
157 vector steerlib_flock(entity this, float _radius, float standoff, float separation_force, float flock_force)
159 vector push = '0 0 0', pull = '0 0 0';
162 entity flock_member = findradius(this.origin, _radius);
165 if(flock_member != this)
166 if(flock_member.flock_id == this.flock_id)
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);
172 flock_member = flock_member.chain;
174 return push + (pull* (1 / ccount));
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).
182 vector steerlib_flock2d(entity this, float _radius, float standoff, float separation_force, float flock_force)
184 vector push = '0 0 0', pull = '0 0 0';
187 entity flock_member = findradius(this.origin,_radius);
190 if(flock_member != this)
191 if(flock_member.flock_id == this.flock_id)
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);
197 flock_member = flock_member.chain;
203 return push + (pull * (1 / ccount));
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.
210 This results in a aligned movement (?!) much like flocking.
212 vector steerlib_swarm(entity this, float _radius, float standoff, float separation_force, float swarm_force)
214 vector force = '0 0 0', center = '0 0 0';
217 entity swarm_member = findradius(this.origin,_radius);
220 if(swarm_member.flock_id == this.flock_id)
223 center = center + swarm_member.origin;
224 force = force + (steerlib_repel(this, swarm_member.origin,standoff) * separation_force);
226 swarm_member = swarm_member.chain;
229 center = center * (1 / ccount);
230 force = force + (steerlib_arrive(this, center,_radius) * swarm_force);
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
240 vector steerlib_traceavoid(entity this, float pitch, float length)
242 vector v_left = v_right * -1;
243 vector v_down = v_up * -1;
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;
249 //te_lightning1(NULL,this.origin, trace_endpos);
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;
255 //te_lightning1(NULL,this.origin, trace_endpos);
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;
261 //te_lightning1(NULL,this.origin, trace_endpos);
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;
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);
273 return (upwish + leftwish + downwish + rightwish) * 0.25;
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
282 vector steerlib_traceavoid_flat(entity this, float pitch, float length, vector vofs)
284 vector v_left = v_right * -1;
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;
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;
294 //te_lightning1(NULL,this.origin, trace_endpos);
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;
300 //te_lightning1(NULL,this.origin, trace_endpos);
302 vector leftwish = v_left * f_left;
303 vector rightwish = v_right * f_right;
304 vector frontwish = v_forward * f_front;
306 return normalize(leftwish + rightwish + frontwish);
309 //#define BEAMSTEER_VISUAL
310 float beamsweep(entity this, vector from, vector dir, float length, float step, float step_up, float step_down)
312 vector u = '0 0 1' * step_up;
313 vector d = '0 0 1' * step_down;
315 traceline(from + u, from - d,MOVE_NORMAL,this);
316 if(trace_fraction == 1.0)
319 if(!location_isok(trace_endpos, false, false))
322 vector a = trace_endpos;
323 for(int i = 0; i < length; i += step)
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)
331 traceline(b + u, b - d,MOVE_NORMAL,this);
332 if(trace_fraction == 1.0)
335 if(!location_isok(trace_endpos, false, false))
337 #ifdef BEAMSTEER_VISUAL
338 te_lightning1(NULL,a+u,b+u);
339 te_lightning1(NULL,b+u,b-d);
347 vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
350 vector vr = vectoangles(dir);
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)
356 //te_lightning1(this,this.origin,this.origin + (dir * length));
361 float bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
363 vr = normalize(v_forward + v_right * 0.125);
364 vector vl = normalize(v_forward - v_right * 0.125);
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);
369 float p = bm_left + bm_right;
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);
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);
386 if(bm_left + bm_right < 0.15)
388 vr = normalize((v_forward*-1) + v_right * 0.90);
389 vl = normalize((v_forward*-1) - v_right * 0.90);
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);
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);
398 bm_forward *= bm_forward;
399 bm_right *= bm_right;
405 return normalize(vr + vl);