8 Uniform pull towards a point
10 vector steerlib_pull(entity this, vector point)
12 return normalize(point - this.origin);
16 Uniform push from a point
18 #define steerlib_push(ent,point) normalize(ent.origin - point)
20 vector steerlib_push(entity this, vector point)
22 return normalize(this.origin - point);
26 Pull toward a point, The further away, the stronger the pull.
28 vector steerlib_arrive(entity this, vector point, float maximal_distance)
33 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
34 direction = normalize(point - this.origin);
35 return direction * (distance / maximal_distance);
39 Pull toward a point increasing the pull the closer we get
41 vector steerlib_attract(entity this, vector point, float maximal_distance)
46 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
47 direction = normalize(point - this.origin);
49 return direction * (1-(distance / maximal_distance));
52 vector steerlib_attract2(entity this, vector point, float min_influense,float max_distance,float max_influense)
58 distance = bound(0.00001,vlen(this.origin - point),max_distance);
59 direction = normalize(point - this.origin);
61 influense = 1 - (distance / max_distance);
62 influense = min_influense + (influense * (max_influense - min_influense));
64 return direction * influense;
68 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
71 vector current_direction;
72 vector target_direction;
73 float i_target,i_current;
76 distance = vlen(this.origin - point);
78 distance = bound(0.001,distance,maximal_distance);
80 target_direction = normalize(point - this.origin);
81 current_direction = normalize(this.velocity);
83 i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
84 i_current = 1 - i_target;
86 // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
90 bprint("IT: ",s,"\n");
92 bprint("IC : ",s,"\n");
94 return normalize((target_direction * i_target) + (current_direction * i_current));
98 Move away from a point.
100 vector steerlib_repell(entity this, vector point,float maximal_distance)
105 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
106 direction = normalize(this.origin - point);
108 return direction * (1-(distance / maximal_distance));
112 Try to keep at ideal_distance away from point
114 vector steerlib_standoff(entity this, vector point,float ideal_distance)
119 distance = vlen(this.origin - point);
122 if(distance < ideal_distance)
124 direction = normalize(this.origin - point);
125 return direction * (distance / ideal_distance);
128 direction = normalize(point - this.origin);
129 return direction * (ideal_distance / distance);
134 A random heading in a forward halfcicrle
137 this.target = steerlib_wander(256,32,this.target)
139 where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
141 vector steerlib_wander(entity this, float range, float tresh, vector oldpoint)
144 wander_point = v_forward - oldpoint;
146 if (vlen(wander_point) > tresh)
149 range = bound(0,range,1);
151 wander_point = this.origin + v_forward * 128;
152 wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
154 return normalize(wander_point - this.origin);
158 Dodge a point. dont work to well.
160 vector steerlib_dodge(entity this, vector point, vector dodge_dir, float min_distance)
164 distance = max(vlen(this.origin - point),min_distance);
165 if (min_distance < distance)
168 return dodge_dir * (min_distance/distance);
172 flocking by .flock_id
173 Group will move towards the unified direction while keeping close to eachother.
176 vector steerlib_flock(entity this, float _radius, float standoff,float separation_force,float flock_force)
179 vector push = '0 0 0', pull = '0 0 0';
182 flock_member = findradius(this.origin, _radius);
185 if(flock_member != this)
186 if(flock_member.flock_id == this.flock_id)
189 push = push + (steerlib_repell(this, flock_member.origin,standoff) * separation_force);
190 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
192 flock_member = flock_member.chain;
194 return push + (pull* (1 / ccount));
198 flocking by .flock_id
199 Group will move towards the unified direction while keeping close to eachother.
200 xy only version (for ground movers).
202 vector steerlib_flock2d(entity this, float _radius, float standoff,float separation_force,float flock_force)
205 vector push = '0 0 0', pull = '0 0 0';
208 flock_member = findradius(this.origin,_radius);
211 if(flock_member != this)
212 if(flock_member.flock_id == this.flock_id)
215 push = push + (steerlib_repell(this, flock_member.origin, standoff) * separation_force);
216 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
218 flock_member = flock_member.chain;
224 return push + (pull * (1 / ccount));
228 All members want to be in the center, and keep away from eachother.
229 The furtehr form the center the more they want to be there.
231 This results in a aligned movement (?!) much like flocking.
233 vector steerlib_swarm(entity this, float _radius, float standoff,float separation_force,float swarm_force)
236 vector force = '0 0 0', center = '0 0 0';
239 swarm_member = findradius(this.origin,_radius);
243 if(swarm_member.flock_id == this.flock_id)
246 center = center + swarm_member.origin;
247 force = force + (steerlib_repell(this, swarm_member.origin,standoff) * separation_force);
249 swarm_member = swarm_member.chain;
252 center = center * (1 / ccount);
253 force = force + (steerlib_arrive(this, center,_radius) * swarm_force);
259 Steer towards the direction least obstructed.
260 Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
261 You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
263 vector steerlib_traceavoid(entity this, float pitch,float length)
265 vector vup_left,vup_right,vdown_left,vdown_right;
266 float fup_left,fup_right,fdown_left,fdown_right;
267 vector upwish,downwish,leftwish,rightwish;
268 vector v_left,v_down;
271 v_left = v_right * -1;
274 vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
275 traceline(this.origin, this.origin + vup_left,MOVE_NOMONSTERS,this);
276 fup_left = trace_fraction;
278 //te_lightning1(NULL,this.origin, trace_endpos);
280 vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
281 traceline(this.origin,this.origin + vup_right ,MOVE_NOMONSTERS,this);
282 fup_right = trace_fraction;
284 //te_lightning1(NULL,this.origin, trace_endpos);
286 vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
287 traceline(this.origin,this.origin + vdown_left,MOVE_NOMONSTERS,this);
288 fdown_left = trace_fraction;
290 //te_lightning1(NULL,this.origin, trace_endpos);
292 vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
293 traceline(this.origin,this.origin + vdown_right,MOVE_NOMONSTERS,this);
294 fdown_right = trace_fraction;
296 //te_lightning1(NULL,this.origin, trace_endpos);
297 upwish = v_up * (fup_left + fup_right);
298 downwish = v_down * (fdown_left + fdown_right);
299 leftwish = v_left * (fup_left + fdown_left);
300 rightwish = v_right * (fup_right + fdown_right);
302 return (upwish+leftwish+downwish+rightwish) * 0.25;
307 Steer towards the direction least obstructed.
308 Run tracelines in a forward trident, bias each direction negative if something is found there.
310 vector steerlib_traceavoid_flat(entity this, float pitch, float length, vector vofs)
312 vector vt_left, vt_right,vt_front;
313 float f_left, f_right,f_front;
314 vector leftwish, rightwish,frontwish, v_left;
316 v_left = v_right * -1;
319 vt_front = v_forward * length;
320 traceline(this.origin + vofs, this.origin + vofs + vt_front,MOVE_NOMONSTERS,this);
321 f_front = trace_fraction;
323 vt_left = (v_forward + (v_left * pitch)) * length;
324 traceline(this.origin + vofs, this.origin + vofs + vt_left,MOVE_NOMONSTERS,this);
325 f_left = trace_fraction;
327 //te_lightning1(NULL,this.origin, trace_endpos);
329 vt_right = (v_forward + (v_right * pitch)) * length;
330 traceline(this.origin + vofs, this.origin + vofs + vt_right ,MOVE_NOMONSTERS,this);
331 f_right = trace_fraction;
333 //te_lightning1(NULL,this.origin, trace_endpos);
335 leftwish = v_left * f_left;
336 rightwish = v_right * f_right;
337 frontwish = v_forward * f_front;
339 return normalize(leftwish + rightwish + frontwish);
342 float beamsweep_badpoint(vector point,float waterok)
346 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
349 pc = pointcontents(point);
350 pc2 = pointcontents(point - '0 0 1');
354 case CONTENT_SOLID: break;
355 case CONTENT_SLIME: break;
356 case CONTENT_LAVA: break;
362 if (pc2 == CONTENT_SOLID)
365 if (pc2 == CONTENT_WATER)
381 //#define BEAMSTEER_VISUAL
382 float beamsweep(entity this, vector from, vector dir,float length, float step,float step_up, float step_down)
387 u = '0 0 1' * step_up;
388 d = '0 0 1' * step_down;
390 traceline(from + u, from - d,MOVE_NORMAL,this);
391 if(trace_fraction == 1.0)
394 if(beamsweep_badpoint(trace_endpos,0))
398 for(i = 0; i < length; i += step)
402 tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,this);
403 if(trace_fraction != 1.0)
406 traceline(b + u, b - d,MOVE_NORMAL,this);
407 if(trace_fraction == 1.0)
410 if(beamsweep_badpoint(trace_endpos,0))
412 #ifdef BEAMSTEER_VISUAL
413 te_lightning1(NULL,a+u,b+u);
414 te_lightning1(NULL,b+u,b-d);
422 vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
424 float bm_forward, bm_right, bm_left,p;
428 vr = vectoangles(dir);
431 tracebox(this.origin + '0 0 1' * step_up, this.mins, this.maxs, ('0 0 1' * step_up) + this.origin + (dir * length), MOVE_NOMONSTERS, this);
432 if(trace_fraction == 1.0)
434 //te_lightning1(this,this.origin,this.origin + (dir * length));
439 bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
441 vr = normalize(v_forward + v_right * 0.125);
442 vl = normalize(v_forward - v_right * 0.125);
444 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
445 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
448 p = bm_left + bm_right;
451 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
452 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
459 vr = normalize(v_forward + v_right * p);
460 vl = normalize(v_forward - v_right * p);
461 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
462 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
465 if(bm_left + bm_right < 0.15)
467 vr = normalize((v_forward*-1) + v_right * 0.75);
468 vl = normalize((v_forward*-1) - v_right * 0.75);
470 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
471 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
474 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
475 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
477 bm_forward *= bm_forward;
478 bm_right *= bm_right;
484 return normalize(vr + vl);
489 //////////////////////////////////////////////
491 // Everything below this point is a mess :D //
492 //////////////////////////////////////////////
493 //#define TLIBS_TETSLIBS
494 #ifdef TLIBS_TETSLIBS
495 void flocker_die(entity this)
497 Send_Effect(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
502 this.nextthink = time;
503 setthink(this, SUB_Remove);
507 void flocker_think(entity this)
509 vector dodgemove,swarmmove;
510 vector reprellmove,wandermove,newmove;
512 this.angles_x = this.angles.x * -1;
513 makevectors(this.angles);
514 this.angles_x = this.angles.x * -1;
516 dodgemove = steerlib_traceavoid(this, 0.35,1000);
517 swarmmove = steerlib_flock(this, 500,75,700,500);
518 reprellmove = steerlib_repell(this, this.owner.enemy.origin+this.enemy.velocity,2000) * 700;
520 if(dodgemove == '0 0 0')
522 this.pos1 = steerlib_wander(this, 0.5,0.1,this.pos1);
523 wandermove = this.pos1 * 50;
526 this.pos1 = normalize(this.velocity);
528 dodgemove = dodgemove * vlen(this.velocity) * 5;
530 newmove = swarmmove + reprellmove + wandermove + dodgemove;
531 this.velocity = movelib_inertmove_byspeed(this, newmove,300,0.2,0.9);
532 //this.velocity = movelib_inertmove(this, dodgemove,0.65);
534 this.velocity = movelib_dragvec(this, 0.01,0.6);
536 this.angles = vectoangles(this.velocity);
541 this.nextthink = time + 0.1;
544 MODEL(FLOCKER, "models/turrets/rocket.md3");
546 void spawn_flocker(entity this)
548 entity flocker = new(flocker);
550 setorigin(flocker, this.origin + '0 0 32');
551 setmodel (flocker, MDL_FLOCKER);
552 setsize (flocker, '-3 -3 -3', '3 3 3');
554 flocker.flock_id = this.flock_id;
555 flocker.owner = this;
556 setthink(flocker, flocker_think);
557 flocker.nextthink = time + random() * 5;
558 PROJECTILE_MAKETRIGGER(flocker);
559 set_movetype(flocker, MOVETYPE_BOUNCEMISSILE);
560 flocker.effects = EF_LOWPRECISION;
561 flocker.velocity = randomvec() * 300;
562 flocker.angles = vectoangles(flocker.velocity);
564 flocker.pos1 = normalize(flocker.velocity + randomvec() * 0.1);
566 this.cnt = this.cnt -1;
570 void flockerspawn_think(entity this)
575 this.nextthink = time + this.delay;
579 void flocker_hunter_think(entity this)
581 vector dodgemove,attractmove,newmove;
584 this.angles_x = this.angles.x * -1;
585 makevectors(this.angles);
586 this.angles_x = this.angles.x * -1;
589 if(vdist(this.enemy.origin - this.origin, <, 64))
599 FOREACH_ENTITY_FLOAT(flock_id, this.flock_id,
601 if(it == this.owner || it == ee)
604 if(!this.enemy || vlen2(this.origin - it.origin) > vlen2(this.origin - this.enemy.origin))
610 attractmove = steerlib_attract(this, this.enemy.origin+this.enemy.velocity * 0.1,5000) * 1250;
612 attractmove = normalize(this.velocity) * 200;
614 dodgemove = steerlib_traceavoid(this, 0.35,1500) * vlen(this.velocity);
616 newmove = dodgemove + attractmove;
617 this.velocity = movelib_inertmove_byspeed(this, newmove,1250,0.3,0.7);
618 this.velocity = movelib_dragvec(this, 0.01,0.5);
620 this.angles = vectoangles(this.velocity);
621 this.nextthink = time + 0.1;
626 spawnfunc(flockerspawn)
630 if(!this.cnt) this.cnt = 20;
631 if(!this.delay) this.delay = 0.25;
632 if(!this.flock_id) this.flock_id = globflockcnt;
634 setthink(this, flockerspawn_think);
635 this.nextthink = time + 0.25;
637 this.enemy = new(FLock Hunter);
639 setmodel(this.enemy, MDL_FLOCKER);
640 setorigin(this.enemy, this.origin + '0 0 768' + (randomvec() * 128));
642 this.enemy.scale = 3;
643 this.enemy.effects = EF_LOWPRECISION;
644 set_movetype(this.enemy, MOVETYPE_BOUNCEMISSILE);
645 PROJECTILE_MAKETRIGGER(this.enemy);
646 setthink(this.enemy, flocker_hunter_think);
647 this.enemy.nextthink = time + 10;
648 this.enemy.flock_id = this.flock_id;
649 this.enemy.owner = this;