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