1 #include "racer_weapon.qh"
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))
10 bool isPlayer = IS_PLAYER(actor);
11 entity player = isPlayer ? actor : actor.owner;
12 entity veh = player.vehicle;
14 if (weapon_prepareattack(thiswep, player, weaponentity, false, autocvar_g_vehicle_racer_cannon_refire)) {
16 veh.vehicle_energy -= autocvar_g_vehicle_racer_cannon_cost;
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);
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);
37 METHOD(RacerAttack, wr_checkammo1, bool(RacerAttack thiswep))
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;
46 void racer_rocket_tracker();
47 void racer_rocket_groundhugger();
49 void racer_fire_rocket(entity player, vector org, vector dir, entity trg)
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);
56 rocket.lip = autocvar_g_vehicle_racer_rocket_accel * sys_frametime;
57 rocket.wait = autocvar_g_vehicle_racer_rocket_turnrate;
58 rocket.nextthink = time;
60 rocket.cnt = time + 15;
63 rocket.think = racer_rocket_tracker;
65 rocket.think = racer_rocket_groundhugger;
68 void racer_rocket_tracker()
70 vector olddir, newdir;
73 self.nextthink = time;
75 if (IS_DEAD(self.owner) || self.cnt < time)
77 self.use(self, NULL, NULL);
81 if(!self.realowner.vehicle)
83 UpdateCSQCProjectile(self);
87 olddir = normalize(self.velocity);
88 oldvel = vlen(self.velocity);
89 newvel = oldvel + self.lip;
90 makevectors(vectoangles(olddir));
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;
95 traceline(self.origin, self.origin + v_forward * 64 - '0 0 32', MOVE_NORMAL, self);
96 newdir = normalize(predicted_origin - self.origin);
99 float height_diff = predicted_origin_z - self.origin_z;
101 if(vdist(newdir - v_forward, >, autocvar_g_vehicle_racer_rocket_locked_maxangle))
103 //bprint("Target lost!\n");
104 //dprint("OF:", ftos(vlen(newdir - v_forward)), "\n");
105 self.think = racer_rocket_groundhugger;
109 if(trace_fraction != 1.0 && trace_ent != self.enemy)
110 newdir_z += 16 * sys_frametime;
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 ;
116 UpdateCSQCProjectile(self);
120 void racer_rocket_groundhugger()
122 vector olddir, newdir;
123 float oldvel, newvel;
125 self.nextthink = time;
127 if(IS_DEAD(self.owner) || self.cnt < time)
129 self.use(self, NULL, NULL);
133 if(!self.realowner.vehicle)
135 UpdateCSQCProjectile(self);
139 olddir = normalize(self.velocity);
140 oldvel = vlen(self.velocity);
141 newvel = oldvel + self.lip;
143 tracebox(self.origin, self.mins, self.maxs, self.origin + olddir * 64, MOVE_WORLDONLY,self);
144 if(trace_fraction <= 0.5)
146 // Hitting somethign soon, just speed ahead
147 self.velocity = olddir * newvel;
148 UpdateCSQCProjectile(self);
152 traceline(trace_endpos, trace_endpos - '0 0 64', MOVE_NORMAL, self);
153 if(trace_fraction != 1.0)
155 newdir = normalize(trace_endpos + '0 0 64' - self.origin) * autocvar_g_vehicle_racer_rocket_turnrate;
156 self.velocity = normalize(olddir + newdir) * newvel;
160 self.velocity = olddir * newvel;
161 self.velocity_z -= 1600 * sys_frametime; // 2x grav looks better for this one
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;
168 UpdateCSQCProjectile(self);