]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/vehicles/racer.qc
New branch, old was br0ked. new aux. crosshait system.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / vehicles / racer.qc
1 #define RACER_MIN '-120 -120 -40'
2 #define RACER_MAX '120 120 40'
3 #define RACER_TICRATE 0.05
4
5 void racer_exit(float eject);
6 void racer_enter();
7
8 // Auto cvars
9 float autocvar_g_vehicle_racer_speed_afterburn;
10 float autocvar_g_vehicle_racer_afterburn_cost;
11
12 float autocvar_g_vehicle_racer_anglestabilizer;
13 float autocvar_g_vehicle_racer_downforce;
14
15 float autocvar_g_vehicle_racer_speed_forward;
16 float autocvar_g_vehicle_racer_speed_strafe;
17 float autocvar_g_vehicle_racer_springlength;
18 float autocvar_g_vehicle_racer_upforcedamper;
19
20 float autocvar_g_vehicle_racer_hovertype;
21 float autocvar_g_vehicle_racer_hoverpower;
22
23 float autocvar_g_vehicle_racer_turnroll;
24 float autocvar_g_vehicle_racer_turnspeed;
25 float autocvar_g_vehicle_racer_pitchspeed;
26
27 float autocvar_g_vehicle_racer_energy;
28 float autocvar_g_vehicle_racer_energy_regen;
29 float autocvar_g_vehicle_racer_energy_regen_pause;
30
31 float autocvar_g_vehicle_racer_health;
32 float autocvar_g_vehicle_racer_health_regen;
33 float autocvar_g_vehicle_racer_health_regen_pause;
34
35 float autocvar_g_vehicle_racer_shield;
36 float autocvar_g_vehicle_racer_shield_regen;
37 float autocvar_g_vehicle_racer_shield_regen_pause;
38
39 float autocvar_g_vehicle_racer_laser_cost;
40 float autocvar_g_vehicle_racer_laser_damage;
41 float autocvar_g_vehicle_racer_laser_radius;
42 float autocvar_g_vehicle_racer_laser_refire;
43 float autocvar_g_vehicle_racer_laser_speed;
44
45 float autocvar_g_vehicle_racer_rocket_accel;
46 float autocvar_g_vehicle_racer_rocket_damage;
47 float autocvar_g_vehicle_racer_rocket_radius;
48 float autocvar_g_vehicle_racer_rocket_refire;
49 float autocvar_g_vehicle_racer_rocket_speed;
50 float autocvar_g_vehicle_racer_rocket_turnrate;
51
52 float autocvar_g_vehicle_racer_respawntime;
53 float autocvar_g_vehicle_racer_collision_multiplier;
54
55 var vector racer_force_from_tag(string tag_name, float spring_length, float max_power);
56
57 void racer_align4point()
58 {
59     vector push_vector, v_add;
60     float fl_push, fr_push, bl_push, br_push;
61
62     push_vector  = racer_force_from_tag("tag_engine_fr", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower);
63     fr_push      = force_fromtag_normpower;
64     vehicles_sweap_collision(force_fromtag_origin, self.velocity, frametime, v_add, autocvar_g_vehicle_racer_collision_multiplier);
65
66     push_vector += racer_force_from_tag("tag_engine_fl", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower);
67     fl_push      = force_fromtag_normpower;
68     vehicles_sweap_collision(force_fromtag_origin, self.velocity, frametime, v_add, autocvar_g_vehicle_racer_collision_multiplier);
69
70     push_vector += racer_force_from_tag("tag_engine_br", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower);
71     br_push      = force_fromtag_normpower;
72     vehicles_sweap_collision(force_fromtag_origin, self.velocity, frametime, v_add, autocvar_g_vehicle_racer_collision_multiplier);
73
74     push_vector += racer_force_from_tag("tag_engine_bl", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower);
75     bl_push      = force_fromtag_normpower;
76     vehicles_sweap_collision(force_fromtag_origin, self.velocity, frametime, v_add, autocvar_g_vehicle_racer_collision_multiplier);
77
78     self.velocity += (push_vector * frametime);
79
80     // Anti ocilation
81     if(self.velocity_z  > 0)
82         self.velocity_z  *= autocvar_g_vehicle_racer_upforcedamper;
83
84     self.velocity += v_add;
85     self.velocity_z -= autocvar_sv_gravity * frametime;
86
87
88
89     push_vector_x =  (fl_push - bl_push);
90     push_vector_x += (fr_push - br_push);
91     push_vector_x *= 360;
92
93     push_vector_z = (fr_push - fl_push);
94     push_vector_z += (br_push - bl_push);
95     push_vector_z *= 360;
96
97     //if (push_vector_z != 0)
98         if(self.angles_z > 0)
99             self.angles_z = max(0, self.angles_z - (autocvar_g_vehicle_racer_anglestabilizer * frametime));
100         else
101             self.angles_z = min(0, self.angles_z + (autocvar_g_vehicle_racer_anglestabilizer * frametime));
102     //else
103         self.angles_z += push_vector_z * frametime;
104
105     //if (push_vector_x != 0)
106         if(self.angles_x > 0)
107             self.angles_x = max(0, self.angles_x - (autocvar_g_vehicle_racer_anglestabilizer * frametime));
108         else
109             self.angles_x = min(0, self.angles_x + (autocvar_g_vehicle_racer_anglestabilizer * frametime));
110     //else
111         self.angles_x += push_vector_x * frametime;
112 }
113
114 void racer_rocket_explode()
115 {
116         PROJECTILE_TOUCH;
117     if(other.owner == self.owner)
118         return;
119
120         self.event_damage = SUB_Null;
121
122     sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
123     pointparticles(particleeffectnum("rocket_explode"), findbetterlocation (self.origin, 16), '0 0 0', 1);
124     RadiusDamage (self, self.realowner ,autocvar_g_vehicle_racer_rocket_damage, 0, autocvar_g_vehicle_racer_rocket_radius, world, 150, DEATH_WAKIROCKET, world);
125
126     remove (self);
127 }
128
129 void racer_bolt_explode()
130 {
131         PROJECTILE_TOUCH;
132     pointparticles(particleeffectnum("wakizashi_gun_impact"), findbetterlocation (self.origin, 8), trace_plane_normal * 1000, 1);
133     RadiusDamage (self, self.realowner, autocvar_g_vehicle_racer_laser_damage, 0, autocvar_g_vehicle_racer_laser_radius, world, 150, DEATH_WAKIGUN, world);
134     sound (self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
135     remove (self);
136 }
137
138 void racer_fire_cannon(string tagname)
139 {
140     entity bolt;
141     vector v;
142
143     bolt = spawn();
144     sound (self, CHAN_WEAPON, "weapons/lasergun_fire.wav", VOL_BASE, ATTN_NORM);
145
146     setorigin(bolt, gettaginfo(self, gettagindex(self, tagname)));
147     PROJECTILE_MAKETRIGGER(bolt);
148
149     bolt.movetype        = MOVETYPE_FLYMISSILE;
150     bolt.flags           = FL_PROJECTILE | FL_NOTARGET;
151     bolt.owner           = self;
152     bolt.realowner       = self.owner;
153     bolt.touch           = racer_bolt_explode;
154     bolt.think           = racer_bolt_explode;
155     bolt.nextthink       = time + 9;
156
157     bolt.bot_dodge       = TRUE;
158     bolt.bot_dodgerating = autocvar_g_vehicle_racer_laser_damage;
159
160         // Fix z-aim (for chase mode)
161         crosshair_trace(self.owner);
162     v = normalize(trace_endpos - bolt.origin);
163     v_forward_z = v_z * 0.5;
164
165     bolt.velocity = v_forward * autocvar_g_vehicle_racer_laser_speed;
166
167     pointparticles(particleeffectnum("wakizashi_gun_muzzleflash"), bolt.origin, bolt.velocity, 1);
168
169     CSQCProjectile(bolt, TRUE, PROJECTILE_LASER, TRUE);
170 }
171
172 void racer_rocket_groundhugger()
173 {
174     vector olddir;
175
176     self.nextthink  = time;
177
178     if ((self.owner.deadflag != DEAD_NO) || (self.cnt < time))
179     {
180         racer_rocket_explode();
181         return;
182     }
183
184     if not (self.realowner.vehicle)
185     {
186         UpdateCSQCProjectile(self);
187         return;
188     }
189
190     olddir = normalize(self.velocity);
191     tracebox(self.origin, self.mins, self.maxs, self.origin + olddir * 64, MOVE_WORLDONLY,self);
192     if(trace_fraction >= 0.5)
193     {
194         traceline(trace_endpos, trace_endpos - '0 0 64', MOVE_NORMAL, self);
195         if(trace_fraction != 1.0)
196         {
197             // Follow ground
198             self.velocity = normalize(olddir + normalize((trace_endpos + '0 0 32') - self.origin) * self.wait) * (vlen(self.velocity) + self.lip);
199             UpdateCSQCProjectile(self);
200             return;
201         }
202         else
203         {
204             // "In air", add gravity.
205             self.velocity = olddir * (vlen(self.velocity) + self.lip);
206             self.velocity_z -= sys_frametime * 1250;
207             UpdateCSQCProjectile(self);
208             return;
209         }
210     }
211
212     // Hitting somethign soon.
213     self.velocity = olddir * (vlen(self.velocity) + self.lip);
214     UpdateCSQCProjectile(self);
215 }
216
217 void racer_fire_rocket(string tagname)
218 {
219     entity rocket;
220
221     sound (self, CHAN_WEAPON, "weapons/rocket_fire.wav", VOL_BASE, ATTN_NORM);
222
223     rocket = spawn();
224     setsize (rocket, '-1 -1 -1', '1 1 1');
225     setorigin(rocket, gettaginfo(self, gettagindex(self, tagname)));
226
227     rocket.lip              = autocvar_g_vehicle_racer_rocket_accel * sys_frametime;
228     rocket.wait             = autocvar_g_vehicle_racer_rocket_turnrate;
229     rocket.solid            = SOLID_BBOX;
230     rocket.movetype         = MOVETYPE_FLYMISSILE;
231     rocket.flags            = FL_PROJECTILE;
232     rocket.owner            = self;
233     rocket.realowner        = self.owner;
234     rocket.touch            = racer_rocket_explode;
235     rocket.bot_dodge        = TRUE;
236     rocket.bot_dodgerating  = autocvar_g_vehicle_racer_rocket_damage;
237     rocket.cnt              = time + 9;
238     rocket.velocity         = v_forward * autocvar_g_vehicle_racer_rocket_speed;
239     rocket.think            = racer_rocket_groundhugger;
240     rocket.nextthink        = time;
241
242     CSQCProjectile(rocket, TRUE, PROJECTILE_ROCKET, TRUE);
243 }
244
245 float racer_frame()
246 {
247     entity player, racer;
248     float ftmp, ftmp2;
249     vector df;
250
251     player          = self;
252     racer           = self.vehicle;
253
254     player.BUTTON_ZOOM = player.BUTTON_CROUCH = 0;
255
256     self = racer;
257
258     if(player.BUTTON_USE)
259     {
260         vehicles_exit(VHEF_NORMAL);
261         self = player;
262         return 0;
263     }
264
265     if(racer.deadflag != DEAD_NO)
266     {
267         self = player;
268         player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0;
269         return 1;
270     }
271
272     racer_align4point();
273
274     racer.angles_x *= -1;
275     makevectors(racer.angles);
276
277     // Yaw
278     ftmp = autocvar_g_vehicle_racer_turnspeed * sys_frametime;
279     ftmp2 = ftmp * -1;
280
281     ftmp = bound(ftmp2, shortangle_f(player.v_angle_y - racer.angles_y, racer.angles_y), ftmp);
282     ftmp2 = anglemods(racer.angles_y + ftmp);
283
284     // Roll
285     ftmp = bound(-45, shortangle_f(player.v_angle_z + ((racer.angles_y - ftmp2) * autocvar_g_vehicle_racer_turnroll), racer.angles_z), 45);
286     ftmp = anglemods(racer.angles_z + ftmp) * frametime;
287     racer.angles_z = bound(-65, racer.angles_z + ftmp, 65);
288
289     // Turn
290     racer.angles_y = ftmp2;
291
292     // Pitch Body
293     ftmp = autocvar_g_vehicle_racer_pitchspeed * sys_frametime;
294     ftmp2 = ftmp * -1;
295
296     ftmp = bound(ftmp2, shortangle_f(player.v_angle_x - racer.angles_x, racer.angles_x), ftmp);
297     racer.angles_x = anglemods(racer.angles_x + ftmp);
298     racer.angles_x *= -1;
299
300     df = racer.velocity * -0.5;
301
302     if(player.movement_x != 0)
303     {
304         if(player.movement_x > 0)
305             df += v_forward  * autocvar_g_vehicle_racer_speed_forward;
306         else if(player.movement_x < 0)
307             df -= v_forward  * autocvar_g_vehicle_racer_speed_forward;
308     }
309
310     if(player.movement_y != 0)
311     {
312         if(player.movement_y < 0)
313             df -= v_right * autocvar_g_vehicle_racer_speed_strafe;
314         else if(player.movement_y > 0)
315             df += v_right * autocvar_g_vehicle_racer_speed_strafe;
316     }
317
318     // limit _z to avoid flying on normal thrust
319     if(df_z > 0)
320         df_z = min(df_z, 700);
321
322
323     // Afterburn
324     if (player.BUTTON_JUMP)
325     if(racer.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * frametime))
326     {
327         racer.wait = time;
328         racer.vehicle_energy -= autocvar_g_vehicle_racer_afterburn_cost * frametime;
329         df += (v_forward * autocvar_g_vehicle_racer_speed_afterburn);
330         self.owner.vehicle_energy = racer.vehicle_energy / autocvar_g_vehicle_racer_energy;
331     }
332
333     racer.velocity  += df * frametime;
334
335     df = (vlen(racer.velocity) * autocvar_g_vehicle_racer_downforce * v_up) * frametime;
336     racer.velocity  = racer.velocity - df;
337     player.movement = racer.velocity;
338
339     if(player.BUTTON_ATCK)
340     if(time > racer.attack_finished_single)
341     if(racer.vehicle_energy >= autocvar_g_vehicle_racer_laser_cost)
342     {
343         racer.vehicle_energy -= autocvar_g_vehicle_racer_laser_cost;
344         racer.wait = time;
345
346         if(racer.cnt)
347         {
348             racer_fire_cannon("tag_fire1");
349             racer.cnt = 0;
350         }
351         else
352         {
353             racer_fire_cannon("tag_fire2");
354             racer.cnt = 1;
355         }
356         racer.attack_finished_single = time + autocvar_g_vehicle_racer_laser_refire;
357         self.owner.vehicle_energy = racer.vehicle_energy / autocvar_g_vehicle_racer_energy;
358     }
359
360     if(player.BUTTON_ATCK2)
361     if(time > racer.delay)
362     {
363         racer_fire_rocket("tag_rocket_r");
364         racer_fire_rocket("tag_rocket_l");
365         racer.delay = time + autocvar_g_vehicle_racer_rocket_refire;
366         racer.lip = time;
367     }
368
369     player.vehicle_reload1 = (time - racer.lip) / (racer.delay - racer.lip);
370
371     if(self.vehicle_flags  & VHF_SHIELDREGEN)
372         vehicles_regen(dmg_time, vehicle_shield, autocvar_g_vehicle_racer_shield, autocvar_g_vehicle_racer_shield_regen_pause, autocvar_g_vehicle_racer_shield_regen, frametime);
373
374     if(self.vehicle_flags  & VHF_HEALTHREGEN)
375         vehicles_regen(dmg_time, vehicle_health, autocvar_g_vehicle_racer_health, autocvar_g_vehicle_racer_health_regen_pause, autocvar_g_vehicle_racer_health_regen, frametime);
376
377     if(self.vehicle_flags  & VHF_ENERGYREGEN)
378         vehicles_regen(wait, vehicle_energy, autocvar_g_vehicle_racer_energy, autocvar_g_vehicle_racer_energy_regen_pause, autocvar_g_vehicle_racer_energy_regen, frametime);
379
380
381     VEHICLE_UPDATE_PLAYER(health, racer);
382
383     if(self.vehicle_flags & VHF_HASSHIELD)
384         VEHICLE_UPDATE_PLAYER(shield, racer);
385
386
387     player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0;
388     setorigin(player,racer.origin + '0 0 32');
389     player.velocity = racer.velocity;
390
391     self = player;
392     return 1;
393 }
394
395 void racer_think()
396 {
397     float a, b, c;
398
399     self.nextthink = time;
400
401     a = autocvar_g_vehicle_racer_anglestabilizer;
402     b = autocvar_g_vehicle_racer_springlength;
403     c = autocvar_g_vehicle_racer_hoverpower;
404
405     autocvar_g_vehicle_racer_anglestabilizer = 36;
406     autocvar_g_vehicle_racer_springlength = 96;
407     autocvar_g_vehicle_racer_hoverpower = 300;
408
409     racer_align4point();
410
411     if(self.velocity_z < 0)
412         self.velocity_z *= 0.95;
413
414     autocvar_g_vehicle_racer_anglestabilizer = a;
415     autocvar_g_vehicle_racer_springlength = b;
416     autocvar_g_vehicle_racer_hoverpower = c;
417
418     self.velocity_x *= 0.95;
419     self.velocity_y *= 0.95;
420 }
421
422 void racer_enter()
423 {
424     self.owner.vehicle_health = (self.vehicle_health / autocvar_g_vehicle_racer_health);
425     self.owner.vehicle_shield = (self.vehicle_shield / autocvar_g_vehicle_racer_shield);
426 }
427
428 void racer_spawn();
429
430 void racer_exit(float eject)
431 {
432     vehicles_setreturn(autocvar_g_vehicle_racer_respawntime, racer_spawn);
433
434     self.think      = racer_think;
435     self.nextthink  = time;
436
437     if not (self.owner)
438         return;
439
440         if(eject)
441         {
442             makevectors(self.angles);
443             setorigin(self.owner,self.origin + v_forward * 100);
444             self.owner.velocity = (v_up + v_forward * 0.25) * 750;
445         }
446         else
447         {
448             self.owner.velocity = v_forward * -150;
449         setorigin(self.owner, self.origin - v_forward * 128);
450         }
451
452     self.owner = world;
453 }
454
455 void racer_touch()
456 {
457     if(self.owner)
458     {
459         if(vlen(self.velocity) == 0)
460             return;
461
462         if(other.classname != "player")
463             return;
464
465         vector a;
466         a = normalize(other.origin - self.origin);
467         a = a - normalize(self.velocity);
468
469         return;
470     }
471
472     if(other.classname != "player")
473         return;
474
475     if(other.deadflag != DEAD_NO)
476         return;
477
478     if(other.vehicle != world)
479         return;
480
481     vehicles_enter();
482 }
483
484 void racer_spawn()
485 {
486     self.think = racer_think;
487     self.nextthink = time;
488
489     self.flags      = FL_NOTARGET;
490     self.effects   = 0;
491
492     self.vehicle_health = autocvar_g_vehicle_racer_health;
493     self.vehicle_shield = autocvar_g_vehicle_racer_shield;
494
495     self.event_damage = vehicles_damage;
496     self.touch      = racer_touch;
497
498     self.iscreature = TRUE;
499     self.scale      = 0.5;
500     self.movetype   = MOVETYPE_BOUNCEMISSILE;
501     self.solid      = SOLID_SLIDEBOX;
502     self.takedamage = DAMAGE_AIM;
503
504     self.alpha      = 1;
505         self.colormap   = 1024;
506         self.deadflag   = DEAD_NO;
507     self.bot_attack = TRUE;
508
509     self.vehicle_energy = 1;
510     self.vehicle_hudmodel.viewmodelforclient = self;
511
512     setorigin(self, self.pos1);
513     self.angles = self.pos2;
514
515     setsize(self, RACER_MIN * 0.5, RACER_MAX * 0.5);
516     pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1);
517     self.delay = time;
518 }
519
520 void racer_blowup()
521 {
522
523     sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
524     pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
525
526     self.deadflag    = DEAD_DEAD;
527     self.vehicle_exit(VHEF_NORMAL);
528     RadiusDamage (self, self, 250, 15, 250, world, 250, DEATH_WAKIBLOWUP, world);
529
530     self.alpha = -1;
531     self.nextthink  = time + autocvar_g_vehicle_racer_respawntime;
532     self.think      = racer_spawn;
533     self.movetype   = MOVETYPE_NONE;
534     self.effects    = EF_NODRAW;
535
536     self.avelocity_z  = 0;
537     self.colormod = '0 0 0';
538
539     setorigin(self,self.pos1);
540     self.avelocity = '0 0 0';
541     self.velocity = '0 0 0';
542 }
543
544 void racer_deadtouch()
545 {
546     self.avelocity_x *= 0.7;
547     self.cnt -= 1;
548     if(self.cnt <= 0)
549         racer_blowup();
550 }
551
552 void racer_die()
553 {
554     self.health       = 0;
555     self.event_damage = SUB_Null;
556     self.iscreature   = FALSE;
557     self.solid        = SOLID_CORPSE;
558     self.takedamage   = DAMAGE_NO;
559     self.deadflag     = DEAD_DYING;
560     self.movetype     = MOVETYPE_BOUNCE;
561     self.wait         = time;
562     self.cnt          = 1 + random() * 3;
563     self.touch        = racer_deadtouch;
564
565     pointparticles(particleeffectnum("rocket_explode"), findbetterlocation (self.origin, 16), '0 0 0', 1);
566
567     self.velocity     += '0 0 700';
568
569     if(random() < 0.5)
570         self.avelocity_z  = 16;
571     else
572         self.avelocity_z  = -16;
573
574     self.avelocity_x = -vlen(self.velocity) * 0.2;
575
576     self.colormod = '-0.5 -0.5 -0.5';
577
578         self.think     = racer_blowup;
579         self.nextthink = 2 + time + random() * 3;
580 }
581
582 void racer_dinit()
583 {
584     if not (vehicle_initialize(
585              "Wakizashi",
586              "models/vehicles/wakizashi.dpm",
587              "",
588              "models/vehicles/wakizashi_cockpit.dpm",
589              "", "", "tag_viewport",
590              HUD_WAKIZASHI,
591              0.5 * RACER_MIN, 0.5 * RACER_MAX,
592              FALSE,
593              racer_spawn, racer_frame,
594              racer_enter, racer_exit,
595              racer_die,   racer_think))
596     {
597         remove(self);
598         return;
599     }
600
601     if(autocvar_g_vehicle_racer_hovertype != 0)
602         racer_force_from_tag = vehicles_force_fromtag_maglev;
603     else
604         racer_force_from_tag = vehicles_force_fromtag_hover;
605
606     // FIXME: this be hakkz, fix the models insted (scale body, add tag_viewport to the hudmodel).
607     self.scale = 0.5;
608     setattachment(self.vehicle_hudmodel, self, "");
609     setattachment(self.vehicle_viewport, self, "tag_viewport");
610 }
611
612 void spawnfunc_vehicle_racer()
613 {
614
615     precache_sound ("weapons/laserimpact.wav");
616     precache_sound ("weapons/lasergun_fire.wav");
617     precache_sound ("weapons/rocket_fire.wav");
618     precache_sound ("weapons/rocket_impact.wav");
619
620     precache_model ("models/vhshield.md3");
621     precache_model ("models/vehicles/wakizashi.dpm");
622     precache_model ("models/vehicles/wakizashi_cockpit.dpm");
623
624
625     vehicles_configcheck("vehicle_racer.cfg", autocvar_g_vehicle_racer_health);
626     if(autocvar_g_vehicle_racer_energy)
627         if(autocvar_g_vehicle_racer_energy_regen)
628             self.vehicle_flags |= VHF_ENERGYREGEN;
629
630     if(autocvar_g_vehicle_racer_shield)
631         self.vehicle_flags |= VHF_HASSHIELD;
632
633     if(autocvar_g_vehicle_racer_shield_regen)
634         self.vehicle_flags |= VHF_SHIELDREGEN;
635
636     if(autocvar_g_vehicle_racer_health_regen)
637         self.vehicle_flags |= VHF_HEALTHREGEN;
638
639     self.think = racer_dinit;
640     self.nextthink = time + 1;
641 }