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)
35 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
36 direction = normalize(point - this.origin);
37 return direction * (distance / maximal_distance);
41 Pull toward a point increasing the pull the closer we get
43 vector steerlib_attract(entity this, vector point, float maximal_distance)
48 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
49 direction = normalize(point - this.origin);
51 return direction * (1-(distance / maximal_distance));
54 vector steerlib_attract2(entity this, vector point, float min_influense,float max_distance,float max_influense)
60 distance = bound(0.00001,vlen(this.origin - point),max_distance);
61 direction = normalize(point - this.origin);
63 influense = 1 - (distance / max_distance);
64 influense = min_influense + (influense * (max_influense - min_influense));
66 return direction * influense;
70 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
73 vector current_direction;
74 vector target_direction;
75 float i_target,i_current;
78 distance = vlen(this.origin - point);
80 distance = bound(0.001,distance,maximal_distance);
82 target_direction = normalize(point - this.origin);
83 current_direction = normalize(this.velocity);
85 i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
86 i_current = 1 - i_target;
88 // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
92 bprint("IT: ",s,"\n");
94 bprint("IC : ",s,"\n");
96 return normalize((target_direction * i_target) + (current_direction * i_current));
100 Move away from a point.
102 vector steerlib_repell(entity this, vector point,float maximal_distance)
107 distance = bound(0.001,vlen(this.origin - point),maximal_distance);
108 direction = normalize(this.origin - point);
110 return direction * (1-(distance / maximal_distance));
114 Try to keep at ideal_distance away from point
116 vector steerlib_standoff(entity this, vector point,float ideal_distance)
121 distance = vlen(this.origin - point);
124 if(distance < ideal_distance)
126 direction = normalize(this.origin - point);
127 return direction * (distance / ideal_distance);
130 direction = normalize(point - this.origin);
131 return direction * (ideal_distance / distance);
136 A random heading in a forward halfcicrle
139 this.target = steerlib_wander(256,32,this.target)
141 where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
143 vector steerlib_wander(entity this, float range, float tresh, vector oldpoint)
146 wander_point = v_forward - oldpoint;
148 if (vdist(wander_point, >, tresh))
151 range = bound(0,range,1);
153 wander_point = this.origin + v_forward * 128;
154 wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
156 return normalize(wander_point - this.origin);
160 Dodge a point. dont work to well.
162 vector steerlib_dodge(entity this, vector point, vector dodge_dir, float min_distance)
166 distance = max(vlen(this.origin - point),min_distance);
167 if (min_distance < distance)
170 return dodge_dir * (min_distance/distance);
174 flocking by .flock_id
175 Group will move towards the unified direction while keeping close to eachother.
178 vector steerlib_flock(entity this, float _radius, float standoff,float separation_force,float flock_force)
181 vector push = '0 0 0', pull = '0 0 0';
184 flock_member = findradius(this.origin, _radius);
187 if(flock_member != this)
188 if(flock_member.flock_id == this.flock_id)
191 push = push + (steerlib_repell(this, flock_member.origin,standoff) * separation_force);
192 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
194 flock_member = flock_member.chain;
196 return push + (pull* (1 / ccount));
200 flocking by .flock_id
201 Group will move towards the unified direction while keeping close to eachother.
202 xy only version (for ground movers).
204 vector steerlib_flock2d(entity this, float _radius, float standoff,float separation_force,float flock_force)
207 vector push = '0 0 0', pull = '0 0 0';
210 flock_member = findradius(this.origin,_radius);
213 if(flock_member != this)
214 if(flock_member.flock_id == this.flock_id)
217 push = push + (steerlib_repell(this, flock_member.origin, standoff) * separation_force);
218 pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
220 flock_member = flock_member.chain;
226 return push + (pull * (1 / ccount));
230 All members want to be in the center, and keep away from eachother.
231 The furtehr form the center the more they want to be there.
233 This results in a aligned movement (?!) much like flocking.
235 vector steerlib_swarm(entity this, float _radius, float standoff,float separation_force,float swarm_force)
238 vector force = '0 0 0', center = '0 0 0';
241 swarm_member = findradius(this.origin,_radius);
245 if(swarm_member.flock_id == this.flock_id)
248 center = center + swarm_member.origin;
249 force = force + (steerlib_repell(this, swarm_member.origin,standoff) * separation_force);
251 swarm_member = swarm_member.chain;
254 center = center * (1 / ccount);
255 force = force + (steerlib_arrive(this, center,_radius) * swarm_force);
261 Steer towards the direction least obstructed.
262 Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
263 You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
265 vector steerlib_traceavoid(entity this, float pitch,float length)
267 vector vup_left,vup_right,vdown_left,vdown_right;
268 float fup_left,fup_right,fdown_left,fdown_right;
269 vector upwish,downwish,leftwish,rightwish;
270 vector v_left,v_down;
273 v_left = v_right * -1;
276 vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
277 traceline(this.origin, this.origin + vup_left,MOVE_NOMONSTERS,this);
278 fup_left = trace_fraction;
280 //te_lightning1(NULL,this.origin, trace_endpos);
282 vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
283 traceline(this.origin,this.origin + vup_right ,MOVE_NOMONSTERS,this);
284 fup_right = trace_fraction;
286 //te_lightning1(NULL,this.origin, trace_endpos);
288 vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
289 traceline(this.origin,this.origin + vdown_left,MOVE_NOMONSTERS,this);
290 fdown_left = trace_fraction;
292 //te_lightning1(NULL,this.origin, trace_endpos);
294 vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
295 traceline(this.origin,this.origin + vdown_right,MOVE_NOMONSTERS,this);
296 fdown_right = trace_fraction;
298 //te_lightning1(NULL,this.origin, trace_endpos);
299 upwish = v_up * (fup_left + fup_right);
300 downwish = v_down * (fdown_left + fdown_right);
301 leftwish = v_left * (fup_left + fdown_left);
302 rightwish = v_right * (fup_right + fdown_right);
304 return (upwish+leftwish+downwish+rightwish) * 0.25;
309 Steer towards the direction least obstructed.
310 Run tracelines in a forward trident, bias each direction negative if something is found there.
312 vector steerlib_traceavoid_flat(entity this, float pitch, float length, vector vofs)
314 vector vt_left, vt_right,vt_front;
315 float f_left, f_right,f_front;
316 vector leftwish, rightwish,frontwish, v_left;
318 v_left = v_right * -1;
321 vt_front = v_forward * length;
322 traceline(this.origin + vofs, this.origin + vofs + vt_front,MOVE_NOMONSTERS,this);
323 f_front = trace_fraction;
325 vt_left = (v_forward + (v_left * pitch)) * length;
326 traceline(this.origin + vofs, this.origin + vofs + vt_left,MOVE_NOMONSTERS,this);
327 f_left = trace_fraction;
329 //te_lightning1(NULL,this.origin, trace_endpos);
331 vt_right = (v_forward + (v_right * pitch)) * length;
332 traceline(this.origin + vofs, this.origin + vofs + vt_right ,MOVE_NOMONSTERS,this);
333 f_right = trace_fraction;
335 //te_lightning1(NULL,this.origin, trace_endpos);
337 leftwish = v_left * f_left;
338 rightwish = v_right * f_right;
339 frontwish = v_forward * f_front;
341 return normalize(leftwish + rightwish + frontwish);
344 //#define BEAMSTEER_VISUAL
345 float beamsweep(entity this, vector from, vector dir,float length, float step,float step_up, float step_down)
350 u = '0 0 1' * step_up;
351 d = '0 0 1' * step_down;
353 traceline(from + u, from - d,MOVE_NORMAL,this);
354 if(trace_fraction == 1.0)
357 if(!location_isok(trace_endpos, false, false))
361 for(i = 0; i < length; i += step)
365 tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,this);
366 if(trace_fraction != 1.0)
369 traceline(b + u, b - d,MOVE_NORMAL,this);
370 if(trace_fraction == 1.0)
373 if(!location_isok(trace_endpos, false, false))
375 #ifdef BEAMSTEER_VISUAL
376 te_lightning1(NULL,a+u,b+u);
377 te_lightning1(NULL,b+u,b-d);
385 vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
387 float bm_forward, bm_right, bm_left,p;
391 vr = vectoangles(dir);
394 tracebox(this.origin + '0 0 1' * step_up, this.mins, this.maxs, ('0 0 1' * step_up) + this.origin + (dir * length), MOVE_NOMONSTERS, this);
395 if(trace_fraction == 1.0)
397 //te_lightning1(this,this.origin,this.origin + (dir * length));
402 bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
404 vr = normalize(v_forward + v_right * 0.125);
405 vl = normalize(v_forward - v_right * 0.125);
407 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
408 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
411 p = bm_left + bm_right;
414 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
415 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
422 vr = normalize(v_forward + v_right * p);
423 vl = normalize(v_forward - v_right * p);
424 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
425 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
428 if(bm_left + bm_right < 0.15)
430 vr = normalize((v_forward*-1) + v_right * 0.90);
431 vl = normalize((v_forward*-1) - v_right * 0.90);
433 bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
434 bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
437 //te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
438 //te_lightning1(this.tur_head,this.origin + '0 0 32',this.origin + '0 0 32' + vl * length);
440 bm_forward *= bm_forward;
441 bm_right *= bm_right;
447 return normalize(vr + vl);
452 //////////////////////////////////////////////
454 // Everything below this point is a mess :D //
455 //////////////////////////////////////////////
456 //#define TLIBS_TETSLIBS
457 #ifdef TLIBS_TETSLIBS
458 void flocker_die(entity this)
460 Send_Effect(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
465 this.nextthink = time;
466 setthink(this, SUB_Remove);
470 void flocker_think(entity this)
472 vector dodgemove,swarmmove;
473 vector reprellmove,wandermove,newmove;
475 this.angles_x = this.angles.x * -1;
476 makevectors(this.angles);
477 this.angles_x = this.angles.x * -1;
479 dodgemove = steerlib_traceavoid(this, 0.35,1000);
480 swarmmove = steerlib_flock(this, 500,75,700,500);
481 reprellmove = steerlib_repell(this, this.owner.enemy.origin+this.enemy.velocity,2000) * 700;
483 if(dodgemove == '0 0 0')
485 this.pos1 = steerlib_wander(this, 0.5,0.1,this.pos1);
486 wandermove = this.pos1 * 50;
489 this.pos1 = normalize(this.velocity);
491 dodgemove = dodgemove * vlen(this.velocity) * 5;
493 newmove = swarmmove + reprellmove + wandermove + dodgemove;
494 this.velocity = movelib_inertmove_byspeed(this, newmove,300,0.2,0.9);
495 //this.velocity = movelib_inertmove(this, dodgemove,0.65);
497 this.velocity = movelib_dragvec(this, 0.01,0.6);
499 this.angles = vectoangles(this.velocity);
504 this.nextthink = time + 0.1;
507 MODEL(FLOCKER, "models/turrets/rocket.md3");
509 void spawn_flocker(entity this)
511 entity flocker = new(flocker);
513 setorigin(flocker, this.origin + '0 0 32');
514 setmodel (flocker, MDL_FLOCKER);
515 setsize (flocker, '-3 -3 -3', '3 3 3');
517 flocker.flock_id = this.flock_id;
518 flocker.owner = this;
519 setthink(flocker, flocker_think);
520 flocker.nextthink = time + random() * 5;
521 PROJECTILE_MAKETRIGGER(flocker);
522 set_movetype(flocker, MOVETYPE_BOUNCEMISSILE);
523 flocker.effects = EF_LOWPRECISION;
524 flocker.velocity = randomvec() * 300;
525 flocker.angles = vectoangles(flocker.velocity);
527 flocker.pos1 = normalize(flocker.velocity + randomvec() * 0.1);
529 IL_PUSH(g_flockers, flocker);
531 this.cnt = this.cnt -1;
535 void flockerspawn_think(entity this)
540 this.nextthink = time + this.delay;
544 void flocker_hunter_think(entity this)
546 vector dodgemove,attractmove,newmove;
549 this.angles_x = this.angles.x * -1;
550 makevectors(this.angles);
551 this.angles_x = this.angles.x * -1;
554 if(vdist(this.enemy.origin - this.origin, <, 64))
564 IL_EACH(g_flockers, it.flock_id == this.flock_id,
566 if(it == this.owner || it == ee)
569 if(!this.enemy || vlen2(this.origin - it.origin) > vlen2(this.origin - this.enemy.origin))
575 attractmove = steerlib_attract(this, this.enemy.origin+this.enemy.velocity * 0.1,5000) * 1250;
577 attractmove = normalize(this.velocity) * 200;
579 dodgemove = steerlib_traceavoid(this, 0.35,1500) * vlen(this.velocity);
581 newmove = dodgemove + attractmove;
582 this.velocity = movelib_inertmove_byspeed(this, newmove,1250,0.3,0.7);
583 this.velocity = movelib_dragvec(this, 0.01,0.5);
585 this.angles = vectoangles(this.velocity);
586 this.nextthink = time + 0.1;
591 spawnfunc(flockerspawn)
595 if(!this.cnt) this.cnt = 20;
596 if(!this.delay) this.delay = 0.25;
597 if(!this.flock_id) this.flock_id = globflockcnt;
599 setthink(this, flockerspawn_think);
600 this.nextthink = time + 0.25;
602 this.enemy = new(FLock Hunter);
604 setmodel(this.enemy, MDL_FLOCKER);
605 setorigin(this.enemy, this.origin + '0 0 768' + (randomvec() * 128));
607 this.enemy.scale = 3;
608 this.enemy.effects = EF_LOWPRECISION;
609 set_movetype(this.enemy, MOVETYPE_BOUNCEMISSILE);
610 PROJECTILE_MAKETRIGGER(this.enemy);
611 setthink(this.enemy, flocker_hunter_think);
612 this.enemy.nextthink = time + 10;
613 this.enemy.flock_id = this.flock_id;
614 this.enemy.owner = this;
616 IL_PUSH(g_flockers, this);
617 IL_PUSH(g_flockers, this.enemy);