5 #include "pathlib/utility.qh"
9 Uniform pull towards a point
11 #define steerlib_pull(ent,point) normalize(point - (ent).origin)
12 /*vector steerlib_pull(entity this, vector point)
14 return normalize(point - this.origin);
18 Uniform push from a point
20 #define steerlib_push(ent,point) normalize((ent).origin - point)
22 vector steerlib_push(entity this, vector point)
24 return normalize(this.origin - point);
28 Pull toward a point, The further away, the stronger the pull.
30 vector steerlib_arrive(entity this, vector point, float maximal_distance)
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);
38 Pull toward a point increasing the pull the closer we get
40 vector steerlib_attract(entity this, vector point, float maximal_distance)
42 float distance = bound(0.001, vlen(this.origin - point), maximal_distance);
43 vector direction = normalize(point - this.origin);
45 return direction * (1 - (distance / maximal_distance));
48 vector steerlib_attract2(entity this, vector point, float min_influense, float max_distance, float max_influense)
50 float distance = bound(0.00001, vlen(this.origin - point), max_distance);
51 vector direction = normalize(point - this.origin);
53 float influense = 1 - (distance / max_distance);
54 influense = min_influense + (influense * (max_influense - min_influense));
56 return direction * influense;
60 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
63 vector current_direction;
64 vector target_direction;
65 float i_target,i_current;
68 distance = vlen(this.origin - point);
70 distance = bound(0.001,distance,maximal_distance);
72 target_direction = normalize(point - this.origin);
73 current_direction = normalize(this.velocity);
75 i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
76 i_current = 1 - i_target;
78 // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
82 bprint("IT: ",s,"\n");
84 bprint("IC : ",s,"\n");
86 return normalize((target_direction * i_target) + (current_direction * i_current));
90 Move away from a point.
92 vector steerlib_repel(entity this, vector point, float maximal_distance)
94 float distance = bound(0.001, vlen(this.origin - point), maximal_distance);
95 vector direction = normalize(this.origin - point);
97 return direction * (1 - (distance / maximal_distance));
101 Try to keep at ideal_distance away from point
103 vector steerlib_standoff(entity this, vector point, float ideal_distance)
106 float distance = vlen(this.origin - point);
108 if(distance < ideal_distance)
110 direction = normalize(this.origin - point);
111 return direction * (distance / ideal_distance);
114 direction = normalize(point - this.origin);
115 return direction * (ideal_distance / distance);
120 A random heading in a forward semicircle
123 this.target = steerlib_wander(256, 32, this.target)
125 where range is the circle radius and threshold is how close we need to be to pick a new heading.
126 Assumes v_forward is set by makevectors
128 vector steerlib_wander(entity this, float range, float threshold, vector oldpoint)
130 vector wander_point = v_forward - oldpoint;
132 if (vdist(wander_point, >, threshold))
135 range = bound(0, range, 1);
137 wander_point = this.origin + v_forward * 128;
138 wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
140 return normalize(wander_point - this.origin);
144 Dodge a point NOTE: doesn't work well
146 vector steerlib_dodge(entity this, vector point, vector dodge_dir, float min_distance)
148 float distance = max(vlen(this.origin - point), min_distance);
149 if (min_distance < distance)
152 return dodge_dir * (min_distance / distance);
156 flocking by .flock_id
157 Group will move towards the unified direction while keeping close to eachother.
160 vector steerlib_flock(entity this, float _radius, float standoff, float separation_force, float flock_force)
162 vector push = '0 0 0', pull = '0 0 0';
165 entity flock_member = findradius(this.origin, _radius);
168 if(flock_member != this)
169 if(flock_member.flock_id == this.flock_id)
172 push = push + (steerlib_repel(this, flock_member.origin,standoff) * separation_force);
173 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
175 flock_member = flock_member.chain;
177 return push + (pull* (1 / ccount));
181 flocking by .flock_id
182 Group will move towards the unified direction while keeping close to eachother.
183 xy only version (for ground movers).
185 vector steerlib_flock2d(entity this, float _radius, float standoff, float separation_force, float flock_force)
187 vector push = '0 0 0', pull = '0 0 0';
190 entity flock_member = findradius(this.origin,_radius);
193 if(flock_member != this)
194 if(flock_member.flock_id == this.flock_id)
197 push = push + (steerlib_repel(this, flock_member.origin, standoff) * separation_force);
198 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
200 flock_member = flock_member.chain;
206 return push + (pull * (1 / ccount));
210 All members want to be in the center, and keep away from eachother.
211 The further from the center the more they want to be there.
213 This results in a aligned movement (?!) much like flocking.
215 vector steerlib_swarm(entity this, float _radius, float standoff, float separation_force, float swarm_force)
217 vector force = '0 0 0', center = '0 0 0';
220 entity swarm_member = findradius(this.origin,_radius);
223 if(swarm_member.flock_id == this.flock_id)
226 center = center + swarm_member.origin;
227 force = force + (steerlib_repel(this, swarm_member.origin,standoff) * separation_force);
229 swarm_member = swarm_member.chain;
232 center = center * (1 / ccount);
233 force = force + (steerlib_arrive(this, center,_radius) * swarm_force);
239 Steer towards the direction least obstructed.
240 Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
241 You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
243 vector steerlib_traceavoid(entity this, float pitch, float length)
245 vector v_left = v_right * -1;
246 vector v_down = v_up * -1;
248 vector vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
249 traceline(this.origin, this.origin + vup_left, MOVE_NOMONSTERS, this);
250 float fup_left = trace_fraction;
252 //te_lightning1(NULL,this.origin, trace_endpos);
254 vector vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
255 traceline(this.origin, this.origin + vup_right, MOVE_NOMONSTERS, this);
256 float fup_right = trace_fraction;
258 //te_lightning1(NULL,this.origin, trace_endpos);
260 vector vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
261 traceline(this.origin, this.origin + vdown_left, MOVE_NOMONSTERS, this);
262 float fdown_left = trace_fraction;
264 //te_lightning1(NULL,this.origin, trace_endpos);
266 vector vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
267 traceline(this.origin, this.origin + vdown_right, MOVE_NOMONSTERS, this);
268 float fdown_right = trace_fraction;
270 //te_lightning1(NULL,this.origin, trace_endpos);
271 vector upwish = v_up * (fup_left + fup_right);
272 vector downwish = v_down * (fdown_left + fdown_right);
273 vector leftwish = v_left * (fup_left + fdown_left);
274 vector rightwish = v_right * (fup_right + fdown_right);
276 return (upwish + leftwish + downwish + rightwish) * 0.25;
281 Steer towards the direction least obstructed.
282 Run tracelines in a forward trident, bias each direction negative if something is found there.
283 You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
285 vector steerlib_traceavoid_flat(entity this, float pitch, float length, vector vofs)
287 vector v_left = v_right * -1;
289 vector vt_front = v_forward * length;
290 traceline(this.origin + vofs, this.origin + vofs + vt_front,MOVE_NOMONSTERS,this);
291 float f_front = trace_fraction;
293 vector vt_left = (v_forward + (v_left * pitch)) * length;
294 traceline(this.origin + vofs, this.origin + vofs + vt_left,MOVE_NOMONSTERS,this);
295 float f_left = trace_fraction;
297 //te_lightning1(NULL,this.origin, trace_endpos);
299 vector vt_right = (v_forward + (v_right * pitch)) * length;
300 traceline(this.origin + vofs, this.origin + vofs + vt_right ,MOVE_NOMONSTERS,this);
301 float f_right = trace_fraction;
303 //te_lightning1(NULL,this.origin, trace_endpos);
305 vector leftwish = v_left * f_left;
306 vector rightwish = v_right * f_right;
307 vector frontwish = v_forward * f_front;
309 return normalize(leftwish + rightwish + frontwish);
312 //#define BEAMSTEER_VISUAL
313 float beamsweep(entity this, vector from, vector dir, float length, float step, float step_up, float step_down)
315 vector u = '0 0 1' * step_up;
316 vector d = '0 0 1' * step_down;
318 traceline(from + u, from - d,MOVE_NORMAL,this);
319 if(trace_fraction == 1.0)
322 if(!location_isok(trace_endpos, false, false))
325 vector a = trace_endpos;
326 for(int i = 0; i < length; i += step)
329 vector b = a + dir * step;
330 tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,this);
331 if(trace_fraction != 1.0)
334 traceline(b + u, b - d,MOVE_NORMAL,this);
335 if(trace_fraction == 1.0)
338 if(!location_isok(trace_endpos, false, false))
340 #ifdef BEAMSTEER_VISUAL
341 te_lightning1(NULL,a+u,b+u);
342 te_lightning1(NULL,b+u,b-d);
350 vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
353 vector vr = vectoangles(dir);
356 tracebox(this.origin + '0 0 1' * step_up, this.mins, this.maxs, ('0 0 1' * step_up) + this.origin + (dir * length), MOVE_NOMONSTERS, this);
357 if(trace_fraction == 1.0)
359 //te_lightning1(this,this.origin,this.origin + (dir * length));
364 float bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
366 vr = normalize(v_forward + v_right * 0.125);
367 vector vl = normalize(v_forward - v_right * 0.125);
369 float bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
370 float bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
372 float p = bm_left + bm_right;
375 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
376 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
383 vr = normalize(v_forward + v_right * p);
384 vl = normalize(v_forward - v_right * p);
385 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
386 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
389 if(bm_left + bm_right < 0.15)
391 vr = normalize((v_forward*-1) + v_right * 0.90);
392 vl = normalize((v_forward*-1) - v_right * 0.90);
394 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
395 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
398 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
399 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
401 bm_forward *= bm_forward;
402 bm_right *= bm_right;
408 return normalize(vr + vl);