]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/vehicles/vehicle/racer_weapon.qc
take3: format 903 files
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / vehicles / vehicle / racer_weapon.qc
1 #include "racer_weapon.qh"
2
3 #ifdef SVQC
4
5 void racer_fire_rocket(entity player, vector org, vector dir, entity trg);
6 METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
7 {
8         bool isPlayer = IS_PLAYER(actor);
9         entity player = isPlayer ? actor : actor.owner;
10         entity veh = player.vehicle;
11         if (fire & 1) {
12                 if (weapon_prepareattack(thiswep, player, weaponentity, false, autocvar_g_vehicle_racer_cannon_refire)) {
13                         if (veh) {
14                                 veh.vehicle_energy -= autocvar_g_vehicle_racer_cannon_cost;
15                                 veh.wait = time;
16                         }
17                         if (isPlayer) { W_SetupShot_Dir(player, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0); }
18                         vector org = w_shotorg;
19                         vector dir = w_shotdir;
20                         entity bolt = vehicles_projectile(veh, EFFECT_RACER_MUZZLEFLASH.eent_eff_name, SND_LASERGUN_FIRE,
21                                 org, normalize(v_forward + randomvec() * autocvar_g_vehicle_racer_cannon_spread) * autocvar_g_vehicle_racer_cannon_speed,
22                                 autocvar_g_vehicle_racer_cannon_damage, autocvar_g_vehicle_racer_cannon_radius, autocvar_g_vehicle_racer_cannon_force,  0,
23                                 DEATH_VH_WAKI_GUN.m_id, PROJECTILE_WAKICANNON, 0, true, true, player);
24                         bolt.velocity = normalize(dir) * autocvar_g_vehicle_racer_cannon_speed;
25                         weapon_thinkf(player, weaponentity, WFRAME_FIRE1, 0, w_ready);
26                 }
27         }
28         if (fire & 2) {
29                 if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
30                         if (isPlayer) { W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0); }
31                         racer_fire_rocket(player, w_shotorg, w_shotdir, NULL);
32                         weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
33                 }
34         }
35 }
36
37 METHOD(RacerAttack, wr_checkammo1, bool(RacerAttack thiswep, entity actor, .entity weaponentity))
38 {
39         bool isPlayer = IS_PLAYER(actor);
40         entity player = isPlayer ? actor : actor.owner;
41         entity veh = player.vehicle;
42         return isPlayer || veh.vehicle_energy >= autocvar_g_vehicle_racer_cannon_cost;
43 }
44
45 void racer_rocket_tracker(entity this);
46 void racer_rocket_groundhugger(entity this);
47
48 void racer_fire_rocket(entity player, vector org, vector dir, entity trg)
49 {
50         entity rocket = vehicles_projectile(player.vehicle, EFFECT_RACER_ROCKETLAUNCH.eent_eff_name, SND_ROCKET_FIRE,
51                 org, dir * autocvar_g_vehicle_racer_rocket_speed,
52                 autocvar_g_vehicle_racer_rocket_damage, autocvar_g_vehicle_racer_rocket_radius, autocvar_g_vehicle_racer_rocket_force, 3,
53                 DEATH_VH_WAKI_ROCKET.m_id, PROJECTILE_WAKIROCKET, 20, false, false, player);
54
55         rocket.lip            = autocvar_g_vehicle_racer_rocket_accel * sys_frametime;
56         rocket.wait          = autocvar_g_vehicle_racer_rocket_turnrate;
57         rocket.nextthink        = time;
58         rocket.enemy            = trg;
59         rocket.cnt            = time + 15;
60
61         if (trg) {
62                 setthink(rocket, racer_rocket_tracker);
63         } else {
64                 setthink(rocket, racer_rocket_groundhugger);
65         }
66 }
67
68 void racer_rocket_tracker(entity this)
69 {
70         vector olddir, newdir;
71         float oldvel, newvel;
72
73         this.nextthink  = time;
74
75         if (IS_DEAD(this.owner) || this.cnt < time) {
76                 this.use(this, NULL, NULL);
77                 return;
78         }
79
80         if (!this.realowner.vehicle) {
81                 UpdateCSQCProjectile(this);
82                 return;
83         }
84
85         olddir = normalize(this.velocity);
86         oldvel = vlen(this.velocity);
87         newvel = oldvel + this.lip;
88         makevectors(vectoangles(olddir));
89
90         float time_to_impact = min(vlen(this.enemy.origin - this.origin) / vlen(this.velocity), 1);
91         vector predicted_origin = this.enemy.origin + this.enemy.velocity * time_to_impact;
92
93         traceline(this.origin, this.origin + v_forward * 64 - '0 0 32', MOVE_NORMAL, this);
94         newdir = normalize(predicted_origin - this.origin);
95
96         // vector
97         float height_diff = predicted_origin_z - this.origin_z;
98
99         if (vdist(newdir - v_forward, >, autocvar_g_vehicle_racer_rocket_locked_maxangle)) {
100                 // bprint("Target lost!\n");
101                 // dprint("OF:", ftos(vlen(newdir - v_forward)), "\n");
102                 setthink(this, racer_rocket_groundhugger);
103                 return;
104         }
105
106         if (trace_fraction != 1.0 && trace_ent != this.enemy) {
107                 newdir_z += 16 * sys_frametime;
108         }
109
110         this.velocity = normalize(olddir + newdir * autocvar_g_vehicle_racer_rocket_turnrate) * newvel;
111         this.velocity_z -= 800 * sys_frametime;
112         this.velocity_z += max(height_diff, autocvar_g_vehicle_racer_rocket_climbspeed) * sys_frametime;
113
114         UpdateCSQCProjectile(this);
115 }
116
117 void racer_rocket_groundhugger(entity this)
118 {
119         vector olddir, newdir;
120         float oldvel, newvel;
121
122         this.nextthink  = time;
123
124         if (IS_DEAD(this.owner) || this.cnt < time) {
125                 this.use(this, NULL, NULL);
126                 return;
127         }
128
129         if (!this.realowner.vehicle) {
130                 UpdateCSQCProjectile(this);
131                 return;
132         }
133
134         olddir = normalize(this.velocity);
135         oldvel = vlen(this.velocity);
136         newvel = oldvel + this.lip;
137
138         tracebox(this.origin, this.mins, this.maxs, this.origin + olddir * 64, MOVE_WORLDONLY, this);
139         if (trace_fraction <= 0.5) {
140                 // Hitting somethign soon, just speed ahead
141                 this.velocity = olddir * newvel;
142                 UpdateCSQCProjectile(this);
143                 return;
144         }
145
146         traceline(trace_endpos, trace_endpos - '0 0 64', MOVE_NORMAL, this);
147         if (trace_fraction != 1.0) {
148                 newdir = normalize(trace_endpos + '0 0 64' - this.origin) * autocvar_g_vehicle_racer_rocket_turnrate;
149                 this.velocity = normalize(olddir + newdir) * newvel;
150         } else {
151                 this.velocity = olddir * newvel;
152                 this.velocity_z -= 1600 * sys_frametime; // 2x grav looks better for this one
153         }
154
155         int cont = pointcontents(this.origin - '0 0 32');
156         if (cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) {
157                 this.velocity_z += 200;
158         }
159
160         UpdateCSQCProjectile(this);
161 }
162
163 #endif