Makefile: use `-I.`
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / vehicles / vehicle / spiderbot_weapons.qc
1 #ifndef VEHICLE_SPIDERBOT_WEAPONS_H
2 #define VEHICLE_SPIDERBOT_WEAPONS_H
3
4 #include <common/weapons/all.qh>
5
6 #endif
7
8 #ifdef IMPLEMENTATION
9
10 #ifdef SVQC
11
12 float autocvar_g_vehicle_spiderbot_minigun_damage;
13 float autocvar_g_vehicle_spiderbot_minigun_refire;
14 float autocvar_g_vehicle_spiderbot_minigun_spread;
15 int autocvar_g_vehicle_spiderbot_minigun_ammo_cost;
16 int autocvar_g_vehicle_spiderbot_minigun_ammo_max;
17 int autocvar_g_vehicle_spiderbot_minigun_ammo_regen;
18 float autocvar_g_vehicle_spiderbot_minigun_ammo_regen_pause;
19 float autocvar_g_vehicle_spiderbot_minigun_force;
20 float autocvar_g_vehicle_spiderbot_minigun_solidpenetration;
21
22 float autocvar_g_vehicle_spiderbot_rocket_damage;
23 float autocvar_g_vehicle_spiderbot_rocket_force;
24 float autocvar_g_vehicle_spiderbot_rocket_radius;
25 float autocvar_g_vehicle_spiderbot_rocket_speed;
26 float autocvar_g_vehicle_spiderbot_rocket_spread;
27 float autocvar_g_vehicle_spiderbot_rocket_refire;
28 float autocvar_g_vehicle_spiderbot_rocket_refire2;
29 float autocvar_g_vehicle_spiderbot_rocket_reload;
30 float autocvar_g_vehicle_spiderbot_rocket_health;
31 float autocvar_g_vehicle_spiderbot_rocket_noise;
32 float autocvar_g_vehicle_spiderbot_rocket_turnrate;
33 float autocvar_g_vehicle_spiderbot_rocket_lifetime;
34
35 void spiderbot_rocket_artillery()
36 {SELFPARAM();
37     self.nextthink = time;
38     UpdateCSQCProjectile(self);
39 }
40
41 void spiderbot_rocket_unguided()
42 {SELFPARAM();
43     vector newdir, olddir;
44
45     self.nextthink  = time;
46
47     olddir = normalize(self.velocity);
48     newdir = normalize(self.pos1 - self.origin) + randomvec() * autocvar_g_vehicle_spiderbot_rocket_noise;
49     self.velocity = normalize(olddir + newdir * autocvar_g_vehicle_spiderbot_rocket_turnrate) * autocvar_g_vehicle_spiderbot_rocket_speed;
50
51     UpdateCSQCProjectile(self);
52
53     if (self.owner.deadflag != DEAD_NO || self.cnt < time || vlen(self.pos1 - self.origin) < 16)
54         self.use();
55 }
56
57 void spiderbot_rocket_guided()
58 {SELFPARAM();
59     vector newdir, olddir;
60
61     self.nextthink  = time;
62
63     if(!self.realowner.vehicle)
64         self.think = spiderbot_rocket_unguided;
65
66     crosshair_trace(self.realowner);
67     olddir = normalize(self.velocity);
68     newdir = normalize(trace_endpos - self.origin) + randomvec() * autocvar_g_vehicle_spiderbot_rocket_noise;
69     self.velocity = normalize(olddir + newdir * autocvar_g_vehicle_spiderbot_rocket_turnrate) * autocvar_g_vehicle_spiderbot_rocket_speed;
70
71     UpdateCSQCProjectile(self);
72
73     if (self.owner.deadflag != DEAD_NO || self.cnt < time)
74         self.use();
75 }
76
77 void spiderbot_guide_release()
78 {SELFPARAM();
79     entity rkt;
80     rkt = findchainentity(realowner, self.owner);
81     if(!rkt)
82         return;
83
84     crosshair_trace(self.owner);
85     while(rkt)
86     {
87         if(rkt.think == spiderbot_rocket_guided)
88         {
89             rkt.pos1 = trace_endpos;
90             rkt.think = spiderbot_rocket_unguided;
91         }
92         rkt = rkt.chain;
93     }
94 }
95
96 float spiberbot_calcartillery_flighttime;
97 vector spiberbot_calcartillery(vector org, vector tgt, float ht)
98 {
99     float grav, sdist, zdist, vs, vz, jumpheight;
100     vector sdir;
101
102     grav  = autocvar_sv_gravity;
103     zdist = tgt_z - org_z;
104     sdist = vlen(tgt - org - zdist * '0 0 1');
105     sdir  = normalize(tgt - org - zdist * '0 0 1');
106
107     // how high do we need to go?
108     jumpheight = fabs(ht);
109     if(zdist > 0)
110         jumpheight = jumpheight + zdist;
111
112     // push so high...
113     vz = sqrt(2 * grav * jumpheight); // NOTE: sqrt(positive)!
114
115     // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
116     if(ht < 0)
117         if(zdist < 0)
118             vz = -vz;
119
120     vector solution;
121     solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
122     // ALWAYS solvable because jumpheight >= zdist
123     if(!solution_z)
124         solution_y = solution_x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
125     if(zdist == 0)
126         solution_x = solution_y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
127
128     if(zdist < 0)
129     {
130         // down-jump
131         if(ht < 0)
132         {
133             // almost straight line type
134             // jump apex is before the jump
135             // we must take the larger one
136             spiberbot_calcartillery_flighttime = solution_y;
137         }
138         else
139         {
140             // regular jump
141             // jump apex is during the jump
142             // we must take the larger one too
143             spiberbot_calcartillery_flighttime = solution_y;
144         }
145     }
146     else
147     {
148         // up-jump
149         if(ht < 0)
150         {
151             // almost straight line type
152             // jump apex is after the jump
153             // we must take the smaller one
154             spiberbot_calcartillery_flighttime = solution_x;
155         }
156         else
157         {
158             // regular jump
159             // jump apex is during the jump
160             // we must take the larger one
161             spiberbot_calcartillery_flighttime = solution_y;
162         }
163     }
164     vs = sdist / spiberbot_calcartillery_flighttime;
165
166     // finally calculate the velocity
167     return sdir * vs + '0 0 1' * vz;
168 }
169
170 void spiderbot_rocket_do()
171 {SELFPARAM();
172     vector v;
173     entity rocket = world;
174
175     if (self.wait != -10)
176     {
177         if (self.owner.BUTTON_ATCK2 && self.vehicle_weapon2mode == SBRM_GUIDE)
178         {
179             if (self.wait == 1)
180             if (self.tur_head.frame == 9 || self.tur_head.frame == 1)
181             {
182                 if(self.gun2.cnt < time && self.tur_head.frame == 9)
183                     self.tur_head.frame = 1;
184
185                 return;
186             }
187             self.wait = 1;
188         }
189         else
190         {
191             if(self.wait)
192                 spiderbot_guide_release();
193
194             self.wait = 0;
195         }
196     }
197
198     if(self.gun2.cnt > time)
199         return;
200
201     if (self.tur_head.frame >= 9)
202     {
203         self.tur_head.frame = 1;
204         self.wait = 0;
205     }
206
207     if(self.wait != -10)
208     if(!self.owner.BUTTON_ATCK2)
209         return;
210
211     if(forbidWeaponUse(self.owner))
212         return;
213
214     v = gettaginfo(self.tur_head,gettagindex(self.tur_head,"tag_fire"));
215
216     switch(self.vehicle_weapon2mode)
217     {
218         case SBRM_VOLLY:
219             rocket = vehicles_projectile(EFFECT_SPIDERBOT_ROCKETLAUNCH.eent_eff_name, SND(ROCKET_FIRE),
220                                    v, normalize(randomvec() * autocvar_g_vehicle_spiderbot_rocket_spread + v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed,
221                                    autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1,
222                                    DEATH_VH_SPID_ROCKET.m_id, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, true, self.owner);
223             crosshair_trace(self.owner);
224             float _dist = (random() * autocvar_g_vehicle_spiderbot_rocket_radius) + vlen(v - trace_endpos);
225             _dist -= (random() * autocvar_g_vehicle_spiderbot_rocket_radius) ;
226             rocket.nextthink  = time + (_dist / autocvar_g_vehicle_spiderbot_rocket_speed);
227             rocket.think         = vehicles_projectile_explode;
228
229             if(self.owner.BUTTON_ATCK2 && self.tur_head.frame == 1)
230                 self.wait = -10;
231             break;
232         case SBRM_GUIDE:
233             rocket = vehicles_projectile(EFFECT_SPIDERBOT_ROCKETLAUNCH.eent_eff_name, SND(ROCKET_FIRE),
234                                    v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed,
235                                    autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1,
236                                    DEATH_VH_SPID_ROCKET.m_id, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, false, self.owner);
237             crosshair_trace(self.owner);
238             rocket.pos1    = trace_endpos;
239             rocket.nextthink  = time;
240             rocket.think          = spiderbot_rocket_guided;
241
242
243         break;
244         case SBRM_ARTILLERY:
245             rocket = vehicles_projectile(EFFECT_SPIDERBOT_ROCKETLAUNCH.eent_eff_name, SND(ROCKET_FIRE),
246                                    v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed,
247                                    autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1,
248                                    DEATH_VH_SPID_ROCKET.m_id, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, true, self.owner);
249
250             crosshair_trace(self.owner);
251
252             rocket.pos1    = trace_endpos + randomvec() * (0.75 * autocvar_g_vehicle_spiderbot_rocket_radius);
253             rocket.pos1_z          = trace_endpos_z;
254
255             traceline(v, v + '0 0 1' * MAX_SHOT_DISTANCE, MOVE_WORLDONLY, self);
256             float h1 = 0.75 * vlen(v - trace_endpos);
257
258             //v = trace_endpos;
259             traceline(v , rocket.pos1 + '0 0 1' * MAX_SHOT_DISTANCE, MOVE_WORLDONLY, self);
260             float h2 = 0.75 * vlen(rocket.pos1 - v);
261
262             rocket.velocity  = spiberbot_calcartillery(v, rocket.pos1, ((h1 < h2) ? h1 : h2));
263             rocket.movetype  = MOVETYPE_TOSS;
264             rocket.gravity   = 1;
265             //rocket.think       = spiderbot_rocket_artillery;
266         break;
267     }
268     rocket.classname  = "spiderbot_rocket";
269
270     rocket.cnt = time + autocvar_g_vehicle_spiderbot_rocket_lifetime;
271
272     self.tur_head.frame += 1;
273     if (self.tur_head.frame == 9)
274         self.attack_finished_single[0] = autocvar_g_vehicle_spiderbot_rocket_reload;
275     else
276         self.attack_finished_single[0] = ((self.vehicle_weapon2mode ==  SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
277
278     self.gun2.cnt = time + self.attack_finished_single[0];
279 }
280
281 #endif
282
283 #endif