]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/vehicles/vehicle/raptor.qc
Update default video settings
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / vehicles / vehicle / raptor.qc
1 #include "raptor.qh"
2
3 #if defined(SVQC)
4         #include <common/gamemodes/gamemode/ctf/sv_ctf.qh>
5 #endif
6
7 #ifdef GAMEQC
8
9 #ifdef SVQC
10
11 bool autocvar_g_vehicle_raptor = true;
12
13 float autocvar_g_vehicle_raptor_respawntime = 40;
14 float autocvar_g_vehicle_raptor_takeofftime = 1.5;
15
16 // 0: go where player aims, +forward etc relative to aim angles
17 // 1: ignore aim for up/down movement. +forward always moved forward, +jump always moves up
18 int autocvar_g_vehicle_raptor_movestyle = 1;
19 float autocvar_g_vehicle_raptor_turnspeed = 200;
20 float autocvar_g_vehicle_raptor_pitchspeed = 50;
21 float autocvar_g_vehicle_raptor_pitchlimit = 45;
22
23 float autocvar_g_vehicle_raptor_speed_forward = 1700;
24 float autocvar_g_vehicle_raptor_speed_strafe = 2200;
25 float autocvar_g_vehicle_raptor_speed_up = 2300;
26 float autocvar_g_vehicle_raptor_speed_down = 2000;
27 float autocvar_g_vehicle_raptor_friction = 2;
28
29 bool autocvar_g_vehicle_raptor_swim = false;
30
31 float autocvar_g_vehicle_raptor_cannon_turnspeed = 120;
32 float autocvar_g_vehicle_raptor_cannon_turnlimit = 20;
33 float autocvar_g_vehicle_raptor_cannon_pitchlimit_up = 12;
34 float autocvar_g_vehicle_raptor_cannon_pitchlimit_down = 32;
35
36 bool autocvar_g_vehicle_raptor_cannon_locktarget = true;
37 float autocvar_g_vehicle_raptor_cannon_locking_time = 0.2;
38 float autocvar_g_vehicle_raptor_cannon_locking_releasetime = 0.45;
39 float autocvar_g_vehicle_raptor_cannon_locked_time = 1;
40 float autocvar_g_vehicle_raptor_cannon_predicttarget = 1;
41
42 float autocvar_g_vehicle_raptor_energy = 100;
43 float autocvar_g_vehicle_raptor_energy_regen = 25;
44 float autocvar_g_vehicle_raptor_energy_regen_pause = 0.25;
45
46 float autocvar_g_vehicle_raptor_health = 250;
47 float autocvar_g_vehicle_raptor_health_regen = 0;
48 float autocvar_g_vehicle_raptor_health_regen_pause = 0;
49
50 float autocvar_g_vehicle_raptor_shield = 200;
51 float autocvar_g_vehicle_raptor_shield_regen = 25;
52 float autocvar_g_vehicle_raptor_shield_regen_pause = 1.5;
53
54 float autocvar_g_vehicle_raptor_bouncefactor = 0.2;
55 float autocvar_g_vehicle_raptor_bouncestop = 0;
56 vector autocvar_g_vehicle_raptor_bouncepain = '1 4 1000';
57
58 .entity bomb1;
59 .entity bomb2;
60
61 void raptor_land(entity this)
62 {
63         float hgt;
64
65         hgt = vehicle_altitude(this, 512);
66         this.velocity = (this.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * PHYS_INPUT_FRAMETIME);
67         this.angles_x *= 0.95;
68         this.angles_z *= 0.95;
69
70         if(hgt < 128 && hgt > 0)
71                 this.frame = (hgt / 128) * 25;
72
73         this.bomb1.gun1.avelocity_y = 90 + ((this.frame / 25) * 2000);
74         this.bomb1.gun2.avelocity_y = -this.bomb1.gun1.avelocity_y;
75
76         if(hgt < 16)
77         {
78                 set_movetype(this, MOVETYPE_TOSS);
79                 setthink(this, vehicles_think);
80                 this.frame      = 0;
81         }
82
83         this.nextthink  = time;
84
85         CSQCMODEL_AUTOUPDATE(this);
86 }
87
88 void raptor_exit(entity this, int eject)
89 {
90         entity player = this.owner;
91
92         this.tur_head.exteriormodeltoclient = NULL;
93
94         if(!IS_DEAD(this))
95         {
96                 setthink(this, raptor_land);
97                 this.nextthink = time;
98         }
99
100         if(!player)
101                 return;
102
103         makevectors(this.angles);
104         vector spot;
105         if(eject)
106         {
107                 spot = this.origin + v_forward * 100 + '0 0 64';
108                 spot = vehicles_findgoodexit(this, player, spot);
109                 setorigin(player, spot);
110                 player.velocity = (v_up + v_forward * 0.25) * 750;
111                 player.oldvelocity = player.velocity;
112         }
113         else
114         {
115                 if(vdist(this.velocity, >, 2 * autocvar_sv_maxairspeed))
116                 {
117                         player.velocity = normalize(this.velocity) * autocvar_sv_maxairspeed * 2;
118                         player.velocity_z += 200;
119                         spot = this.origin + v_forward * 32 + '0 0 64';
120                         spot = vehicles_findgoodexit(this, player, spot);
121                 }
122                 else
123                 {
124                         player.velocity = this.velocity * 0.5;
125                         player.velocity_z += 10;
126                         spot = this.origin - v_forward * 200 + '0 0 64';
127                         spot = vehicles_findgoodexit(this, player, spot);
128                 }
129                 player.oldvelocity = player.velocity;
130                 setorigin(player, spot);
131         }
132
133         this.owner = NULL;
134         antilag_clear(player, CS(player));
135 }
136
137 bool raptor_frame(entity this, float dt)
138 {
139         entity vehic = this.vehicle;
140         return = true;
141
142         if(game_stopped)
143         {
144                 vehic.solid = SOLID_NOT;
145                 vehic.takedamage = DAMAGE_NO;
146                 set_movetype(vehic, MOVETYPE_NONE);
147                 return;
148         }
149
150         vehicles_frame(vehic, this);
151
152         /*
153         ftmp = vlen(vehic.velocity);
154         if(ftmp > autocvar_g_vehicle_raptor_speed_forward)
155                 ftmp = 1;
156         else
157                 ftmp = ftmp / autocvar_g_vehicle_raptor_speed_forward;
158         */
159
160         if(vehic.sound_nexttime < time)
161         {
162                 vehic.sound_nexttime = time + 7.955812;
163                 //sound (vehic.tur_head, CH_TRIGGER_SINGLE, SND_VEH_RAPTOR_FLY, 1 - ftmp,   ATTEN_NORM );
164                 sound (vehic, CH_TRIGGER_SINGLE, SND_VEH_RAPTOR_SPEED, 1, ATTEN_NORM);
165                 vehic.wait = 0;
166         }
167         /*
168         else if(fabs(ftmp - vehic.wait) > 0.2)
169         {
170                 sound (vehic.tur_head, CH_TRIGGER_SINGLE, SND_Null, 1 - ftmp,   ATTEN_NORM );
171                 sound (vehic, CH_TRIGGER_SINGLE, SND_Null, ftmp, ATTEN_NORM);
172                 vehic.wait = ftmp;
173         }
174         */
175
176         if(IS_DEAD(vehic))
177         {
178                 PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
179                 return;
180         }
181         crosshair_trace(this);
182
183         //if(time - vehic.lastteleporttime < 1)
184         //{
185                 if(vehic.angles_z > 50 || vehic.angles_z < -50)
186                 {
187                         if(PHYS_INPUT_BUTTON_JUMP(this))
188                         {
189                                 PHYS_INPUT_BUTTON_CROUCH(this) = true;
190                                 PHYS_INPUT_BUTTON_JUMP(this) = false;
191                         }
192                 }
193         //}
194
195         vector vang;
196         vang = vehic.angles;
197         vector df = vectoangles(normalize(trace_endpos - vehic.origin + '0 0 32'));
198         vang_x *= -1;
199         df_x *= -1;
200         if(df_x > 180)  df_x -= 360;
201         if(df_x < -180) df_x += 360;
202         if(df_y > 180)  df_y -= 360;
203         if(df_y < -180) df_y += 360;
204
205         float ftmp = shortangle_f(this.v_angle_y - vang_y, vang_y);
206         if(ftmp > 180)  ftmp -= 360; if(ftmp < -180) ftmp += 360;
207         vehic.avelocity_y = bound(-autocvar_g_vehicle_raptor_turnspeed, ftmp + vehic.avelocity_y * 0.9, autocvar_g_vehicle_raptor_turnspeed);
208
209         // Pitch
210         ftmp = 0;
211         if(CS(this).movement_x > 0 && vang_x < autocvar_g_vehicle_raptor_pitchlimit) ftmp = 5;
212         else if(CS(this).movement_x < 0 && vang_x > -autocvar_g_vehicle_raptor_pitchlimit) ftmp = -20;
213
214         df_x = bound(-autocvar_g_vehicle_raptor_pitchlimit, df_x , autocvar_g_vehicle_raptor_pitchlimit);
215         ftmp = vang_x - bound(-autocvar_g_vehicle_raptor_pitchlimit, df_x + ftmp, autocvar_g_vehicle_raptor_pitchlimit);
216         vehic.avelocity_x = bound(-autocvar_g_vehicle_raptor_pitchspeed, ftmp + vehic.avelocity_x * 0.9, autocvar_g_vehicle_raptor_pitchspeed);
217
218         vehic.angles_x = anglemods(vehic.angles_x);
219         vehic.angles_y = anglemods(vehic.angles_y);
220         vehic.angles_z = anglemods(vehic.angles_z);
221
222         if(autocvar_g_vehicle_raptor_movestyle == 1)
223                 makevectors('0 1 0' * vehic.angles_y);
224         else
225                 makevectors(this.v_angle);
226
227         df = vehic.velocity * -autocvar_g_vehicle_raptor_friction;
228
229         if(CS(this).movement_x != 0)
230         {
231                 if(CS(this).movement_x > 0)
232                         df += v_forward  * autocvar_g_vehicle_raptor_speed_forward;
233                 else if(CS(this).movement_x < 0)
234                         df -= v_forward  * autocvar_g_vehicle_raptor_speed_forward;
235         }
236
237         if(CS(this).movement_y != 0)
238         {
239                 if(CS(this).movement_y < 0)
240                         df -= v_right * autocvar_g_vehicle_raptor_speed_strafe;
241                 else if(CS(this).movement_y > 0)
242                         df += v_right * autocvar_g_vehicle_raptor_speed_strafe;
243
244                 vehic.angles_z = bound(-30,vehic.angles_z + (CS(this).movement_y / autocvar_g_vehicle_raptor_speed_strafe),30);
245         }
246         else
247         {
248                 vehic.angles_z *= 0.95;
249                 if(vehic.angles_z >= -1 && vehic.angles_z <= -1)
250                         vehic.angles_z = 0;
251         }
252
253         if(PHYS_INPUT_BUTTON_CROUCH(this))
254                 df -=   v_up * autocvar_g_vehicle_raptor_speed_down;
255         else if (PHYS_INPUT_BUTTON_JUMP(this))
256                 df +=  v_up * autocvar_g_vehicle_raptor_speed_up;
257
258         vehic.velocity  += df * dt;
259         this.velocity = CS(this).movement  = vehic.velocity;
260         setorigin(this, vehic.origin + '0 0 32');
261         this.oldorigin = this.origin; // negate fall damage
262
263         STAT(VEHICLESTAT_W2MODE, this) = STAT(VEHICLESTAT_W2MODE, vehic);
264
265         vector vf, ad;
266         // Target lock & predict
267         if(autocvar_g_vehicle_raptor_cannon_locktarget == 2)
268         {
269                 if(vehic.gun1.lock_time < time || IS_DEAD(vehic.gun1.enemy) || STAT(FROZEN, vehic.gun1.enemy))
270                         vehic.gun1.enemy = NULL;
271
272                 if(trace_ent)
273                 if(trace_ent.move_movetype)
274                 if(trace_ent.takedamage)
275                 if(!IS_DEAD(trace_ent) && !STAT(FROZEN, trace_ent))
276                 {
277                         if(teamplay)
278                         {
279                                 if(trace_ent.team != this.team)
280                                 {
281                                         vehic.gun1.enemy = trace_ent;
282                                         vehic.gun1.lock_time = time + 5;
283                                 }
284                         }
285                         else
286                         {
287                                 vehic.gun1.enemy = trace_ent;
288                                 vehic.gun1.lock_time = time + 0.5;
289                         }
290                 }
291
292                 if(vehic.gun1.enemy)
293                 {
294                         float distance, impact_time;
295
296                         vf = real_origin(vehic.gun1.enemy);
297                         UpdateAuxiliaryXhair(this, vf, '1 0 0', 1);
298                         vector _vel = vehic.gun1.enemy.velocity;
299                         if(vehic.gun1.enemy.move_movetype == MOVETYPE_WALK)
300                                 _vel_z *= 0.1;
301
302                         if(autocvar_g_vehicle_raptor_cannon_predicttarget)
303                         {
304                                 ad = vf;
305                                 distance = vlen(ad - this.origin);
306                                 impact_time = distance / autocvar_g_vehicle_raptor_cannon_speed;
307                                 ad = vf + _vel * impact_time;
308                                 trace_endpos = ad;
309                         }
310                         else
311                                 trace_endpos = vf;
312                 }
313         }
314         else if(autocvar_g_vehicle_raptor_cannon_locktarget == 1)
315         {
316
317                 vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_raptor_cannon_locking_time) * dt,
318                                                          (1 / autocvar_g_vehicle_raptor_cannon_locking_releasetime) * dt,
319                                                          autocvar_g_vehicle_raptor_cannon_locked_time);
320
321                 if(vehic.lock_target != NULL)
322                 if(autocvar_g_vehicle_raptor_cannon_predicttarget)
323                 if(vehic.lock_strength == 1)
324                 {
325                         float i, distance, impact_time;
326
327                         vf = real_origin(vehic.lock_target);
328                         ad = vf;
329                         for(i = 0; i < 4; ++i)
330                         {
331                                 distance = vlen(ad - vehic.origin);
332                                 impact_time = distance / autocvar_g_vehicle_raptor_cannon_speed;
333                                 ad = vf + vehic.lock_target.velocity * impact_time;
334                         }
335                         trace_endpos = ad;
336                 }
337
338                 if(vehic.lock_target)
339                 {
340                         if(vehic.lock_strength == 1)
341                                 UpdateAuxiliaryXhair(this, real_origin(vehic.lock_target), '1 0 0', 1);
342                         else if(vehic.lock_strength > 0.5)
343                                 UpdateAuxiliaryXhair(this, real_origin(vehic.lock_target), '0 1 0', 1);
344                         else if(vehic.lock_strength < 0.5)
345                                 UpdateAuxiliaryXhair(this, real_origin(vehic.lock_target), '0 0 1', 1);
346                 }
347         }
348
349
350         vehicle_aimturret(vehic, trace_endpos, vehic.gun1, "fire1",
351                                                   autocvar_g_vehicle_raptor_cannon_pitchlimit_down * -1,  autocvar_g_vehicle_raptor_cannon_pitchlimit_up,
352                                                   autocvar_g_vehicle_raptor_cannon_turnlimit * -1,  autocvar_g_vehicle_raptor_cannon_turnlimit,  autocvar_g_vehicle_raptor_cannon_turnspeed, dt);
353
354         vehicle_aimturret(vehic, trace_endpos, vehic.gun2, "fire1",
355                                                   autocvar_g_vehicle_raptor_cannon_pitchlimit_down * -1,  autocvar_g_vehicle_raptor_cannon_pitchlimit_up,
356                                                   autocvar_g_vehicle_raptor_cannon_turnlimit * -1,  autocvar_g_vehicle_raptor_cannon_turnlimit,  autocvar_g_vehicle_raptor_cannon_turnspeed, dt);
357
358         /*
359         ad = ad * 0.5;
360         v_forward = vf * 0.5;
361         traceline(ad, ad + v_forward * max_shot_distance, MOVE_NORMAL, vehic);
362         UpdateAuxiliaryXhair(this, trace_endpos, '0 1 0', 0);
363         */
364
365         Weapon wep1 = WEP_RAPTOR;
366         .entity weaponentity = weaponentities[0];
367         if(!weaponLocked(this) && !weaponUseForbidden(this))
368         if(PHYS_INPUT_BUTTON_ATCK(this))
369         if (wep1.wr_checkammo1(wep1, vehic, weaponentity))
370         {
371                 wep1.wr_think(wep1, vehic, weaponentity, 1);
372         }
373
374         if(vehic.vehicle_flags  & VHF_SHIELDREGEN)
375                 vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, dt, true);
376
377         if(vehic.vehicle_flags  & VHF_HEALTHREGEN)
378                 vehicles_regen_resource(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false, RES_HEALTH);
379
380         if(vehic.vehicle_flags  & VHF_ENERGYREGEN)
381                 vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, dt, false);
382
383         Weapon wep2a = WEP_RAPTOR_BOMB;
384         if(!weaponLocked(this) && !weaponUseForbidden(this))
385         if(STAT(VEHICLESTAT_W2MODE, vehic) == RSM_BOMB)
386         {
387                 if(time > vehic.lip + autocvar_g_vehicle_raptor_bombs_refire)
388                 if(PHYS_INPUT_BUTTON_ATCK2(this))
389                 {
390                     .entity weaponentity = weaponentities[1];
391                         wep2a.wr_think(wep2a, vehic, weaponentity, 2);
392                         vehic.delay = time + autocvar_g_vehicle_raptor_bombs_refire;
393                         vehic.lip   = time;
394                 }
395         }
396         else
397         {
398                 Weapon wep2b = WEP_RAPTOR_FLARE;
399                 if(time > vehic.lip + autocvar_g_vehicle_raptor_flare_refire)
400                 if(PHYS_INPUT_BUTTON_ATCK2(this))
401                 {
402                     .entity weaponentity = weaponentities[1];
403                         wep2b.wr_think(wep2b, vehic, weaponentity, 2);
404                         vehic.delay = time + autocvar_g_vehicle_raptor_flare_refire;
405                         vehic.lip   = time;
406                 }
407         }
408
409         vehic.bomb1.alpha = vehic.bomb2.alpha = (time - vehic.lip) / (vehic.delay - vehic.lip);
410         this.vehicle_reload2 = bound(0, vehic.bomb1.alpha * 100, 100);
411         this.vehicle_ammo2 = (this.vehicle_reload2 == 100) ? 100 : 0;
412
413         if(vehic.bomb1.cnt < time)
414         {
415                 bool incoming = false;
416                 IL_EACH(g_projectiles, it.enemy == vehic,
417                 {
418                         if(it.missile_flags & MIF_GUIDED_TRACKING)
419                         if(vdist(vehic.origin - it.origin, <, 2 * autocvar_g_vehicle_raptor_flare_range))
420                         {
421                                 incoming = true;
422                                 break;
423                         }
424                 });
425
426                 if(incoming)
427                 {
428                         msg_entity = this;
429                         soundto(MSG_ONE, vehic, CH_PAIN_SINGLE, SND(VEH_MISSILE_ALARM), VOL_BASE, ATTEN_NONE, 0);
430                 }
431
432                 vehic.bomb1.cnt = time + 1;
433         }
434
435
436         VEHICLE_UPDATE_PLAYER_RESOURCE(this, vehic, health, raptor, RES_HEALTH);
437         VEHICLE_UPDATE_PLAYER(this, vehic, energy, raptor);
438         if(vehic.vehicle_flags & VHF_HASSHIELD)
439                 VEHICLE_UPDATE_PLAYER(this, vehic, shield, raptor);
440
441         PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
442 }
443
444 bool raptor_takeoff(entity this, float dt)
445 {
446         entity vehic = this.vehicle;
447         return = true;
448
449         vehic.nextthink = time;
450         CSQCMODEL_AUTOUPDATE(vehic);
451         vehic.nextthink = 0; // will this work?
452
453         if(vehic.sound_nexttime < time)
454         {
455                 vehic.sound_nexttime = time + 7.955812; //soundlength("vehicles/raptor_fly.wav");
456                 sound (vehic, CH_TRIGGER_SINGLE, SND_VEH_RAPTOR_SPEED, VOL_VEHICLEENGINE, ATTEN_NORM);
457         }
458
459         // Takeoff sequense
460         if(vehic.frame < 25)
461         {
462                 vehic.frame += 25 / (autocvar_g_vehicle_raptor_takeofftime / dt);
463                 vehic.velocity_z = min(vehic.velocity_z * 1.5, 256);
464                 vehic.bomb1.gun1.avelocity_y = 90 + ((vehic.frame / 25) * 25000);
465                 vehic.bomb1.gun2.avelocity_y = -vehic.bomb1.gun1.avelocity_y;
466                 PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
467
468                 setorigin(this, vehic.origin + '0 0 32');
469                 this.oldorigin = this.origin;
470         }
471         else
472                 this.PlayerPhysplug = raptor_frame;
473
474         STAT(VEHICLESTAT_W2MODE, this) = STAT(VEHICLESTAT_W2MODE, vehic);
475
476         if(vehic.vehicle_flags  & VHF_SHIELDREGEN)
477                 vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, dt, true);
478
479         if(vehic.vehicle_flags  & VHF_HEALTHREGEN)
480                 vehicles_regen_resource(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false, RES_HEALTH);
481
482         if(vehic.vehicle_flags  & VHF_ENERGYREGEN)
483                 vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, dt, false);
484
485
486         vehic.bomb1.alpha = vehic.bomb2.alpha = (time - vehic.lip) / (vehic.delay - vehic.lip);
487         this.vehicle_reload2 = bound(0, vehic.bomb1.alpha * 100, 100);
488         this.vehicle_ammo2 = (this.vehicle_reload2 == 100) ? 100 : 0;
489
490         VEHICLE_UPDATE_PLAYER_RESOURCE(this, vehic, health, raptor, RES_HEALTH);
491         VEHICLE_UPDATE_PLAYER(this, vehic, energy, raptor);
492         if(vehic.vehicle_flags & VHF_HASSHIELD)
493                 VEHICLE_UPDATE_PLAYER(this, vehic, shield, raptor);
494
495         PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
496 }
497
498 void raptor_blowup(entity this, entity toucher)
499 {
500         this.deadflag   = DEAD_DEAD;
501         this.vehicle_exit(this, VHEF_NORMAL);
502         RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_RAPT_DEATH.m_id, DMG_NOWEP, NULL);
503
504         this.alpha                = -1;
505         set_movetype(this, MOVETYPE_NONE);
506         this.effects            = EF_NODRAW;
507         this.colormod      = '0 0 0';
508         this.avelocity    = '0 0 0';
509         this.velocity      = '0 0 0';
510
511         setorigin(this, this.pos1);
512         settouch(this, func_null);
513         this.nextthink = 0;
514 }
515
516 void raptor_diethink(entity this)
517 {
518         if(time >= this.wait)
519         {
520                 raptor_blowup(this, NULL);
521                 return;
522         }
523
524         if(random() < 0.05)
525         {
526                 sound (this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
527                 Send_Effect(EFFECT_EXPLOSION_SMALL, randomvec() * 80 + (this.origin + '0 0 100'), '0 0 0', 1);
528         }
529         this.nextthink = time;
530
531         CSQCMODEL_AUTOUPDATE(this);
532 }
533
534 // If we dont do this ever now and then, the raptors rotors
535 // stop working, presumably due to angle overflow. cute.
536 void raptor_rotor_anglefix(entity this)
537 {
538         this.gun1.angles_y = anglemods(this.gun1.angles_y);
539         this.gun2.angles_y = anglemods(this.gun2.angles_y);
540         this.nextthink = time + 15;
541 }
542
543 bool raptor_impulse(entity this, int _imp)
544 {
545         switch(_imp)
546         {
547                 case IMP_weapon_group_1.impulse:
548                         STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_BOMB;
549                         CSQCVehicleSetup(this, 0);
550                         return true;
551                 case IMP_weapon_group_2.impulse:
552                         STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_FLARE;
553                         CSQCVehicleSetup(this, 0);
554                         return true;
555
556                 case IMP_weapon_next_byid.impulse:
557                 case IMP_weapon_next_bypriority.impulse:
558                 case IMP_weapon_next_bygroup.impulse:
559                         STAT(VEHICLESTAT_W2MODE, this.vehicle) += 1;
560                         if(STAT(VEHICLESTAT_W2MODE, this.vehicle) > RSM_LAST)
561                                 STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_FIRST;
562
563                         CSQCVehicleSetup(this, 0);
564                         return true;
565                 case IMP_weapon_last.impulse:
566                 case IMP_weapon_prev_byid.impulse:
567                 case IMP_weapon_prev_bypriority.impulse:
568                 case IMP_weapon_prev_bygroup.impulse:
569                         STAT(VEHICLESTAT_W2MODE, this.vehicle) -= 1;
570                         if(STAT(VEHICLESTAT_W2MODE, this.vehicle) < RSM_FIRST)
571                                 STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_LAST;
572
573                         CSQCVehicleSetup(this, 0);
574                         return true;
575
576                 /*
577                 case IMP_weapon_drop.impulse: // toss gun, could be used to exit?
578                         break;
579                 case IMP_weapon_reload.impulse: // Manual minigun reload?
580                         break;
581                 */
582         }
583         return false;
584 }
585
586 spawnfunc(vehicle_raptor)
587 {
588         if(!autocvar_g_vehicle_raptor) { delete(this); return; }
589         if(!vehicle_initialize(this, VEH_RAPTOR, false)) { delete(this); return; }
590 }
591
592 METHOD(Raptor, vr_impact, void(Raptor thisveh, entity instance))
593 {
594     if(autocvar_g_vehicle_raptor_bouncepain)
595         vehicles_impact(instance, autocvar_g_vehicle_raptor_bouncepain_x, autocvar_g_vehicle_raptor_bouncepain_y, autocvar_g_vehicle_raptor_bouncepain_z);
596 }
597 METHOD(Raptor, vr_enter, void(Raptor thisveh, entity instance))
598 {
599     STAT(VEHICLESTAT_W2MODE, instance) = RSM_BOMB;
600     instance.owner.PlayerPhysplug = raptor_takeoff;
601     set_movetype(instance, MOVETYPE_BOUNCEMISSILE);
602     instance.solid                = SOLID_SLIDEBOX;
603     instance.owner.vehicle_health = (GetResource(instance, RES_HEALTH) / autocvar_g_vehicle_raptor_health) * 100;
604     instance.owner.vehicle_shield = (instance.vehicle_shield / autocvar_g_vehicle_raptor_shield) * 100;
605     instance.velocity = '0 0 1'; // nudge upwards so takeoff sequence can work
606     instance.tur_head.exteriormodeltoclient = instance.owner;
607
608     instance.delay = time + autocvar_g_vehicle_raptor_bombs_refire;
609     instance.lip   = time;
610
611     if(instance.owner.flagcarried)
612        setorigin(instance.owner.flagcarried, '-20 0 96');
613
614     CSQCVehicleSetup(instance.owner, 0);
615 }
616 METHOD(Raptor, vr_death, void(Raptor thisveh, entity instance))
617 {
618         SetResourceExplicit(instance, RES_HEALTH, 0);
619     instance.event_damage               = func_null;
620     instance.solid                              = SOLID_CORPSE;
621     instance.takedamage                 = DAMAGE_NO;
622     instance.deadflag                   = DEAD_DYING;
623     set_movetype(instance, MOVETYPE_BOUNCE);
624     setthink(instance, raptor_diethink);
625     instance.nextthink                  = time;
626     instance.wait                               = time + 5 + (random() * 5);
627
628     Send_Effect(EFFECT_EXPLOSION_MEDIUM, findbetterlocation (instance.origin, 16), '0 0 0', 1);
629
630     instance.velocity_z += 600;
631
632     instance.avelocity = '0 0.5 1' * (random() * 400);
633     instance.avelocity -= '0 0.5 1' * (random() * 400);
634
635     instance.colormod = '-0.5 -0.5 -0.5';
636     settouch(instance, raptor_blowup);
637 }
638 METHOD(Raptor, vr_spawn, void(Raptor thisveh, entity instance))
639 {
640     if(!instance.gun1)
641     {
642         entity spinner;
643         vector ofs;
644
645         //FIXME: Camera is in a bad place in HUD model.
646         //setorigin(instance.vehicle_viewport, '25 0 5');
647
648         instance.vehicles_impulse = raptor_impulse;
649
650         instance.frame = 0;
651
652         instance.bomb1 = new(raptor_bomb);
653         instance.bomb2 = new(raptor_bomb);
654         instance.gun1  = new(raptor_gun);
655         instance.gun2  = new(raptor_gun);
656
657         setmodel(instance.bomb1, MDL_VEH_RAPTOR_CB_FOLDED);
658         setmodel(instance.bomb2, MDL_VEH_RAPTOR_CB_FOLDED);
659         setmodel(instance.gun1, MDL_VEH_RAPTOR_GUN);
660         setmodel(instance.gun2, MDL_VEH_RAPTOR_GUN);
661         setmodel(instance.tur_head, MDL_VEH_RAPTOR_TAIL);
662
663         setattachment(instance.bomb1, instance, "bombmount_left");
664         setattachment(instance.bomb2, instance, "bombmount_right");
665         setattachment(instance.tur_head, instance,"root");
666
667         // FIXMODEL Guns mounts to angled bones
668         instance.bomb1.angles = instance.angles;
669         instance.angles = '0 0 0';
670         // This messes up gun-aim, so work arround it.
671         //setattachment(instance.gun1, instance, "gunmount_left");
672         ofs = gettaginfo(instance, gettagindex(instance, "gunmount_left"));
673         ofs -= instance.origin;
674         setattachment(instance.gun1, instance, "");
675         setorigin(instance.gun1, ofs);
676
677         //setattachment(instance.gun2, instance, "gunmount_right");
678         ofs = gettaginfo(instance, gettagindex(instance, "gunmount_right"));
679         ofs -= instance.origin;
680         setattachment(instance.gun2, instance, "");
681         setorigin(instance.gun2, ofs);
682
683         instance.angles = instance.bomb1.angles;
684         instance.bomb1.angles = '0 0 0';
685
686         spinner = new(raptor_spinner);
687         spinner.owner = instance;
688         setmodel(spinner, MDL_VEH_RAPTOR_PROP);
689         setattachment(spinner, instance, "engine_left");
690         set_movetype(spinner, MOVETYPE_NOCLIP);
691         spinner.avelocity = '0 90 0';
692         instance.bomb1.gun1 = spinner;
693
694         spinner = new(raptor_spinner);
695         spinner.owner = instance;
696         setmodel(spinner, MDL_VEH_RAPTOR_PROP);
697         setattachment(spinner, instance, "engine_right");
698         set_movetype(spinner, MOVETYPE_NOCLIP);
699         spinner.avelocity = '0 -90 0';
700         instance.bomb1.gun2 = spinner;
701
702         // Sigh.
703         setthink(instance.bomb1, raptor_rotor_anglefix);
704         instance.bomb1.nextthink = time;
705
706         instance.mass                      = 1 ;
707     }
708
709     instance.frame                = 0;
710     SetResourceExplicit(instance, RES_HEALTH, autocvar_g_vehicle_raptor_health);
711     instance.vehicle_shield = autocvar_g_vehicle_raptor_shield;
712     set_movetype(instance, MOVETYPE_TOSS);
713     instance.solid                = SOLID_SLIDEBOX;
714     instance.vehicle_energy = 1;
715
716     if(!autocvar_g_vehicle_raptor_swim)
717         instance.dphitcontentsmask |= DPCONTENTS_LIQUIDSMASK;
718
719     instance.PlayerPhysplug = raptor_frame;
720
721     instance.bomb1.gun1.avelocity_y = 90;
722     instance.bomb1.gun2.avelocity_y = -90;
723
724     instance.delay = time;
725
726     instance.bouncefactor = autocvar_g_vehicle_raptor_bouncefactor;
727     instance.bouncestop = autocvar_g_vehicle_raptor_bouncestop;
728     instance.damageforcescale = 0.25;
729     SetResourceExplicit(instance, RES_HEALTH, autocvar_g_vehicle_raptor_health);
730     instance.vehicle_shield = autocvar_g_vehicle_raptor_shield;
731 }
732 METHOD(Raptor, vr_setup, void(Raptor thisveh, entity instance))
733 {
734     if(autocvar_g_vehicle_raptor_shield)
735         instance.vehicle_flags |= VHF_HASSHIELD;
736
737     if(autocvar_g_vehicle_raptor_shield_regen)
738         instance.vehicle_flags |= VHF_SHIELDREGEN;
739
740     if(autocvar_g_vehicle_raptor_health_regen)
741         instance.vehicle_flags |= VHF_HEALTHREGEN;
742
743     if(autocvar_g_vehicle_raptor_energy_regen)
744         instance.vehicle_flags |= VHF_ENERGYREGEN;
745
746     instance.vehicle_exit = raptor_exit;
747     instance.respawntime = autocvar_g_vehicle_raptor_respawntime;
748     SetResourceExplicit(instance, RES_HEALTH, autocvar_g_vehicle_raptor_health);
749     instance.vehicle_shield = autocvar_g_vehicle_raptor_shield;
750     instance.max_health = GetResource(instance, RES_HEALTH);
751
752     if(!autocvar_g_vehicle_raptor_swim)
753         instance.dphitcontentsmask |= DPCONTENTS_LIQUIDSMASK;
754 }
755
756 #endif
757 #ifdef CSQC
758
759 METHOD(Raptor, vr_hud, void(Raptor thisveh))
760 {
761     Vehicles_drawHUD(VEH_RAPTOR.m_icon, "vehicle_raptor_weapon1", "vehicle_raptor_weapon2",
762                      "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
763                      "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color);
764 }
765 METHOD(Raptor, vr_crosshair, void(Raptor thisveh, entity player))
766 {
767     string crosshair;
768
769     switch(weapon2mode)
770     {
771         case RSM_FLARE: crosshair = vCROSS_RAIN;  break;
772         case RSM_BOMB:  crosshair = vCROSS_BURST; break;
773         default:        crosshair = vCROSS_BURST;
774     }
775
776     vector tmpSize = '0 0 0';
777     if(weapon2mode != RSM_FLARE && !spectatee_status)
778     {
779         vector where;
780
781         if(!dropmark)
782         {
783             dropmark = new(raptor_dropmark);
784             dropmark.owner = player;
785             dropmark.gravity = 1;
786             dropmark.dphitcontentsmask = DPCONTENTS_SOLID;
787             dropmark.solid = SOLID_CORPSE;
788                         set_movetype(dropmark, MOVETYPE_BOUNCE);
789         }
790
791         float reload2 = STAT(VEHICLESTAT_RELOAD2) * 0.01;
792         if(reload2 == 1)
793         {
794             setorigin(dropmark, pmove_org);
795             dropmark.velocity = pmove_vel;
796             tracetoss(dropmark, player);
797
798             where = project_3d_to_2d(trace_endpos);
799
800             setorigin(dropmark, trace_endpos);
801
802             if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
803             {
804                 tmpSize = draw_getimagesize(vCROSS_DROP) * autocvar_cl_vehicles_crosshair_size;
805                 where.x -= tmpSize.x * 0.5;
806                 where.y -= tmpSize.y * 0.5;
807                 where.z = 0;
808                 drawpic(where, vCROSS_DROP, tmpSize, '0 1 0', autocvar_crosshair_alpha * 0.9, DRAWFLAG_ADDITIVE);
809                 drawpic(where, vCROSS_DROP, tmpSize, '0 1 0', autocvar_crosshair_alpha * 0.6, DRAWFLAG_NORMAL); // Ensure visibility against bright bg
810             }
811             dropmark.cnt = time + 5;
812         }
813         else
814         {
815             if(dropmark.cnt > time)
816             {
817                 where = project_3d_to_2d(dropmark.origin);
818
819                 if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
820                 {
821                     tmpSize = draw_getimagesize(vCROSS_DROP) * autocvar_cl_vehicles_crosshair_size * 1.25;
822                     where.x -= tmpSize.x * 0.5;
823                     where.y -= tmpSize.y * 0.5;
824                     where.z = 0;
825                     drawpic(where, vCROSS_DROP, tmpSize, '1 0 0', autocvar_crosshair_alpha * 0.9, DRAWFLAG_ADDITIVE);
826                     drawpic(where, vCROSS_DROP, tmpSize, '1 0 0', autocvar_crosshair_alpha * 0.6, DRAWFLAG_NORMAL); // Ensure visibility against bright bg
827                 }
828             }
829         }
830     }
831
832     Vehicles_drawCrosshair(crosshair);
833 }
834 METHOD(Raptor, vr_setup, void(Raptor thisveh, entity instance))
835 {
836     AuxiliaryXhair[1].axh_image = vCROSS_LOCK;
837 }
838
839 #endif
840
841 #endif