2 Uniform pull towards a point
\r
4 vector steerlib_pull(vector point)
\r
6 return normalize(point - self.origin);
\r
10 Uniform push from a point
\r
12 #define steerlib_push(point) normalize(self.origin - point)
\r
14 vector steerlib_push(vector point)
\r
16 return normalize(self.origin - point);
\r
20 Pull toward a point, The further away, the stronger the pull.
\r
22 vector steerlib_arrive(vector point,float maximal_distance)
\r
27 distance = bound(0.001,vlen(self.origin - point),maximal_distance);
\r
28 direction = normalize(point - self.origin);
\r
29 return direction * (distance / maximal_distance);
\r
33 Pull toward a point increasing the pull the closer we get
\r
35 vector steerlib_attract(vector point, float maximal_distance)
\r
40 distance = bound(0.001,vlen(self.origin - point),maximal_distance);
\r
41 direction = normalize(point - self.origin);
\r
43 return direction * (1-(distance / maximal_distance));
\r
46 vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense)
\r
52 distance = bound(0.00001,vlen(self.origin - point),max_distance);
\r
53 direction = normalize(point - self.origin);
\r
55 influense = 1 - (distance / max_distance);
\r
56 influense = min_influense + (influense * (max_influense - min_influense));
\r
58 return direction * influense;
\r
62 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
\r
65 vector current_direction;
\r
66 vector target_direction;
\r
67 float i_target,i_current;
\r
70 distance = vlen(self.origin - point);
\r
72 distance = bound(0.001,distance,maximal_distance);
\r
74 target_direction = normalize(point - self.origin);
\r
75 current_direction = normalize(self.velocity);
\r
77 i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
\r
78 i_current = 1 - i_target;
\r
80 // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
\r
84 bprint("IT: ",s,"\n");
\r
85 s = ftos(i_current);
\r
86 bprint("IC : ",s,"\n");
\r
88 return normalize((target_direction * i_target) + (current_direction * i_current));
\r
92 Move away from a point.
\r
94 vector steerlib_repell(vector point,float maximal_distance)
\r
99 distance = bound(0.001,vlen(self.origin - point),maximal_distance);
\r
100 direction = normalize(self.origin - point);
\r
102 return direction * (1-(distance / maximal_distance));
\r
106 Try to keep at ideal_distance away from point
\r
108 vector steerlib_standoff(vector point,float ideal_distance)
\r
113 distance = vlen(self.origin - point);
\r
116 if(distance < ideal_distance)
\r
118 direction = normalize(self.origin - point);
\r
119 return direction * (distance / ideal_distance);
\r
122 direction = normalize(point - self.origin);
\r
123 return direction * (ideal_distance / distance);
\r
128 A random heading in a forward halfcicrle
\r
131 self.target = steerlib_wander(256,32,self.target)
\r
133 where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
\r
135 vector steerlib_wander(float range,float tresh,vector oldpoint)
\r
137 vector wander_point;
\r
138 wander_point = v_forward - oldpoint;
\r
140 if (vlen(wander_point) > tresh)
\r
143 range = bound(0,range,1);
\r
145 wander_point = self.origin + v_forward * 128;
\r
146 wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
\r
148 return normalize(wander_point - self.origin);
\r
152 Dodge a point. dont work to well.
\r
154 vector steerlib_dodge(vector point,vector dodge_dir,float min_distance)
\r
158 distance = max(vlen(self.origin - point),min_distance);
\r
159 if (min_distance < distance)
\r
162 return dodge_dir * (min_distance/distance);
\r
166 flocking by .flock_id
\r
167 Group will move towards the unified direction while keeping close to eachother.
\r
170 vector steerlib_flock(float radius, float standoff,float separation_force,float flock_force)
\r
172 entity flock_member;
\r
176 flock_member = findradius(self.origin,radius);
\r
177 while(flock_member)
\r
179 if(flock_member != self)
\r
180 if(flock_member.flock_id == self.flock_id)
\r
183 push = push + (steerlib_repell(flock_member.origin,standoff) * separation_force);
\r
184 pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity,radius) * flock_force);
\r
186 flock_member = flock_member.chain;
\r
188 return push + (pull* (1 / ccount));
\r
192 flocking by .flock_id
\r
193 Group will move towards the unified direction while keeping close to eachother.
\r
194 xy only version (for ground movers).
\r
196 vector steerlib_flock2d(float radius, float standoff,float separation_force,float flock_force)
\r
198 entity flock_member;
\r
202 flock_member = findradius(self.origin,radius);
\r
203 while(flock_member)
\r
205 if(flock_member != self)
\r
206 if(flock_member.flock_id == self.flock_id)
\r
209 push = push + (steerlib_repell(flock_member.origin, standoff) * separation_force);
\r
210 pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity, radius) * flock_force);
\r
212 flock_member = flock_member.chain;
\r
218 return push + (pull * (1 / ccount));
\r
222 All members want to be in the center, and keep away from eachother.
\r
223 The furtehr form the center the more they want to be there.
\r
225 This results in a aligned movement (?!) much like flocking.
\r
227 vector steerlib_swarm(float radius, float standoff,float separation_force,float swarm_force)
\r
229 entity swarm_member;
\r
230 vector force,center;
\r
233 swarm_member = findradius(self.origin,radius);
\r
235 while(swarm_member)
\r
237 if(swarm_member.flock_id == self.flock_id)
\r
240 center = center + swarm_member.origin;
\r
241 force = force + (steerlib_repell(swarm_member.origin,standoff) * separation_force);
\r
243 swarm_member = swarm_member.chain;
\r
246 center = center * (1 / ccount);
\r
247 force = force + (steerlib_arrive(center,radius) * swarm_force);
\r
253 Steer towards the direction least obstructed.
\r
254 Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
\r
255 You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
\r
257 vector steerlib_traceavoid(float pitch,float length)
\r
259 vector vup_left,vup_right,vdown_left,vdown_right;
\r
260 float fup_left,fup_right,fdown_left,fdown_right;
\r
261 vector upwish,downwish,leftwish,rightwish;
\r
262 vector v_left,v_down;
\r
265 v_left = v_right * -1;
\r
266 v_down = v_up * -1;
\r
268 vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
\r
269 traceline(self.origin, self.origin + vup_left,MOVE_NOMONSTERS,self);
\r
270 fup_left = trace_fraction;
\r
272 //te_lightning1(world,self.origin, trace_endpos);
\r
274 vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
\r
275 traceline(self.origin,self.origin + vup_right ,MOVE_NOMONSTERS,self);
\r
276 fup_right = trace_fraction;
\r
278 //te_lightning1(world,self.origin, trace_endpos);
\r
280 vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
\r
281 traceline(self.origin,self.origin + vdown_left,MOVE_NOMONSTERS,self);
\r
282 fdown_left = trace_fraction;
\r
284 //te_lightning1(world,self.origin, trace_endpos);
\r
286 vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
\r
287 traceline(self.origin,self.origin + vdown_right,MOVE_NOMONSTERS,self);
\r
288 fdown_right = trace_fraction;
\r
290 //te_lightning1(world,self.origin, trace_endpos);
\r
291 upwish = v_up * (fup_left + fup_right);
\r
292 downwish = v_down * (fdown_left + fdown_right);
\r
293 leftwish = v_left * (fup_left + fdown_left);
\r
294 rightwish = v_right * (fup_right + fdown_right);
\r
296 return (upwish+leftwish+downwish+rightwish) * 0.25;
\r
301 Steer towards the direction least obstructed.
\r
302 Run tracelines in a forward trident, bias each direction negative if something is found there.
\r
304 vector steerlib_traceavoid_flat(float pitch, float length, vector vofs)
\r
306 vector vt_left, vt_right,vt_front;
\r
307 float f_left, f_right,f_front;
\r
308 vector leftwish, rightwish,frontwish, v_left;
\r
310 v_left = v_right * -1;
\r
313 vt_front = v_forward * length;
\r
314 traceline(self.origin + vofs, self.origin + vofs + vt_front,MOVE_NOMONSTERS,self);
\r
315 f_front = trace_fraction;
\r
317 vt_left = (v_forward + (v_left * pitch)) * length;
\r
318 traceline(self.origin + vofs, self.origin + vofs + vt_left,MOVE_NOMONSTERS,self);
\r
319 f_left = trace_fraction;
\r
321 //te_lightning1(world,self.origin, trace_endpos);
\r
323 vt_right = (v_forward + (v_right * pitch)) * length;
\r
324 traceline(self.origin + vofs, self.origin + vofs + vt_right ,MOVE_NOMONSTERS,self);
\r
325 f_right = trace_fraction;
\r
327 //te_lightning1(world,self.origin, trace_endpos);
\r
329 leftwish = v_left * f_left;
\r
330 rightwish = v_right * f_right;
\r
331 frontwish = v_forward * f_front;
\r
333 return normalize(leftwish + rightwish + frontwish);
\r
336 float beamsweep_badpoint(vector point,float waterok)
\r
340 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
343 pc = pointcontents(point);
\r
344 pc2 = pointcontents(point - '0 0 1');
\r
348 case CONTENT_SOLID: break;
\r
349 case CONTENT_SLIME: break;
\r
350 case CONTENT_LAVA: break;
\r
355 case CONTENT_EMPTY:
\r
356 if (pc2 == CONTENT_SOLID)
\r
359 if (pc2 == CONTENT_WATER)
\r
365 case CONTENT_WATER:
\r
375 //#define BEAMSTEER_VISUAL
\r
376 float beamsweep(vector from, vector dir,float length, float step,float step_up, float step_down)
\r
381 u = '0 0 1' * step_up;
\r
382 d = '0 0 1' * step_down;
\r
384 traceline(from + u, from - d,MOVE_NORMAL,self);
\r
385 if(trace_fraction == 1.0)
\r
388 if(beamsweep_badpoint(trace_endpos,0))
\r
392 for(i = 0; i < length; i += step)
\r
395 b = a + dir * step;
\r
396 tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,self);
\r
397 if(trace_fraction != 1.0)
\r
400 traceline(b + u, b - d,MOVE_NORMAL,self);
\r
401 if(trace_fraction == 1.0)
\r
404 if(beamsweep_badpoint(trace_endpos,0))
\r
406 #ifdef BEAMSTEER_VISUAL
\r
407 te_lightning1(world,a+u,b+u);
\r
408 te_lightning1(world,b+u,b-d);
\r
416 vector steerlib_beamsteer(vector dir, float length, float step, float step_up, float step_down)
\r
418 float bm_forward, bm_right, bm_left,p;
\r
422 vr = vectoangles(dir);
\r
425 tracebox(self.origin , self.mins,self.maxs,self.origin + (dir * length) ,MOVE_NOMONSTERS,self);
\r
426 if(trace_fraction == 1.0)
\r
428 //te_lightning1(self,self.origin,self.origin + (dir * length));
\r
436 bm_forward = beamsweep(self.origin, v_forward, length, step, step_up, step_down);
\r
438 vr = normalize(v_forward + v_right * 0.125);
\r
439 vl = normalize(v_forward - v_right * 0.125);
\r
441 bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
\r
442 bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
\r
445 p = bm_left + bm_right;
\r
448 //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
\r
449 //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
\r
456 vr = normalize(v_forward + v_right * p);
\r
457 vl = normalize(v_forward - v_right * p);
\r
458 bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
\r
459 bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
\r
462 if(bm_left + bm_right < 0.15)
\r
464 vr = normalize((v_forward*-1) + v_right * 0.75);
\r
465 vl = normalize((v_forward*-1) - v_right * 0.75);
\r
467 bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
\r
468 bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
\r
471 //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
\r
472 //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
\r
474 bm_forward *= bm_forward;
\r
475 bm_right *= bm_right;
\r
476 bm_left *= bm_left;
\r
478 vr = vr * bm_right;
\r
481 return normalize(vr + vl);
\r
486 //////////////////////////////////////////////
\r
488 // Everything below this point is a mess :D //
\r
489 //////////////////////////////////////////////
\r
490 //#define TLIBS_TETSLIBS
\r
491 #ifdef TLIBS_TETSLIBS
\r
494 sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
\r
496 pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
\r
498 self.owner.cnt += 1;
\r
499 self.owner = world;
\r
501 self.nextthink = time;
\r
502 self.think = SUB_Remove;
\r
506 void flocker_think()
\r
508 vector dodgemove,swarmmove;
\r
509 vector reprellmove,wandermove,newmove;
\r
511 self.angles_x = self.angles_x * -1;
\r
512 makevectors(self.angles);
\r
513 self.angles_x = self.angles_x * -1;
\r
515 dodgemove = steerlib_traceavoid(0.35,1000);
\r
516 swarmmove = steerlib_flock(500,75,700,500);
\r
517 reprellmove = steerlib_repell(self.owner.enemy.origin+self.enemy.velocity,2000) * 700;
\r
519 if(vlen(dodgemove) == 0)
\r
521 self.pos1 = steerlib_wander(0.5,0.1,self.pos1);
\r
522 wandermove = self.pos1 * 50;
\r
525 self.pos1 = normalize(self.velocity);
\r
527 dodgemove = dodgemove * vlen(self.velocity) * 5;
\r
529 newmove = swarmmove + reprellmove + wandermove + dodgemove;
\r
530 self.velocity = movelib_inertmove_byspeed(newmove,300,0.2,0.9);
\r
531 //self.velocity = movelib_inertmove(dodgemove,0.65);
\r
533 self.velocity = movelib_dragvec(0.01,0.6);
\r
535 self.angles = vectoangles(self.velocity);
\r
537 if(self.health <= 0)
\r
540 self.nextthink = time + 0.1;
\r
544 void spawn_flocker()
\r
548 flocker = spawn ();
\r
550 setorigin(flocker, self.origin + '0 0 32');
\r
551 setmodel (flocker, "models/turrets/rocket.md3");
\r
552 setsize (flocker, '-3 -3 -3', '3 3 3');
\r
554 flocker.flock_id = self.flock_id;
\r
555 flocker.classname = "flocker";
\r
556 flocker.owner = self;
\r
557 flocker.think = flocker_think;
\r
558 flocker.nextthink = time + random() * 5;
\r
559 PROJECTILE_MAKETRIGGER(flocker);
\r
560 flocker.movetype = MOVETYPE_BOUNCEMISSILE;
\r
561 flocker.effects = EF_LOWPRECISION;
\r
562 flocker.velocity = randomvec() * 300;
\r
563 flocker.angles = vectoangles(flocker.velocity);
\r
564 flocker.health = 10;
\r
565 flocker.pos1 = normalize(flocker.velocity + randomvec() * 0.1);
\r
567 self.cnt = self.cnt -1;
\r
571 void flockerspawn_think()
\r
578 self.nextthink = time + self.delay;
\r
582 void flocker_hunter_think()
\r
584 vector dodgemove,attractmove,newmove;
\r
588 self.angles_x = self.angles_x * -1;
\r
589 makevectors(self.angles);
\r
590 self.angles_x = self.angles_x * -1;
\r
593 if(vlen(self.enemy.origin - self.origin) < 64)
\r
597 self.enemy = world;
\r
603 e = findchainfloat(flock_id,self.flock_id);
\r
606 d = vlen(self.origin - e.origin);
\r
608 if(e != self.owner)
\r
620 attractmove = steerlib_attract(self.enemy.origin+self.enemy.velocity * 0.1,5000) * 1250;
\r
622 attractmove = normalize(self.velocity) * 200;
\r
624 dodgemove = steerlib_traceavoid(0.35,1500) * vlen(self.velocity);
\r
626 newmove = dodgemove + attractmove;
\r
627 self.velocity = movelib_inertmove_byspeed(newmove,1250,0.3,0.7);
\r
628 self.velocity = movelib_dragvec(0.01,0.5);
\r
631 self.angles = vectoangles(self.velocity);
\r
632 self.nextthink = time + 0.1;
\r
636 float globflockcnt;
\r
637 void spawnfunc_flockerspawn()
\r
639 precache_model ( "models/turrets/rocket.md3");
\r
640 precache_model("models/turrets/c512.md3");
\r
643 if(!self.cnt) self.cnt = 20;
\r
644 if(!self.delay) self.delay = 0.25;
\r
645 if(!self.flock_id) self.flock_id = globflockcnt;
\r
647 self.think = flockerspawn_think;
\r
648 self.nextthink = time + 0.25;
\r
650 self.enemy = spawn();
\r
652 setmodel(self.enemy, "models/turrets/rocket.md3");
\r
653 setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
\r
655 self.enemy.classname = "FLock Hunter";
\r
656 self.enemy.scale = 3;
\r
657 self.enemy.effects = EF_LOWPRECISION;
\r
658 self.enemy.movetype = MOVETYPE_BOUNCEMISSILE;
\r
659 PROJECTILE_MAKETRIGGER(self.enemy);
\r
660 self.enemy.think = flocker_hunter_think;
\r
661 self.enemy.nextthink = time + 10;
\r
662 self.enemy.flock_id = self.flock_id;
\r
663 self.enemy.owner = self;
\r