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