8 Uniform pull towards a point
10 #define steerlib_pull(ent,point) normalize(point - (ent).origin)
11 /*vector steerlib_pull(entity this, vector point)
13 return normalize(point - this.origin);
17 Uniform push from a point
19 #define steerlib_push(ent,point) normalize(ent.origin - point)
21 vector steerlib_push(entity this, vector point)
23 return normalize(this.origin - point);
27 Pull toward a point, The further away, the stronger the pull.
29 vector steerlib_arrive(entity this, vector point, float maximal_distance)
34 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
35 direction = normalize(point - this.origin);
36 return direction * (distance / maximal_distance);
40 Pull toward a point increasing the pull the closer we get
42 vector steerlib_attract(entity this, vector point, float maximal_distance)
47 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
48 direction = normalize(point - this.origin);
50 return direction * (1-(distance / maximal_distance));
53 vector steerlib_attract2(entity this, vector point, float min_influense,float max_distance,float max_influense)
59 distance = bound(0.00001,vlen(this.origin - point),max_distance);
60 direction = normalize(point - this.origin);
62 influense = 1 - (distance / max_distance);
63 influense = min_influense + (influense * (max_influense - min_influense));
65 return direction * influense;
69 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
72 vector current_direction;
73 vector target_direction;
74 float i_target,i_current;
77 distance = vlen(this.origin - point);
79 distance = bound(0.001,distance,maximal_distance);
81 target_direction = normalize(point - this.origin);
82 current_direction = normalize(this.velocity);
84 i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
85 i_current = 1 - i_target;
87 // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
91 bprint("IT: ",s,"\n");
93 bprint("IC : ",s,"\n");
95 return normalize((target_direction * i_target) + (current_direction * i_current));
99 Move away from a point.
101 vector steerlib_repell(entity this, vector point,float maximal_distance)
106 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
107 direction = normalize(this.origin - point);
109 return direction * (1-(distance / maximal_distance));
113 Try to keep at ideal_distance away from point
115 vector steerlib_standoff(entity this, vector point,float ideal_distance)
120 distance = vlen(this.origin - point);
123 if(distance < ideal_distance)
125 direction = normalize(this.origin - point);
126 return direction * (distance / ideal_distance);
129 direction = normalize(point - this.origin);
130 return direction * (ideal_distance / distance);
135 A random heading in a forward halfcicrle
138 this.target = steerlib_wander(256,32,this.target)
140 where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
142 vector steerlib_wander(entity this, float range, float tresh, vector oldpoint)
145 wander_point = v_forward - oldpoint;
147 if (vdist(wander_point, >, tresh))
150 range = bound(0,range,1);
152 wander_point = this.origin + v_forward * 128;
153 wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
155 return normalize(wander_point - this.origin);
159 Dodge a point. dont work to well.
161 vector steerlib_dodge(entity this, vector point, vector dodge_dir, float min_distance)
165 distance = max(vlen(this.origin - point),min_distance);
166 if (min_distance < distance)
169 return dodge_dir * (min_distance/distance);
173 flocking by .flock_id
174 Group will move towards the unified direction while keeping close to eachother.
177 vector steerlib_flock(entity this, float _radius, float standoff,float separation_force,float flock_force)
180 vector push = '0 0 0', pull = '0 0 0';
183 flock_member = findradius(this.origin, _radius);
186 if(flock_member != this)
187 if(flock_member.flock_id == this.flock_id)
190 push = push + (steerlib_repell(this, flock_member.origin,standoff) * separation_force);
191 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
193 flock_member = flock_member.chain;
195 return push + (pull* (1 / ccount));
199 flocking by .flock_id
200 Group will move towards the unified direction while keeping close to eachother.
201 xy only version (for ground movers).
203 vector steerlib_flock2d(entity this, float _radius, float standoff,float separation_force,float flock_force)
206 vector push = '0 0 0', pull = '0 0 0';
209 flock_member = findradius(this.origin,_radius);
212 if(flock_member != this)
213 if(flock_member.flock_id == this.flock_id)
216 push = push + (steerlib_repell(this, flock_member.origin, standoff) * separation_force);
217 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
219 flock_member = flock_member.chain;
225 return push + (pull * (1 / ccount));
229 All members want to be in the center, and keep away from eachother.
230 The furtehr form the center the more they want to be there.
232 This results in a aligned movement (?!) much like flocking.
234 vector steerlib_swarm(entity this, float _radius, float standoff,float separation_force,float swarm_force)
237 vector force = '0 0 0', center = '0 0 0';
240 swarm_member = findradius(this.origin,_radius);
244 if(swarm_member.flock_id == this.flock_id)
247 center = center + swarm_member.origin;
248 force = force + (steerlib_repell(this, swarm_member.origin,standoff) * separation_force);
250 swarm_member = swarm_member.chain;
253 center = center * (1 / ccount);
254 force = force + (steerlib_arrive(this, center,_radius) * swarm_force);
260 Steer towards the direction least obstructed.
261 Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
262 You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
264 vector steerlib_traceavoid(entity this, float pitch,float length)
266 vector vup_left,vup_right,vdown_left,vdown_right;
267 float fup_left,fup_right,fdown_left,fdown_right;
268 vector upwish,downwish,leftwish,rightwish;
269 vector v_left,v_down;
272 v_left = v_right * -1;
275 vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
276 traceline(this.origin, this.origin + vup_left,MOVE_NOMONSTERS,this);
277 fup_left = trace_fraction;
279 //te_lightning1(NULL,this.origin, trace_endpos);
281 vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
282 traceline(this.origin,this.origin + vup_right ,MOVE_NOMONSTERS,this);
283 fup_right = trace_fraction;
285 //te_lightning1(NULL,this.origin, trace_endpos);
287 vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
288 traceline(this.origin,this.origin + vdown_left,MOVE_NOMONSTERS,this);
289 fdown_left = trace_fraction;
291 //te_lightning1(NULL,this.origin, trace_endpos);
293 vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
294 traceline(this.origin,this.origin + vdown_right,MOVE_NOMONSTERS,this);
295 fdown_right = trace_fraction;
297 //te_lightning1(NULL,this.origin, trace_endpos);
298 upwish = v_up * (fup_left + fup_right);
299 downwish = v_down * (fdown_left + fdown_right);
300 leftwish = v_left * (fup_left + fdown_left);
301 rightwish = v_right * (fup_right + fdown_right);
303 return (upwish+leftwish+downwish+rightwish) * 0.25;
308 Steer towards the direction least obstructed.
309 Run tracelines in a forward trident, bias each direction negative if something is found there.
311 vector steerlib_traceavoid_flat(entity this, float pitch, float length, vector vofs)
313 vector vt_left, vt_right,vt_front;
314 float f_left, f_right,f_front;
315 vector leftwish, rightwish,frontwish, v_left;
317 v_left = v_right * -1;
320 vt_front = v_forward * length;
321 traceline(this.origin + vofs, this.origin + vofs + vt_front,MOVE_NOMONSTERS,this);
322 f_front = trace_fraction;
324 vt_left = (v_forward + (v_left * pitch)) * length;
325 traceline(this.origin + vofs, this.origin + vofs + vt_left,MOVE_NOMONSTERS,this);
326 f_left = trace_fraction;
328 //te_lightning1(NULL,this.origin, trace_endpos);
330 vt_right = (v_forward + (v_right * pitch)) * length;
331 traceline(this.origin + vofs, this.origin + vofs + vt_right ,MOVE_NOMONSTERS,this);
332 f_right = trace_fraction;
334 //te_lightning1(NULL,this.origin, trace_endpos);
336 leftwish = v_left * f_left;
337 rightwish = v_right * f_right;
338 frontwish = v_forward * f_front;
340 return normalize(leftwish + rightwish + frontwish);
343 bool beamsweep_badpoint(vector point, bool waterok)
345 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
348 int pc = pointcontents(point);
349 int pc2 = pointcontents(point - '0 0 1');
351 if(pc == CONTENT_EMPTY && pc2 == CONTENT_SOLID)
353 if(pc == CONTENT_EMPTY && pc2 == CONTENT_WATER && waterok)
355 if(pc == CONTENT_WATER && waterok)
361 case CONTENT_SOLID: break;
362 case CONTENT_SLIME: break;
363 case CONTENT_LAVA: break;
369 if (pc2 == CONTENT_SOLID)
372 if (pc2 == CONTENT_WATER)
388 //#define BEAMSTEER_VISUAL
389 float beamsweep(entity this, vector from, vector dir,float length, float step,float step_up, float step_down)
394 u = '0 0 1' * step_up;
395 d = '0 0 1' * step_down;
397 traceline(from + u, from - d,MOVE_NORMAL,this);
398 if(trace_fraction == 1.0)
401 if(beamsweep_badpoint(trace_endpos,0))
405 for(i = 0; i < length; i += step)
409 tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,this);
410 if(trace_fraction != 1.0)
413 traceline(b + u, b - d,MOVE_NORMAL,this);
414 if(trace_fraction == 1.0)
417 if(beamsweep_badpoint(trace_endpos,0))
419 #ifdef BEAMSTEER_VISUAL
420 te_lightning1(NULL,a+u,b+u);
421 te_lightning1(NULL,b+u,b-d);
429 vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
431 float bm_forward, bm_right, bm_left,p;
435 vr = vectoangles(dir);
438 tracebox(this.origin + '0 0 1' * step_up, this.mins, this.maxs, ('0 0 1' * step_up) + this.origin + (dir * length), MOVE_NOMONSTERS, this);
439 if(trace_fraction == 1.0)
441 //te_lightning1(this,this.origin,this.origin + (dir * length));
446 bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
448 vr = normalize(v_forward + v_right * 0.125);
449 vl = normalize(v_forward - v_right * 0.125);
451 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
452 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
455 p = bm_left + bm_right;
458 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
459 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
466 vr = normalize(v_forward + v_right * p);
467 vl = normalize(v_forward - v_right * p);
468 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
469 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
472 if(bm_left + bm_right < 0.15)
474 vr = normalize((v_forward*-1) + v_right * 0.90);
475 vl = normalize((v_forward*-1) - v_right * 0.90);
477 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
478 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
481 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
482 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
484 bm_forward *= bm_forward;
485 bm_right *= bm_right;
491 return normalize(vr + vl);
496 //////////////////////////////////////////////
498 // Everything below this point is a mess :D //
499 //////////////////////////////////////////////
500 //#define TLIBS_TETSLIBS
501 #ifdef TLIBS_TETSLIBS
502 void flocker_die(entity this)
504 Send_Effect(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
509 this.nextthink = time;
510 setthink(this, SUB_Remove);
514 void flocker_think(entity this)
516 vector dodgemove,swarmmove;
517 vector reprellmove,wandermove,newmove;
519 this.angles_x = this.angles.x * -1;
520 makevectors(this.angles);
521 this.angles_x = this.angles.x * -1;
523 dodgemove = steerlib_traceavoid(this, 0.35,1000);
524 swarmmove = steerlib_flock(this, 500,75,700,500);
525 reprellmove = steerlib_repell(this, this.owner.enemy.origin+this.enemy.velocity,2000) * 700;
527 if(dodgemove == '0 0 0')
529 this.pos1 = steerlib_wander(this, 0.5,0.1,this.pos1);
530 wandermove = this.pos1 * 50;
533 this.pos1 = normalize(this.velocity);
535 dodgemove = dodgemove * vlen(this.velocity) * 5;
537 newmove = swarmmove + reprellmove + wandermove + dodgemove;
538 this.velocity = movelib_inertmove_byspeed(this, newmove,300,0.2,0.9);
539 //this.velocity = movelib_inertmove(this, dodgemove,0.65);
541 this.velocity = movelib_dragvec(this, 0.01,0.6);
543 this.angles = vectoangles(this.velocity);
548 this.nextthink = time + 0.1;
551 MODEL(FLOCKER, "models/turrets/rocket.md3");
553 void spawn_flocker(entity this)
555 entity flocker = new(flocker);
557 setorigin(flocker, this.origin + '0 0 32');
558 setmodel (flocker, MDL_FLOCKER);
559 setsize (flocker, '-3 -3 -3', '3 3 3');
561 flocker.flock_id = this.flock_id;
562 flocker.owner = this;
563 setthink(flocker, flocker_think);
564 flocker.nextthink = time + random() * 5;
565 PROJECTILE_MAKETRIGGER(flocker);
566 set_movetype(flocker, MOVETYPE_BOUNCEMISSILE);
567 flocker.effects = EF_LOWPRECISION;
568 flocker.velocity = randomvec() * 300;
569 flocker.angles = vectoangles(flocker.velocity);
571 flocker.pos1 = normalize(flocker.velocity + randomvec() * 0.1);
573 this.cnt = this.cnt -1;
577 void flockerspawn_think(entity this)
582 this.nextthink = time + this.delay;
586 void flocker_hunter_think(entity this)
588 vector dodgemove,attractmove,newmove;
591 this.angles_x = this.angles.x * -1;
592 makevectors(this.angles);
593 this.angles_x = this.angles.x * -1;
596 if(vdist(this.enemy.origin - this.origin, <, 64))
606 FOREACH_ENTITY_FLOAT(flock_id, this.flock_id,
608 if(it == this.owner || it == ee)
611 if(!this.enemy || vlen2(this.origin - it.origin) > vlen2(this.origin - this.enemy.origin))
617 attractmove = steerlib_attract(this, this.enemy.origin+this.enemy.velocity * 0.1,5000) * 1250;
619 attractmove = normalize(this.velocity) * 200;
621 dodgemove = steerlib_traceavoid(this, 0.35,1500) * vlen(this.velocity);
623 newmove = dodgemove + attractmove;
624 this.velocity = movelib_inertmove_byspeed(this, newmove,1250,0.3,0.7);
625 this.velocity = movelib_dragvec(this, 0.01,0.5);
627 this.angles = vectoangles(this.velocity);
628 this.nextthink = time + 0.1;
633 spawnfunc(flockerspawn)
637 if(!this.cnt) this.cnt = 20;
638 if(!this.delay) this.delay = 0.25;
639 if(!this.flock_id) this.flock_id = globflockcnt;
641 setthink(this, flockerspawn_think);
642 this.nextthink = time + 0.25;
644 this.enemy = new(FLock Hunter);
646 setmodel(this.enemy, MDL_FLOCKER);
647 setorigin(this.enemy, this.origin + '0 0 768' + (randomvec() * 128));
649 this.enemy.scale = 3;
650 this.enemy.effects = EF_LOWPRECISION;
651 set_movetype(this.enemy, MOVETYPE_BOUNCEMISSILE);
652 PROJECTILE_MAKETRIGGER(this.enemy);
653 setthink(this.enemy, flocker_hunter_think);
654 this.enemy.nextthink = time + 10;
655 this.enemy.flock_id = this.flock_id;
656 this.enemy.owner = this;