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 bool beamsweep_badpoint(vector point, bool waterok)
344 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
347 int pc = pointcontents(point);
348 int pc2 = pointcontents(point - '0 0 1');
350 if(pc == CONTENT_EMPTY && pc2 == CONTENT_SOLID)
352 if(pc == CONTENT_EMPTY && pc2 == CONTENT_WATER && waterok)
354 if(pc == CONTENT_WATER && waterok)
360 case CONTENT_SOLID: break;
361 case CONTENT_SLIME: break;
362 case CONTENT_LAVA: break;
368 if (pc2 == CONTENT_SOLID)
371 if (pc2 == CONTENT_WATER)
387 //#define BEAMSTEER_VISUAL
388 float beamsweep(entity this, vector from, vector dir,float length, float step,float step_up, float step_down)
393 u = '0 0 1' * step_up;
394 d = '0 0 1' * step_down;
396 traceline(from + u, from - d,MOVE_NORMAL,this);
397 if(trace_fraction == 1.0)
400 if(beamsweep_badpoint(trace_endpos,0))
404 for(i = 0; i < length; i += step)
408 tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,this);
409 if(trace_fraction != 1.0)
412 traceline(b + u, b - d,MOVE_NORMAL,this);
413 if(trace_fraction == 1.0)
416 if(beamsweep_badpoint(trace_endpos,0))
418 #ifdef BEAMSTEER_VISUAL
419 te_lightning1(NULL,a+u,b+u);
420 te_lightning1(NULL,b+u,b-d);
428 vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
430 float bm_forward, bm_right, bm_left,p;
434 vr = vectoangles(dir);
437 tracebox(this.origin + '0 0 1' * step_up, this.mins, this.maxs, ('0 0 1' * step_up) + this.origin + (dir * length), MOVE_NOMONSTERS, this);
438 if(trace_fraction == 1.0)
440 //te_lightning1(this,this.origin,this.origin + (dir * length));
445 bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
447 vr = normalize(v_forward + v_right * 0.125);
448 vl = normalize(v_forward - v_right * 0.125);
450 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
451 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
454 p = bm_left + bm_right;
457 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
458 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
465 vr = normalize(v_forward + v_right * p);
466 vl = normalize(v_forward - v_right * p);
467 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
468 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
471 if(bm_left + bm_right < 0.15)
473 vr = normalize((v_forward*-1) + v_right * 0.90);
474 vl = normalize((v_forward*-1) - v_right * 0.90);
476 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
477 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
480 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
481 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
483 bm_forward *= bm_forward;
484 bm_right *= bm_right;
490 return normalize(vr + vl);
495 //////////////////////////////////////////////
497 // Everything below this point is a mess :D //
498 //////////////////////////////////////////////
499 //#define TLIBS_TETSLIBS
500 #ifdef TLIBS_TETSLIBS
501 void flocker_die(entity this)
503 Send_Effect(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
508 this.nextthink = time;
509 setthink(this, SUB_Remove);
513 void flocker_think(entity this)
515 vector dodgemove,swarmmove;
516 vector reprellmove,wandermove,newmove;
518 this.angles_x = this.angles.x * -1;
519 makevectors(this.angles);
520 this.angles_x = this.angles.x * -1;
522 dodgemove = steerlib_traceavoid(this, 0.35,1000);
523 swarmmove = steerlib_flock(this, 500,75,700,500);
524 reprellmove = steerlib_repell(this, this.owner.enemy.origin+this.enemy.velocity,2000) * 700;
526 if(dodgemove == '0 0 0')
528 this.pos1 = steerlib_wander(this, 0.5,0.1,this.pos1);
529 wandermove = this.pos1 * 50;
532 this.pos1 = normalize(this.velocity);
534 dodgemove = dodgemove * vlen(this.velocity) * 5;
536 newmove = swarmmove + reprellmove + wandermove + dodgemove;
537 this.velocity = movelib_inertmove_byspeed(this, newmove,300,0.2,0.9);
538 //this.velocity = movelib_inertmove(this, dodgemove,0.65);
540 this.velocity = movelib_dragvec(this, 0.01,0.6);
542 this.angles = vectoangles(this.velocity);
547 this.nextthink = time + 0.1;
550 MODEL(FLOCKER, "models/turrets/rocket.md3");
552 void spawn_flocker(entity this)
554 entity flocker = new(flocker);
556 setorigin(flocker, this.origin + '0 0 32');
557 setmodel (flocker, MDL_FLOCKER);
558 setsize (flocker, '-3 -3 -3', '3 3 3');
560 flocker.flock_id = this.flock_id;
561 flocker.owner = this;
562 setthink(flocker, flocker_think);
563 flocker.nextthink = time + random() * 5;
564 PROJECTILE_MAKETRIGGER(flocker);
565 set_movetype(flocker, MOVETYPE_BOUNCEMISSILE);
566 flocker.effects = EF_LOWPRECISION;
567 flocker.velocity = randomvec() * 300;
568 flocker.angles = vectoangles(flocker.velocity);
570 flocker.pos1 = normalize(flocker.velocity + randomvec() * 0.1);
572 this.cnt = this.cnt -1;
576 void flockerspawn_think(entity this)
581 this.nextthink = time + this.delay;
585 void flocker_hunter_think(entity this)
587 vector dodgemove,attractmove,newmove;
590 this.angles_x = this.angles.x * -1;
591 makevectors(this.angles);
592 this.angles_x = this.angles.x * -1;
595 if(vdist(this.enemy.origin - this.origin, <, 64))
605 FOREACH_ENTITY_FLOAT(flock_id, this.flock_id,
607 if(it == this.owner || it == ee)
610 if(!this.enemy || vlen2(this.origin - it.origin) > vlen2(this.origin - this.enemy.origin))
616 attractmove = steerlib_attract(this, this.enemy.origin+this.enemy.velocity * 0.1,5000) * 1250;
618 attractmove = normalize(this.velocity) * 200;
620 dodgemove = steerlib_traceavoid(this, 0.35,1500) * vlen(this.velocity);
622 newmove = dodgemove + attractmove;
623 this.velocity = movelib_inertmove_byspeed(this, newmove,1250,0.3,0.7);
624 this.velocity = movelib_dragvec(this, 0.01,0.5);
626 this.angles = vectoangles(this.velocity);
627 this.nextthink = time + 0.1;
632 spawnfunc(flockerspawn)
636 if(!this.cnt) this.cnt = 20;
637 if(!this.delay) this.delay = 0.25;
638 if(!this.flock_id) this.flock_id = globflockcnt;
640 setthink(this, flockerspawn_think);
641 this.nextthink = time + 0.25;
643 this.enemy = new(FLock Hunter);
645 setmodel(this.enemy, MDL_FLOCKER);
646 setorigin(this.enemy, this.origin + '0 0 768' + (randomvec() * 128));
648 this.enemy.scale = 3;
649 this.enemy.effects = EF_LOWPRECISION;
650 set_movetype(this.enemy, MOVETYPE_BOUNCEMISSILE);
651 PROJECTILE_MAKETRIGGER(this.enemy);
652 setthink(this.enemy, flocker_hunter_think);
653 this.enemy.nextthink = time + 10;
654 this.enemy.flock_id = this.flock_id;
655 this.enemy.owner = this;