]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/vehicles/vehicle/racer_weapon.qc
Merge branch 'master' into Mario/wepent_experimental
[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, weaponentity, 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, weaponentity, 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, 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 void racer_rocket_tracker(entity this)
68 {
69     vector olddir, newdir;
70     float oldvel, newvel;
71
72     this.nextthink  = time;
73
74     if (IS_DEAD(this.owner) || this.cnt < time)
75     {
76         this.use(this, NULL, NULL);
77         return;
78     }
79
80     if(!this.realowner.vehicle)
81     {
82         UpdateCSQCProjectile(this);
83         return;
84     }
85
86     olddir = normalize(this.velocity);
87     oldvel = vlen(this.velocity);
88     newvel = oldvel + this.lip;
89     makevectors(vectoangles(olddir));
90
91     float time_to_impact = min(vlen(this.enemy.origin - this.origin) / vlen(this.velocity), 1);
92     vector predicted_origin = this.enemy.origin + this.enemy.velocity * time_to_impact;
93
94     traceline(this.origin, this.origin + v_forward * 64 - '0 0 32', MOVE_NORMAL, this);
95     newdir = normalize(predicted_origin - this.origin);
96
97     //vector
98     float height_diff = predicted_origin_z - this.origin_z;
99
100     if(vdist(newdir - v_forward, >, autocvar_g_vehicle_racer_rocket_locked_maxangle))
101     {
102         //bprint("Target lost!\n");
103         //dprint("OF:", ftos(vlen(newdir - v_forward)), "\n");
104         setthink(this, racer_rocket_groundhugger);
105         return;
106     }
107
108     if(trace_fraction != 1.0 && trace_ent != this.enemy)
109         newdir_z += 16 * sys_frametime;
110
111     this.velocity = normalize(olddir + newdir * autocvar_g_vehicle_racer_rocket_turnrate) * newvel;
112     this.velocity_z -= 800 * sys_frametime;
113     this.velocity_z += max(height_diff, autocvar_g_vehicle_racer_rocket_climbspeed) * sys_frametime ;
114
115     UpdateCSQCProjectile(this);
116     return;
117 }
118
119 void racer_rocket_groundhugger(entity this)
120 {
121     vector olddir, newdir;
122     float oldvel, newvel;
123
124     this.nextthink  = time;
125
126     if(IS_DEAD(this.owner) || this.cnt < time)
127     {
128         this.use(this, NULL, NULL);
129         return;
130     }
131
132     if(!this.realowner.vehicle)
133     {
134         UpdateCSQCProjectile(this);
135         return;
136     }
137
138     olddir = normalize(this.velocity);
139     oldvel = vlen(this.velocity);
140     newvel = oldvel + this.lip;
141
142     tracebox(this.origin, this.mins, this.maxs, this.origin + olddir * 64, MOVE_WORLDONLY,this);
143     if(trace_fraction <= 0.5)
144     {
145         // Hitting somethign soon, just speed ahead
146         this.velocity = olddir * newvel;
147         UpdateCSQCProjectile(this);
148         return;
149     }
150
151     traceline(trace_endpos, trace_endpos - '0 0 64', MOVE_NORMAL, this);
152     if(trace_fraction != 1.0)
153     {
154         newdir = normalize(trace_endpos + '0 0 64' - this.origin) * autocvar_g_vehicle_racer_rocket_turnrate;
155         this.velocity = normalize(olddir + newdir) * newvel;
156     }
157     else
158     {
159         this.velocity = olddir * newvel;
160         this.velocity_z -= 1600 * sys_frametime; // 2x grav looks better for this one
161     }
162
163     int cont = pointcontents(this.origin - '0 0 32');
164     if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME)
165         this.velocity_z += 200;
166
167     UpdateCSQCProjectile(this);
168     return;
169 }
170
171 #endif
172
173 #endif