]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/vehicles/racer.qc
Better "drop to ground" for vehicles and moving turrets.
[divverent/nexuiz.git] / data / qcsrc / server / vehicles / racer.qc
1 #define RACER_MIN '-80 -80 -40'
2 #define RACER_MAX '80 80 40'
3 #define RACER_TICRATE 0.05
4
5 void racer_exit(float eject);
6 void racer_enter();
7 //void racer_think();
8
9 float racer_power_air;
10 float racer_power_solid;
11 float racer_power_min;
12 float racer_anglestabilizer;
13 float racer_springlength;
14
15 float racer_healthmax;
16 float racer_shieldmax;
17 float racer_energymax;
18
19 float racer_pitchspeed;
20 float racer_turnspeed;
21 float racer_turnroll;
22 float racer_speed_forward;
23 float racer_speed_strafe;
24
25 float  jetfromtag_power;
26 float  jetfromtag_normpower;
27 vector jetfromtag_origin;
28 float  jetfromtag_groundcontact;
29
30 //pow(drag, exp)
31
32 void racer_loadsettings()
33 {
34     racer_power_min         = cvar("g_vehicle_racer_power_min")   * 0.25;
35     racer_power_air         = cvar("g_vehicle_racer_power_air")   * 0.25;
36     racer_power_solid       = cvar("g_vehicle_racer_power_solid") * 0.25;
37     racer_springlength      = cvar("g_vehicle_racer_springlength");
38     racer_anglestabilizer   = cvar("g_vehicle_racer_anglestabilizer");
39     racer_pitchspeed        = cvar("g_vehicle_racer_pitchspeed");
40     racer_turnspeed         = cvar("g_vehicle_racer_turnspeed");
41     racer_turnroll          = cvar("g_vehicle_racer_turnroll");
42     racer_speed_forward     = cvar("g_vehicle_racer_speed_forward");
43     racer_speed_strafe      = cvar("g_vehicle_racer_speed_strafe");
44
45     racer_healthmax = cvar("g_vehicle_racer_health");
46     racer_shieldmax = cvar("g_vehicle_racer_shield");
47     racer_energymax = cvar("g_vehicle_racer_energy");
48
49 }
50
51 vector racer_jetfromtag(string tagname)
52 {
53     vector force_dir;
54     float  air_frac, solid_frac, air_pwr, solid_pwr;
55
56     jetfromtag_origin = gettaginfo(self,gettagindex(self,tagname));
57     v_forward  = normalize(v_forward) * -1;
58
59     force_dir = jetfromtag_origin - (v_forward  * racer_springlength);
60     traceline(jetfromtag_origin, force_dir, MOVE_NORMAL, self);
61     //te_lightning1(world,jetfromtag_origin, force_dir);
62
63     //trace_fraction *= trace_fraction;
64
65     solid_frac = 1 - trace_fraction;
66     air_frac = trace_fraction;
67
68     if (trace_fraction != 1.0)
69         jetfromtag_groundcontact = 1;
70
71     solid_pwr = solid_frac * racer_power_solid;
72     air_pwr   = air_frac * racer_power_air;
73
74     jetfromtag_power     = solid_pwr + air_pwr;
75     jetfromtag_normpower = jetfromtag_power / (racer_power_air + racer_power_solid);
76
77     //te_lightning1(world,jetfromtag_origin,jetfromtag_origin + normalize(self.origin - force_dir) * max(jetfromtag_power, racer_power_min));
78     //return normalize(self.origin - force_dir) * max(jetfromtag_power, racer_power_min);
79     return v_forward  * max(jetfromtag_power, racer_power_min);
80 }
81
82 void racer_align4point()
83 {
84     vector push_vector;
85     float fl_push, fr_push, bl_push, br_push;
86
87     jetfromtag_groundcontact = 0;
88
89     push_vector = racer_jetfromtag("tag_engine_fr");
90     fr_push = jetfromtag_normpower;
91     traceline(jetfromtag_origin, jetfromtag_origin + self.velocity * frametime, MOVE_NORMAL,self);
92     if(trace_fraction != 1)
93         self.velocity += normalize(self.origin - trace_endpos) * (vlen(self.velocity) * 1.25);
94
95     push_vector += racer_jetfromtag("tag_engine_fl");
96     fl_push = jetfromtag_normpower;
97     traceline(jetfromtag_origin, jetfromtag_origin + self.velocity * frametime, MOVE_NORMAL,self);
98     if(trace_fraction != 1)
99         self.velocity += normalize(self.origin - trace_endpos) * (vlen(self.velocity) * 1.25);
100
101     push_vector += racer_jetfromtag("tag_engine_br");
102     br_push = jetfromtag_normpower;
103     traceline(jetfromtag_origin, jetfromtag_origin + self.velocity * frametime, MOVE_NORMAL,self);
104     if(trace_fraction != 1)
105         self.velocity += normalize(self.origin - trace_endpos) * (vlen(self.velocity) * 1.25);
106
107     push_vector += racer_jetfromtag("tag_engine_bl");
108     bl_push = jetfromtag_normpower;
109     traceline(jetfromtag_origin, jetfromtag_origin + self.velocity * frametime, MOVE_NORMAL,self);
110     if(trace_fraction != 1)
111         self.velocity += normalize(self.origin - trace_endpos) * (vlen(self.velocity) * 1.25);
112
113     self.velocity =  self.velocity + (push_vector * frametime);
114     self.velocity_z -= sv_gravity * frametime;
115
116     push_vector_x = (fl_push - bl_push);
117     push_vector_x += (fr_push - br_push);
118     push_vector_x *= 360;
119
120     push_vector_z = (fr_push - fl_push);
121     push_vector_z += (br_push - bl_push);
122     push_vector_z *= 360;
123
124     if (push_vector_z == 1.0)
125         if(self.angles_z > 0)
126             self.angles_z = max(0, self.angles_z - (racer_anglestabilizer * frametime));
127         else
128             self.angles_z = min(0, self.angles_z + (racer_anglestabilizer * frametime));
129     else
130         self.angles_z += push_vector_z * frametime;
131
132     if (push_vector_x == 1.0)
133         if(self.angles_x > 0)
134             self.angles_x = max(0, self.angles_x - (racer_anglestabilizer * frametime));
135         else
136             self.angles_x = min(0, self.angles_x + (racer_anglestabilizer * frametime));
137     else
138         self.angles_x += push_vector_x * frametime;
139 }
140
141 void racer_bolt_explode()
142 {
143     vector org2;
144
145     org2 = findbetterlocation (self.origin, 8);
146     pointparticles(particleeffectnum("laser_impact"), org2, trace_plane_normal * 1000, 1);
147     RadiusDamage (self, self.realowner, cvar("g_vehicle_racer_laser_damage"), 0, cvar("g_vehicle_racer_laser_radius"), world, 150, DEATH_WAKIGUN, world);
148     sound (self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_NORM);
149
150     remove (self);
151 }
152
153 void racer_rocket_explode()
154 {
155     vector org2;
156
157     //if not(self.owner)
158     //    self.owner = self.realowner;
159
160     sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
161     org2 = findbetterlocation (self.origin, 16);
162     pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
163     RadiusDamage (self, self.realowner ,cvar("g_vehicle_racer_rocket_damage"), 0, cvar("g_vehicle_racer_rocket_radius"), world, 150, DEATH_WAKIROCKET, world);
164
165     remove (self);
166 }
167
168 void racer_rocket_touch()
169 {
170     if(other.owner == self.owner)
171         return;
172
173     PROJECTILE_TOUCH;
174     /*
175     if(pointcontents(self.origin) == CONTENT_SKY)
176     {
177         self.think = SUB_Remove;
178         self.nextthink = time;
179         return;
180     }
181     */
182
183     racer_rocket_explode();
184 }
185
186 void racer_fire_cannon(string tagname)
187 {
188     entity bolt;
189
190     bolt = spawn();
191     bolt.solid           = SOLID_BBOX;
192     bolt.movetype        = MOVETYPE_FLYMISSILE;
193     bolt.flags           = FL_PROJECTILE | FL_NOTARGET;
194     bolt.owner           = self;
195     bolt.realowner       = self.owner;
196     bolt.touch           = racer_bolt_explode;
197     bolt.think           = racer_bolt_explode;
198     bolt.nextthink       = time + 9;
199     bolt.bot_dodge       = TRUE;
200     bolt.bot_dodgerating = cvar("g_vehicle_racer_laser_damage");
201     setorigin(bolt, gettaginfo(self,gettagindex(self,tagname)));
202     bolt.velocity = v_forward * cvar("g_vehicle_racer_laser_speed");
203
204     CSQCProjectile(bolt, TRUE, PROJECTILE_LASER, TRUE);
205 }
206
207 void racer_rocket_think()
208 {
209     vector newdir,olddir;
210     float oldspeed, newspeed;
211
212     self.nextthink  = time;
213
214     if ((self.owner.deadflag != DEAD_NO) || (self.cnt < time))
215     {
216         racer_rocket_explode();
217         return;
218     }
219
220     if not (self.realowner.vehicle)
221     {
222         UpdateCSQCProjectile(self);
223         return;
224     }
225
226     self.solid      = SOLID_BBOX;
227     self.touch      = racer_rocket_explode;
228
229     olddir = normalize(self.velocity);
230     oldspeed = vlen(self.velocity);
231
232     newdir = normalize((0.5 * (self.enemy.absmin + self.enemy.absmax)) - self.origin);
233     newspeed = oldspeed + self.lip;
234
235     self.velocity = normalize(olddir + newdir * self.wait) * newspeed;
236
237     UpdateCSQCProjectile(self);
238 }
239
240 void racer_fire_rocket(string tagname)
241 {
242     entity rocket;
243     dprint("self.owner=",self.owner.netname,"\n");
244
245     rocket = spawn();
246     setsize (rocket, '-1 -1 -1', '1 1 1');
247     rocket.lip             = cvar("g_vehicle_racer_rocket_accel") * sys_frametime;
248     rocket.wait            = cvar("g_vehicle_racer_rocket_turnrate");
249     rocket.solid           = SOLID_BBOX;
250     rocket.movetype        = MOVETYPE_FLYMISSILE;
251     rocket.flags           = FL_PROJECTILE;
252     rocket.owner           = self;
253     rocket.realowner       = self.owner;
254     rocket.touch           = racer_rocket_touch;
255     rocket.bot_dodge       = TRUE;
256     rocket.bot_dodgerating = cvar("g_vehicle_racer_rocket_damage");
257     setorigin(rocket, gettaginfo(self,gettagindex(self,tagname)));
258
259     if( (self.tur_head.gun1) && (self.tur_head.cnt > time))
260         rocket.enemy = self.tur_head.gun1;
261
262     if(rocket.enemy)
263     {
264         rocket.cnt             = time + 9;
265         rocket.velocity = v_forward * cvar("g_vehicle_racer_rocket_speed");
266         rocket.think = racer_rocket_think;
267         rocket.nextthink = time;
268         CSQCProjectile(rocket, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound
269         //dprint("Tracking...", rocket.enemy.netname, " (", rocket.enemy.classname, ")\n");
270     }
271     else
272     {
273         rocket.velocity = v_forward * cvar("g_vehicle_racer_rocket_speed");
274         rocket.think = racer_rocket_explode;
275         rocket.nextthink = time + 9;
276         CSQCProjectile(rocket, TRUE, PROJECTILE_ROCKET, TRUE);
277     }
278 }
279
280 float racer_customizeentityforclient()
281 {
282
283     if(self.deadflag == DEAD_DEAD)
284         return FALSE;
285
286     /*
287     if(other == self.owner)
288         self.alpha = -1;
289     else
290         self.alpha = 1;
291     */
292
293     return TRUE;
294 }
295
296 float racer_pplug()
297 {
298     entity player, racer;
299     float ftmp, ftmp2;
300     vector df;
301
302
303     if(cvar("g_vehicle_racer_reload"))
304     {
305         racer_loadsettings();
306         cvar_set("g_vehicle_racer_reload","0");
307     }
308
309     player          = self;
310     racer           = self.vehicle;
311
312     player.BUTTON_ZOOM = 0;
313     player.BUTTON_CROUCH = 0;
314
315     self = racer;
316
317     if(player.BUTTON_USE)
318     {
319         self = racer;
320         racer_exit(0);
321         self = player;
322         return 0;
323     }
324
325     if(racer.deadflag != DEAD_NO)
326     {
327         self = player;
328         player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0;
329         return 1;
330     }
331
332
333     racer_align4point();
334
335     racer.angles_x *= -1;
336     makevectors(racer.angles);
337
338     // Rotate Body
339     ftmp = racer_turnspeed * sys_frametime;
340     ftmp2 = ftmp * -1;
341
342     ftmp = bound(ftmp2,shortangle_f(player.v_angle_y - racer.angles_y,racer.angles_y),ftmp);
343     ftmp2 = safeangle(racer.angles_y + ftmp);
344
345     // Roll
346     ftmp = bound(-90,shortangle_f(player.v_angle_z + ((racer.angles_y - ftmp2) * racer_turnroll), racer.angles_z),90);
347     ftmp = safeangle(racer.angles_z + ftmp);
348     racer.angles_z = ftmp;
349
350     // Turn
351     racer.angles_y = ftmp2;
352
353     // Pitch Body
354     ftmp = racer_pitchspeed * sys_frametime;
355     ftmp2 = ftmp * -1;
356
357     ftmp = bound(ftmp2,shortangle_f(player.v_angle_x - racer.angles_x,racer.angles_x),ftmp);
358     //ftmp = 0;
359     racer.angles_x = safeangle(racer.angles_x + ftmp);
360     racer.angles_x *= -1;
361
362     if(player.movement_x != 0)
363     {
364         if(player.movement_x > 0)
365             df += v_forward  * racer_speed_forward;
366         else if(player.movement_x < 0)
367             df -= v_forward  * racer_speed_forward;
368     }
369
370     if(player.movement_y != 0)
371     {
372         if(player.movement_y < 0)
373             df -= v_right * racer_speed_strafe;
374         else if(player.movement_y > 0)
375             df += v_right * racer_speed_strafe;
376     }
377
378     // limit _z to avoid flying on normal thrust
379     if(df_z > 0)
380         df_z = min(df_z,700);
381
382
383     // Afterburn
384     //if (jetfromtag_groundcontact)
385     if (player.BUTTON_JUMP)
386     if(racer.vehicle_energy >= (cvar("g_vehicle_racer_speed_afterburn_cost")* frametime))
387     {
388         racer.wait = time + cvar("g_vehicle_racer_energy_usepause");
389         racer.vehicle_energy -= cvar("g_vehicle_racer_speed_afterburn_cost") * frametime;
390         df += (v_forward * cvar("g_vehicle_racer_speed_afterburn"));
391     }
392
393     racer.velocity  += df * frametime;
394
395     df = (vlen(racer.velocity) * cvar("g_vehicle_racer_downforce") * v_up) * frametime;
396     racer.velocity  = racer.velocity - df;
397     player.movement = racer.velocity;
398
399     if(cvar("g_vehicle_racer_drag"))
400         racer.velocity  = movelib_dragvec(cvar("g_vehicle_racer_drag"), cvar("g_vehicle_racer_dragexp"));
401
402     if(self.owner.cursor_trace_ent)
403     {
404         //dprint("Lock: ", self.owner.cursor_trace_ent.classname, "\n");
405         //if not (self.tur_head.enemy)
406         //    bprint(self.owner,"Locked: ",
407         self.tur_head.gun1 = self.owner.cursor_trace_ent;
408         self.tur_head.cnt = time + 1;
409     }
410
411     if(player.BUTTON_ATCK)
412     if(time > racer.attack_finished_single)
413     if(racer.vehicle_energy >= cvar("g_vehicle_racer_laser_cost"))
414     {
415         racer.vehicle_energy -= cvar("g_vehicle_racer_laser_cost");
416         racer.wait = time + cvar("g_vehicle_racer_energy_usepause");
417
418         if(racer.cnt)
419         {
420             racer_fire_cannon("tag_fire1");
421             racer.cnt = 0;
422         }
423         else
424         {
425             racer_fire_cannon("tag_fire2");
426             racer.cnt = 1;
427         }
428         racer.attack_finished_single = time + cvar("g_vehicle_racer_laser_refire");
429     }
430
431     if(player.BUTTON_ATCK2)
432     if(time > racer.delay)
433     {
434         racer_fire_rocket("tag_rocket_r");
435         racer_fire_rocket("tag_rocket_l");
436         racer.delay = time + cvar("g_vehicle_racer_rocket_refire");
437         racer.lip = time;
438
439     }
440
441     player.vehicle_reload1 = (time - racer.lip) / (racer.delay-racer.lip);
442     //player.vehicle_energy = racer.vehicle_energy;
443
444     vehicle_stdproc_shiledregen(racer_shieldmax, frametime);
445     vehicle_stdproc_healthregen(racer_healthmax, frametime);
446
447     if (racer.wait < time)
448         vehicle_stdproc_energyregen(racer_energymax, frametime);
449     else
450         player.vehicle_energy = (racer.vehicle_energy / racer_energymax);
451
452     self = player;
453
454     player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0;
455     setorigin(player,racer.origin + '0 0 32');
456     player.velocity = racer.velocity;
457
458     return 1;
459 }
460
461 void racer_exitthink()
462 {
463     float a, b, c;
464
465     self.nextthink = time;
466
467     a = racer_anglestabilizer;
468     b = racer_springlength;
469     c = racer_power_solid;
470
471     racer_anglestabilizer = 36;
472     racer_springlength = 96;
473     racer_power_solid = 300;
474
475     racer_align4point();
476
477     if(self.velocity_z < 0)
478         self.velocity_z *= 0.95;
479
480     racer_anglestabilizer = a;
481     racer_springlength = b;
482     racer_power_solid = c;
483
484     self.velocity_x *= 0.95;
485     self.velocity_y *= 0.95;
486 }
487
488 void racer_spawnthink()
489 {
490     float a, b, c;
491     vector dorg;
492
493     self.nextthink = time;
494
495     a = racer_anglestabilizer;
496     b = racer_springlength;
497     c = racer_power_solid;
498
499     racer_anglestabilizer = 36;
500     racer_springlength = 96;
501     racer_power_solid = 300;
502
503     // self.velocity_z += sin(time * 128) * 4;
504
505     racer_align4point();
506
507     if(self.velocity_z < 0)
508         self.velocity_z *= 0.98;
509
510     racer_anglestabilizer = a;
511     racer_springlength = b;
512     racer_power_solid = c;
513
514     self.velocity_x *= 0.95;
515     self.velocity_y *= 0.95;
516
517     dorg = self.pos1 - self.origin ;
518
519     self.velocity_x = bound(-32, self.velocity_x + dorg_x, 32);
520     self.velocity_y = bound(-32, self.velocity_y + dorg_y, 32);
521 }
522
523 void racer_enter()
524 {
525     self.owner = other;
526
527
528     self.nextthink = 0;
529     self.flags               = 0;
530     self.vehicle_hudmodel.viewmodelforclient = self.owner;
531     self.colormap             = self.owner.colormap;
532
533     self.owner.PlayerPhysplug = racer_pplug;
534     self.owner.takedamage     = DAMAGE_NO;
535     self.owner.event_damage   = SUB_Null;
536     self.owner.vehicle        = self;
537     self.owner.angles = self.angles;
538     self.owner.solid          = SOLID_NOT;
539     self.owner.movetype       = MOVETYPE_NOCLIP;
540     self.owner.alpha          = -1;
541     self.owner.hud            = HUD_WAKIZASHI;
542     self.owner.effects        |= EF_NODRAW;
543     self.owner.view_ofs = '0 0 0';
544
545     self.owner.vehicle_health = (self.vehicle_health / cvar("g_vehicle_racer_health"));
546     self.owner.vehicle_shield = (self.vehicle_shield / cvar("g_vehicle_racer_shield"));
547
548     setorigin(other,self.origin + '0 0 32');
549     other.velocity = self.velocity;
550
551     other.flags &~= FL_ONGROUND;
552     msg_entity = other;
553     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
554     WriteEntity( MSG_ONE, self.vehicle_viewport);
555
556     WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES
557     WriteAngle(MSG_ONE,  self.angles_x * -1);    // tilt
558     WriteAngle(MSG_ONE,  self.angles_y);    // yaw
559     WriteAngle(MSG_ONE,  0);                // roll
560 }
561
562 void racer_spawn();
563 void racer_return()
564 {
565     pointparticles(particleeffectnum("teleport"), self.enemy.origin + '0 0 64', '0 0 0', 1);
566     self.enemy.think = racer_spawn;
567     self.enemy.nextthink = time;
568     remove(self);
569 }
570
571 void racer_exit(float eject)
572 {
573         self.colormap   = 1024;
574         self.flags      = FL_NOTARGET;
575
576     if not (self.owner)
577         return;
578
579     msg_entity = self.owner;
580     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
581     WriteEntity( MSG_ONE, self.owner);
582
583     WriteByte (MSG_ONE, SVC_SETVIEWANGLES);    // 10 = SVC_SETVIEWANGLES
584     WriteAngle(MSG_ONE,  0);                   // tilt
585     WriteAngle(MSG_ONE,  self.angles_y); // yaw
586     WriteAngle(MSG_ONE,  0);                   // roll
587
588     if (self.deadflag == DEAD_NO)
589     {
590         self.think = racer_exitthink;
591         self.nextthink = time;
592     }
593
594     self.owner.takedamage     = DAMAGE_AIM;
595     self.owner.solid          = SOLID_SLIDEBOX;
596     self.owner.movetype       = MOVETYPE_WALK;
597
598     setsize(self.owner,PL_MIN,PL_MAX);
599
600     self.owner.effects        &~= EF_NODRAW;
601     self.owner.alpha          = 1;
602     self.owner.PlayerPhysplug = SUB_Null;
603     self.owner.vehicle        = world;
604         self.owner.view_ofs       = PL_VIEW_OFS;
605         self.owner.event_damage   = PlayerDamage;
606         self.owner.hud            = HUD_NORMAL;
607
608     self.vehicle_hudmodel.viewmodelforclient = self;
609
610         if(eject)
611         {
612             makevectors(self.angles);
613             setorigin(self.owner,self.origin + v_forward * 100);
614             self.owner.velocity = (v_up + v_forward * 0.25) * 750;
615         }
616         else
617         {
618             self.owner.velocity = (v_forward) * -150;
619         setorigin(self.owner,self.origin - v_forward * 128);
620         }
621
622     self.owner = world;
623
624     if (self.deadflag != DEAD_NO)
625     {
626         entity ret;
627         ret = spawn();
628         ret.enemy = self;
629         ret.think = racer_return;
630         ret.nextthink = time + cvar("g_vehicle_racer_respawntime");
631     }
632 }
633
634 void racer_touch()
635 {
636     if(self.owner)
637     {
638         if(vlen(self.velocity) == 0)
639             return;
640
641         if(other.classname != "player")
642             return;
643
644         vector a;
645         a = normalize(other.origin - self.origin);
646         a = a - normalize(self.velocity);
647
648         return;
649     }
650
651     if(other.classname != "player")
652         return;
653
654     if(other.deadflag != DEAD_NO)
655         return;
656
657     if(other.vehicle != world)
658         return;
659
660     racer_enter();
661 }
662
663 /*
664 float racer_customizeentityforclient()
665 {
666     if(self.deadflag == DEAD_DEAD)
667         return FALSE;
668
669     return TRUE;
670 }
671 */
672
673 void racer_spawn()
674 {
675     self.think = racer_spawnthink;
676     self.nextthink = time;
677
678     self.flags      = FL_NOTARGET;
679     self.effects   = 0;
680
681     self.vehicle_health = racer_healthmax;
682     self.vehicle_shield = racer_shieldmax;
683
684     self.event_damage = vehicle_stdproc_damage;
685     self.touch      = racer_touch;
686
687     self.iscreature = TRUE;
688     self.scale      = 0.5;
689     self.movetype   = MOVETYPE_FLY;
690     self.solid      = SOLID_SLIDEBOX;
691     self.takedamage = DAMAGE_AIM;
692
693     self.alpha = 1;
694         self.colormap = 1024;
695         self.deadflag    = DEAD_NO;
696     self.bot_attack = TRUE;
697
698     self.vehicle_energy = 1;
699     self.vehicle_hudmodel.viewmodelforclient = self;
700
701     setorigin(self, self.pos1);
702     self.angles = self.pos2;
703
704     setsize(self,RACER_MIN * 0.5,RACER_MAX * 0.5);
705     pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1);
706     self.delay = time;
707 }
708
709
710 void racer_blowup()
711 {
712
713     sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
714     pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
715
716     self.deadflag    = DEAD_DEAD;
717     self.vehicle_exit(VHEF_NORMAL);
718     RadiusDamage (self, self, 250, 15, 250, world, 250, DEATH_WAKIBLOWUP, world);
719
720     self.alpha = -1;
721     self.nextthink  = time + cvar("g_vehicle_racer_respawntime");
722     self.think      = racer_spawn;
723     self.movetype   = MOVETYPE_NONE;
724     self.effects    = EF_NODRAW;
725
726     self.avelocity_z  = 0;
727     self.colormod = '0 0 0';
728
729     setorigin(self,self.pos1);
730 }
731
732 void racer_dietouch()
733 {
734     if(self.wait > time)
735         return;
736
737     self.wait = time + 0.75;
738
739     pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
740 }
741
742 void racer_die()
743 {
744     self.health       = 0;
745     self.event_damage = SUB_Null;
746     self.iscreature   = FALSE;
747     self.solid        = SOLID_NOT;
748     self.takedamage   = DAMAGE_NO;
749     self.touch        = racer_dietouch;
750     self.deadflag     = DEAD_DYING;
751     self.movetype     = MOVETYPE_BOUNCE;
752     self.wait = time;
753
754     pointparticles(particleeffectnum("rocket_explode"), findbetterlocation (self.origin, 16), '0 0 0', 1);
755
756     self.velocity     += '0 0 128';
757
758     if(random() < 0.5)
759         self.avelocity_z  = 16;
760     else
761         self.avelocity_z  = -16;
762
763     self.colormod = '-0.5 -0.5 -0.5';
764
765         self.think     = racer_blowup;
766         self.nextthink = time + 3;
767 }
768
769 void racer_dinit()
770 {
771
772     tracebox(self.origin + '0 0 100', RACER_MIN * 0.5, RACER_MAX * 0.5, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
773     setorigin(self,trace_endpos);
774
775     if (self.netname == "")
776         self.netname     = "Race PoD";
777
778     self.cvar_basename      = "g_vehicle_racer";
779
780     self.vehicle_viewport   = spawn();
781     self.vehicle_hudmodel   = spawn();
782     //self.ccamera            = spawn();
783
784     setorigin(self, self.origin);
785
786     setmodel(self,"models/vehicles/wakizashi.dpm");
787     setmodel(self.vehicle_hudmodel, "models/vehicles/wakizashi_cockpit.dpm");
788     setmodel (self.vehicle_viewport, "null");
789
790     setattachment(self.vehicle_hudmodel, self, "");
791     setattachment(self.vehicle_viewport, self, "tag_viewport");
792
793     self.vehicle_hudmodel.viewmodelforclient = self;
794     self.customizeentityforclient            = racer_customizeentityforclient;
795
796     self.tur_head     = spawn();
797
798     self.pos1         = self.origin;
799     self.pos2         = self.angles;
800     self.angles       = '0 0 0';
801     self.angles       = self.pos1;
802
803     self.vehicle_die  = racer_die;
804     self.vehicle_exit = racer_exit;
805
806     addstat(STAT_HUD, AS_INT,  hud);
807         addstat(STAT_VEHICLESTAT_HEALTH,  AS_FLOAT, vehicle_health);
808         addstat(STAT_VEHICLESTAT_SHIELD,  AS_FLOAT, vehicle_shield);
809         addstat(STAT_VEHICLESTAT_ENERGY,  AS_FLOAT, vehicle_energy);
810
811         addstat(STAT_VEHICLESTAT_AMMO1,   AS_INT,   vehicle_ammo1);
812         addstat(STAT_VEHICLESTAT_RELOAD1, AS_FLOAT, vehicle_reload1);
813
814         addstat(STAT_VEHICLESTAT_AMMO2,   AS_INT,   vehicle_ammo2);
815         addstat(STAT_VEHICLESTAT_RELOAD2, AS_FLOAT, vehicle_reload2);
816
817     racer_spawn();
818 }
819
820 void spawnfunc_vehicle_racer()
821 {
822     g_turrets_common_precash();
823     racer_loadsettings();
824
825     self.vehicle_flags      = VHF_HASSHIELD | VHF_SHIELDREGEN;
826
827     /*
828     traceline(self.origin,self.origin - '0 0 2048',MOVE_WORLDONLY,self);
829     if(trace_startsolid)
830     {
831         dprint("WARNING: vehicle_racer placed in solid\n");
832         traceline(self.origin + '0 0 512' ,self.origin - '0 0 2048',MOVE_WORLDONLY,self);
833         if(trace_startsolid || trace_fraction == 1.0)
834         {
835             dprint("ERROR: vehicle_racer placed in more then 512 units into solid\n");
836             remove(self);
837             return;
838         }
839     }
840     */
841
842     if(trace_fraction != 1.0)
843         setorigin(self,trace_endpos + '0 0 128');
844     else
845         dprint("WARNING: vehicle_racer placed more then 2048 units above ground.\n");
846
847     precache_model ("models/vehicles/wakizashi.dpm");
848     precache_model ("models/vehicles/wakizashi_cockpit.dpm");
849     precache_model ("maps/bspmodel.bsp");
850
851
852     self.think = racer_dinit;
853     self.nextthink = time + 1;
854 }