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