]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/steerlib.qc
forgot this one
[divverent/nexuiz.git] / data / qcsrc / server / steerlib.qc
1 /**\r
2     Uniform pull towards a point\r
3 **/\r
4 vector steerlib_pull(vector point)\r
5 {\r
6     return normalize(point - self.origin);\r
7 }\r
8 \r
9 /**\r
10     Uniform push from a point\r
11 **/\r
12 vector steerlib_push(vector point)\r
13 {\r
14     return normalize(self.origin - point);\r
15 }\r
16 \r
17 /**\r
18     Pull toward a point, The further away, the stronger the pull.\r
19 **/\r
20 vector steerlib_arrive(vector point,float maximal_distance)\r
21 {\r
22     float distance;\r
23     vector direction;\r
24 \r
25     distance = bound(0.001,vlen(self.origin - point),maximal_distance);\r
26     direction = normalize(point - self.origin);\r
27     return  direction * (distance / maximal_distance);\r
28 }\r
29 \r
30 /**\r
31     Pull toward a point increasing the pull the closer we get\r
32 **/\r
33 vector steerlib_attract(vector point, float maximal_distance)\r
34 {\r
35     float distance;\r
36     vector direction;\r
37 \r
38     distance = bound(0.001,vlen(self.origin - point),maximal_distance);\r
39     direction = normalize(point - self.origin);\r
40 \r
41     return  direction * (1-(distance / maximal_distance));\r
42 }\r
43 \r
44 vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense)\r
45 {\r
46     float distance;\r
47     vector direction;\r
48     float influense;\r
49 \r
50     distance  = bound(0.00001,vlen(self.origin - point),max_distance);\r
51     direction = normalize(point - self.origin);\r
52 \r
53     influense = 1 - (distance / max_distance);\r
54     influense = min_influense + (influense * (max_influense - min_influense));\r
55 \r
56     return  direction * influense;\r
57 }\r
58 \r
59 /*\r
60 vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)\r
61 {\r
62     //float distance;\r
63     vector current_direction;\r
64     vector target_direction;\r
65     float i_target,i_current;\r
66 \r
67     if(!distance)\r
68         distance = vlen(self.origin - point);\r
69 \r
70     distance = bound(0.001,distance,maximal_distance);\r
71 \r
72     target_direction = normalize(point - self.origin);\r
73     current_direction = normalize(self.velocity);\r
74 \r
75     i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);\r
76     i_current = 1 - i_target;\r
77 \r
78     // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);\r
79 \r
80     string s;\r
81     s = ftos(i_target);\r
82     bprint("IT: ",s,"\n");\r
83     s = ftos(i_current);\r
84     bprint("IC  : ",s,"\n");\r
85 \r
86     return  normalize((target_direction * i_target) + (current_direction * i_current));\r
87 }\r
88 */\r
89 /**\r
90     Move away from a point.\r
91 **/\r
92 vector steerlib_repell(vector point,float maximal_distance)\r
93 {\r
94     float distance;\r
95     vector direction;\r
96 \r
97     distance = bound(0.001,vlen(self.origin - point),maximal_distance);\r
98     direction = normalize(self.origin - point);\r
99 \r
100     return  direction * (1-(distance / maximal_distance));\r
101 }\r
102 \r
103 /**\r
104     Try to keep at ideal_distance away from point\r
105 **/\r
106 vector steerlib_standoff(vector point,float ideal_distance)\r
107 {\r
108     float distance;\r
109     vector direction;\r
110 \r
111     distance = vlen(self.origin - point);\r
112 \r
113 \r
114     if(distance < ideal_distance)\r
115     {\r
116         direction = normalize(self.origin - point);\r
117         return direction * (distance / ideal_distance);\r
118     }\r
119 \r
120     direction = normalize(point - self.origin);\r
121     return direction * (ideal_distance / distance);\r
122 \r
123 }\r
124 \r
125 /**\r
126     A random heading in a forward halfcicrle\r
127 \r
128     use like:\r
129     self.target = steerlib_waner(256,32,self.target)\r
130 \r
131     where range is the cicrle radius and tresh is how close we need to be to pick a new heading.\r
132 **/\r
133 vector steerlib_waner(float range,float tresh,vector oldpoint)\r
134 {\r
135     vector wander_point;\r
136     wander_point = v_forward - oldpoint;\r
137 \r
138     if (vlen(wander_point) > tresh)\r
139         return oldpoint;\r
140 \r
141     range = bound(0,range,1);\r
142 \r
143     wander_point = self.origin + v_forward * 128;\r
144     wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);\r
145 \r
146     return normalize(wander_point - self.origin);\r
147 }\r
148 \r
149 /**\r
150     Dodge a point. dont work to well.\r
151 **/\r
152 vector steerlib_dodge(vector point,vector dodge_dir,float min_distance)\r
153 {\r
154     float distance;\r
155 \r
156     distance = max(vlen(self.origin - point),min_distance);\r
157 \r
158     return dodge_dir * (min_distance/distance);\r
159 }\r
160 \r
161 /**\r
162     flocking by .flock_id\r
163     Group will move towards the unified direction while keeping close to eachother.\r
164 **/\r
165 .float flock_id;\r
166 vector steerlib_flock(float radius, float standoff,float separation_force,float flock_force)\r
167 {\r
168     entity flock_member;\r
169     vector push,pull;\r
170     float ccount;\r
171 \r
172     flock_member = findradius(self.origin,radius);\r
173     while(flock_member)\r
174     {\r
175         if(flock_member != self)\r
176         if(flock_member.flock_id == self.flock_id)\r
177         {\r
178             ++ccount;\r
179             push = push + (steerlib_repell(flock_member.origin,standoff) * separation_force);\r
180             pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity,radius) * flock_force);\r
181         }\r
182         flock_member = flock_member.chain;\r
183     }\r
184     return push + (pull* (1 / ccount));\r
185 }\r
186 \r
187 /**\r
188     All members want to be in the center, and keep away from eachother.\r
189     The furtehr form the center the more they want to be there.\r
190 \r
191     This results in a aligned movement (?!) much like flocking.\r
192 **/\r
193 vector steerlib_swarm(float radius, float standoff,float separation_force,float swarm_force)\r
194 {\r
195     entity swarm_member;\r
196     vector force,center;\r
197     float ccount;\r
198 \r
199     swarm_member = findradius(self.origin,radius);\r
200 \r
201     while(swarm_member)\r
202     {\r
203         if(swarm_member.flock_id == self.flock_id)\r
204         {\r
205             ++ccount;\r
206             center = center + swarm_member.origin;\r
207             force = force + (steerlib_repell(swarm_member.origin,standoff) * separation_force);\r
208         }\r
209         swarm_member = swarm_member.chain;\r
210     }\r
211 \r
212     center = center * (1 / ccount);\r
213     force = force + (steerlib_arrive(center,radius) * swarm_force);\r
214 \r
215     return force;\r
216 }\r
217 \r
218 /**\r
219     Steer towards the direction least obstructed.\r
220     Run four tracelines in a forward funnel, bias each diretion negative if something is found there.\r
221 **/\r
222 vector steerlib_traceavoid(float pitch,float length)\r
223 {\r
224     vector vup_left,vup_right,vdown_left,vdown_right;\r
225     float fup_left,fup_right,fdown_left,fdown_right;\r
226     vector upwish,downwish,leftwish,rightwish;\r
227     vector v_left,v_down;\r
228 \r
229     v_left = v_right * -1;\r
230     v_down = v_up * -1;\r
231 \r
232     vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;\r
233     traceline(self.origin, self.origin +  vup_left,MOVE_NOMONSTERS,self);\r
234     fup_left = trace_fraction;\r
235 \r
236     //te_lightning1(world,self.origin, trace_endpos);\r
237 \r
238     vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;\r
239     traceline(self.origin,self.origin + vup_right ,MOVE_NOMONSTERS,self);\r
240     fup_right = trace_fraction;\r
241 \r
242     //te_lightning1(world,self.origin, trace_endpos);\r
243 \r
244     vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;\r
245     traceline(self.origin,self.origin + vdown_left,MOVE_NOMONSTERS,self);\r
246     fdown_left = trace_fraction;\r
247 \r
248     //te_lightning1(world,self.origin, trace_endpos);\r
249 \r
250     vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;\r
251     traceline(self.origin,self.origin + vdown_right,MOVE_NOMONSTERS,self);\r
252     fdown_right = trace_fraction;\r
253 \r
254     //te_lightning1(world,self.origin, trace_endpos);\r
255 \r
256     upwish    = v_up    * (fup_left   + fup_right);\r
257     downwish  = v_down  * (fdown_left + fdown_right);\r
258     leftwish  = v_left  * (fup_left   + fdown_left);\r
259     rightwish = v_right * (fup_right  + fdown_right);\r
260 \r
261     return (upwish+leftwish+downwish+rightwish) * 0.25;\r
262 \r
263 }\r
264 \r
265 \r
266 \r
267 //////////////////////////////////////////////\r
268 //     Testting                             //\r
269 // Everything below this point is a mess :D //\r
270 //////////////////////////////////////////////\r
271 //#define TLIBS_TETSLIBS\r
272 #ifdef TLIBS_TETSLIBS\r
273 void flocker_die()\r
274 {\r
275         sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);\r
276 \r
277         pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);\r
278 \r
279     self.owner.cnt += 1;\r
280     self.owner = world;\r
281 \r
282     self.nextthink = time;\r
283     self.think = SUB_Remove;\r
284 }\r
285 \r
286 \r
287 void flocker_think()\r
288 {\r
289     vector dodgemove,swarmmove;\r
290     vector reprellmove,wandermove,newmove;\r
291 \r
292     self.angles_x = self.angles_x * -1;\r
293     makevectors(self.angles);\r
294     self.angles_x = self.angles_x * -1;\r
295 \r
296     dodgemove   = steerlib_traceavoid(0.35,1000);\r
297     swarmmove   = steerlib_flock(500,75,700,500);\r
298     reprellmove = steerlib_repell(self.owner.enemy.origin+self.enemy.velocity,2000) * 700;\r
299 \r
300     if(vlen(dodgemove) == 0)\r
301     {\r
302         self.pos1 = steerlib_waner(0.5,0.1,self.pos1);\r
303         wandermove  = self.pos1 * 50;\r
304     }\r
305     else\r
306         self.pos1 = normalize(self.velocity);\r
307 \r
308     dodgemove = dodgemove * vlen(self.velocity) * 5;\r
309 \r
310     newmove = swarmmove + reprellmove + wandermove + dodgemove;\r
311     self.velocity = movelib_inertmove_byspeed(newmove,300,0.2,0.9);\r
312     //self.velocity  = movelib_inertmove(dodgemove,0.65);\r
313 \r
314     self.velocity = movelib_dragvec(0.01,0.6);\r
315 \r
316     self.angles = vectoangles(self.velocity);\r
317 \r
318     if(self.health <= 0)\r
319         flocker_die();\r
320     else\r
321         self.nextthink = time + 0.1;\r
322 }\r
323 \r
324 \r
325 void spawn_flocker()\r
326 {\r
327     entity flocker;\r
328 \r
329     flocker = spawn ();\r
330 \r
331     setorigin(flocker, self.origin + '0 0 32');\r
332     setmodel (flocker, "models/turrets/rocket.md3");\r
333     setsize (flocker, '-3 -3 -3', '3 3 3');\r
334 \r
335     flocker.flock_id   = self.flock_id;\r
336     flocker.classname  = "flocker";\r
337     flocker.owner      = self;\r
338     flocker.think      = flocker_think;\r
339     flocker.nextthink  = time + random() * 5;\r
340     flocker.solid      = SOLID_BBOX;\r
341     flocker.movetype   = MOVETYPE_BOUNCEMISSILE;\r
342     flocker.effects    = EF_LOWPRECISION;\r
343     flocker.velocity   = randomvec() * 300;\r
344     flocker.angles     = vectoangles(flocker.velocity);\r
345     flocker.health     = 10;\r
346     flocker.pos1      = normalize(flocker.velocity + randomvec() * 0.1);\r
347 \r
348     self.cnt = self.cnt -1;\r
349 \r
350 }\r
351 \r
352 void flockerspawn_think()\r
353 {\r
354 \r
355 \r
356     if(self.cnt > 0)\r
357         spawn_flocker();\r
358 \r
359     self.nextthink = time + self.delay;\r
360 \r
361 }\r
362 \r
363 void flocker_hunter_think()\r
364 {\r
365     vector dodgemove,attractmove,newmove;\r
366     entity e,ee;\r
367     float d,bd;\r
368 \r
369     self.angles_x = self.angles_x * -1;\r
370     makevectors(self.angles);\r
371     self.angles_x = self.angles_x * -1;\r
372 \r
373     if(self.enemy)\r
374     if(vlen(self.enemy.origin - self.origin) < 64)\r
375     {\r
376         ee = self.enemy;\r
377         ee.health = -1;\r
378         self.enemy = world;\r
379 \r
380     }\r
381 \r
382     if(!self.enemy)\r
383     {\r
384         e = findchainfloat(flock_id,self.flock_id);\r
385         while(e)\r
386         {\r
387             d = vlen(self.origin - e.origin);\r
388 \r
389             if(e != self.owner)\r
390             if(e != ee)\r
391             if(d > bd)\r
392             {\r
393                 self.enemy = e;\r
394                 bd = d;\r
395             }\r
396             e = e.chain;\r
397         }\r
398     }\r
399 \r
400     if(self.enemy)\r
401         attractmove = steerlib_attract(self.enemy.origin+self.enemy.velocity * 0.1,5000) * 1250;\r
402     else\r
403         attractmove = normalize(self.velocity) * 200;\r
404 \r
405     dodgemove = steerlib_traceavoid(0.35,1500) * vlen(self.velocity);\r
406 \r
407     newmove = dodgemove + attractmove;\r
408     self.velocity = movelib_inertmove_byspeed(newmove,1250,0.3,0.7);\r
409     self.velocity = movelib_dragvec(0.01,0.5);\r
410 \r
411 \r
412     self.angles = vectoangles(self.velocity);\r
413     self.nextthink = time + 0.1;\r
414 }\r
415 \r
416 \r
417 float globflockcnt;\r
418 void spawnfunc_flockerspawn()\r
419 {\r
420     precache_model ( "models/turrets/rocket.md3");\r
421     precache_model("models/turrets/c512.md3");\r
422     ++globflockcnt;\r
423 \r
424     if(!self.cnt)      self.cnt = 20;\r
425     if(!self.delay)    self.delay = 0.25;\r
426     if(!self.flock_id) self.flock_id = globflockcnt;\r
427 \r
428     self.think     = flockerspawn_think;\r
429     self.nextthink = time + 0.25;\r
430 \r
431     self.enemy = spawn();\r
432 \r
433     setmodel(self.enemy, "models/turrets/rocket.md3");\r
434     setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));\r
435 \r
436     self.enemy.classname = "FLock Hunter";\r
437     self.enemy.scale     = 3;\r
438     self.enemy.effects   = EF_LOWPRECISION;\r
439     self.enemy.movetype  = MOVETYPE_BOUNCEMISSILE;\r
440     self.enemy.solid     = SOLID_BBOX;\r
441     self.enemy.think     = flocker_hunter_think;\r
442     self.enemy.nextthink = time + 10;\r
443     self.enemy.flock_id  = self.flock_id;\r
444     self.enemy.owner     = self;\r
445 }\r
446 #endif\r
447 \r
448 \r