]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/vehicles/unit/spiderbot.qc
Load vehicles in the menu with the registry system
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / vehicles / unit / spiderbot.qc
1 #ifndef VEHICLE_SPIDERBOT
2 #define VEHICLE_SPIDERBOT
3 REGISTER_VEHICLE_SIMPLE(
4 /* VEH_##id   */ SPIDERBOT,
5 /* function   */ v_spiderbot,
6 /* spawnflags */ VHF_DMGSHAKE,
7 /* mins,maxs  */ '-75 -75 10', '75 75 125',
8 /* model          */ "models/vehicles/spiderbot.dpm",
9 /* head_model */ "models/vehicles/spiderbot_top.dpm",
10 /* hud_model  */ "models/vehicles/spiderbot_cockpit.dpm",
11 /* tags           */ "tag_head", "tag_hud", "",
12 /* netname        */ "spiderbot",
13 /* fullname   */ _("Spiderbot")
14 );
15 #endif
16
17 #ifdef IMPLEMENTATION
18
19 const int SBRM_FIRST = 1;
20 const int SBRM_VOLLY = 1;
21 const int SBRM_GUIDE = 2;
22 const int SBRM_ARTILLERY = 3;
23 const int SBRM_LAST = 3;
24
25 #ifdef SVQC
26 bool autocvar_g_vehicle_spiderbot;
27
28 float autocvar_g_vehicle_spiderbot_respawntime;
29
30 float autocvar_g_vehicle_spiderbot_speed_stop;
31 float autocvar_g_vehicle_spiderbot_speed_strafe;
32 float autocvar_g_vehicle_spiderbot_speed_walk;
33 float autocvar_g_vehicle_spiderbot_speed_run = 700;
34 float autocvar_g_vehicle_spiderbot_turnspeed;
35 float autocvar_g_vehicle_spiderbot_turnspeed_strafe;
36 float autocvar_g_vehicle_spiderbot_movement_inertia;
37
38 float autocvar_g_vehicle_spiderbot_springlength;
39 float autocvar_g_vehicle_spiderbot_springup;
40 float autocvar_g_vehicle_spiderbot_springblend;
41 float autocvar_g_vehicle_spiderbot_tiltlimit;
42
43 float autocvar_g_vehicle_spiderbot_head_pitchlimit_down;
44 float autocvar_g_vehicle_spiderbot_head_pitchlimit_up;
45 float autocvar_g_vehicle_spiderbot_head_turnlimit;
46 float autocvar_g_vehicle_spiderbot_head_turnspeed;
47
48 int autocvar_g_vehicle_spiderbot_health;
49 float autocvar_g_vehicle_spiderbot_health_regen;
50 float autocvar_g_vehicle_spiderbot_health_regen_pause;
51
52 int autocvar_g_vehicle_spiderbot_shield;
53 float autocvar_g_vehicle_spiderbot_shield_regen;
54 float autocvar_g_vehicle_spiderbot_shield_regen_pause;
55
56 float autocvar_g_vehicle_spiderbot_minigun_damage;
57 float autocvar_g_vehicle_spiderbot_minigun_refire;
58 float autocvar_g_vehicle_spiderbot_minigun_spread;
59 int autocvar_g_vehicle_spiderbot_minigun_ammo_cost;
60 int autocvar_g_vehicle_spiderbot_minigun_ammo_max;
61 int autocvar_g_vehicle_spiderbot_minigun_ammo_regen;
62 float autocvar_g_vehicle_spiderbot_minigun_ammo_regen_pause;
63 float autocvar_g_vehicle_spiderbot_minigun_force;
64 float autocvar_g_vehicle_spiderbot_minigun_solidpenetration;
65
66 float autocvar_g_vehicle_spiderbot_rocket_damage;
67 float autocvar_g_vehicle_spiderbot_rocket_force;
68 float autocvar_g_vehicle_spiderbot_rocket_radius;
69 float autocvar_g_vehicle_spiderbot_rocket_speed;
70 float autocvar_g_vehicle_spiderbot_rocket_spread;
71 float autocvar_g_vehicle_spiderbot_rocket_refire;
72 float autocvar_g_vehicle_spiderbot_rocket_refire2;
73 float autocvar_g_vehicle_spiderbot_rocket_reload;
74 float autocvar_g_vehicle_spiderbot_rocket_health;
75 float autocvar_g_vehicle_spiderbot_rocket_noise;
76 float autocvar_g_vehicle_spiderbot_rocket_turnrate;
77 float autocvar_g_vehicle_spiderbot_rocket_lifetime;
78
79 vector autocvar_g_vehicle_spiderbot_bouncepain;
80
81 void spiderbot_rocket_artillery()
82 {
83         self.nextthink = time;
84         UpdateCSQCProjectile(self);
85 }
86
87 void spiderbot_rocket_unguided()
88 {
89         vector newdir, olddir;
90
91         self.nextthink  = time;
92
93         olddir = normalize(self.velocity);
94         newdir = normalize(self.pos1 - self.origin) + randomvec() * autocvar_g_vehicle_spiderbot_rocket_noise;
95         self.velocity = normalize(olddir + newdir * autocvar_g_vehicle_spiderbot_rocket_turnrate) * autocvar_g_vehicle_spiderbot_rocket_speed;
96
97         UpdateCSQCProjectile(self);
98
99         if (self.owner.deadflag != DEAD_NO || self.cnt < time || vlen(self.pos1 - self.origin) < 16)
100                 self.use();
101 }
102
103 void spiderbot_rocket_guided()
104 {
105         vector newdir, olddir;
106
107         self.nextthink  = time;
108
109         if(!self.realowner.vehicle)
110                 self.think = spiderbot_rocket_unguided;
111
112         crosshair_trace(self.realowner);
113         olddir = normalize(self.velocity);
114         newdir = normalize(trace_endpos - self.origin) + randomvec() * autocvar_g_vehicle_spiderbot_rocket_noise;
115         self.velocity = normalize(olddir + newdir * autocvar_g_vehicle_spiderbot_rocket_turnrate) * autocvar_g_vehicle_spiderbot_rocket_speed;
116
117         UpdateCSQCProjectile(self);
118
119         if (self.owner.deadflag != DEAD_NO || self.cnt < time)
120                 self.use();
121 }
122
123 void spiderbot_guide_release()
124 {
125         entity rkt;
126         rkt = findchainentity(realowner, self.owner);
127         if(!rkt)
128                 return;
129
130         crosshair_trace(self.owner);
131         while(rkt)
132         {
133                 if(rkt.think == spiderbot_rocket_guided)
134                 {
135                         rkt.pos1 = trace_endpos;
136                         rkt.think = spiderbot_rocket_unguided;
137                 }
138                 rkt = rkt.chain;
139         }
140 }
141
142 float spiberbot_calcartillery_flighttime;
143 vector spiberbot_calcartillery(vector org, vector tgt, float ht)
144 {
145         float grav, sdist, zdist, vs, vz, jumpheight;
146         vector sdir;
147
148         grav  = autocvar_sv_gravity;
149         zdist = tgt_z - org_z;
150         sdist = vlen(tgt - org - zdist * '0 0 1');
151         sdir  = normalize(tgt - org - zdist * '0 0 1');
152
153         // how high do we need to go?
154         jumpheight = fabs(ht);
155         if(zdist > 0)
156                 jumpheight = jumpheight + zdist;
157
158         // push so high...
159         vz = sqrt(2 * grav * jumpheight); // NOTE: sqrt(positive)!
160
161         // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
162         if(ht < 0)
163                 if(zdist < 0)
164                         vz = -vz;
165
166         vector solution;
167         solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
168         // ALWAYS solvable because jumpheight >= zdist
169         if(!solution_z)
170                 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)
171         if(zdist == 0)
172                 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)
173
174         if(zdist < 0)
175         {
176                 // down-jump
177                 if(ht < 0)
178                 {
179                         // almost straight line type
180                         // jump apex is before the jump
181                         // we must take the larger one
182                         spiberbot_calcartillery_flighttime = solution_y;
183                 }
184                 else
185                 {
186                         // regular jump
187                         // jump apex is during the jump
188                         // we must take the larger one too
189                         spiberbot_calcartillery_flighttime = solution_y;
190                 }
191         }
192         else
193         {
194                 // up-jump
195                 if(ht < 0)
196                 {
197                         // almost straight line type
198                         // jump apex is after the jump
199                         // we must take the smaller one
200                         spiberbot_calcartillery_flighttime = solution_x;
201                 }
202                 else
203                 {
204                         // regular jump
205                         // jump apex is during the jump
206                         // we must take the larger one
207                         spiberbot_calcartillery_flighttime = solution_y;
208                 }
209         }
210         vs = sdist / spiberbot_calcartillery_flighttime;
211
212         // finally calculate the velocity
213         return sdir * vs + '0 0 1' * vz;
214 }
215
216 void spiderbot_rocket_do()
217 {
218         vector v;
219         entity rocket = world;
220
221         if (self.wait != -10)
222         {
223                 if (self.owner.BUTTON_ATCK2 && self.vehicle_weapon2mode == SBRM_GUIDE)
224                 {
225                         if (self.wait == 1)
226                         if (self.tur_head.frame == 9 || self.tur_head.frame == 1)
227                         {
228                                 if(self.gun2.cnt < time && self.tur_head.frame == 9)
229                                         self.tur_head.frame = 1;
230
231                                 return;
232                         }
233                         self.wait = 1;
234                 }
235                 else
236                 {
237                         if(self.wait)
238                                 spiderbot_guide_release();
239
240                         self.wait = 0;
241                 }
242         }
243
244         if(self.gun2.cnt > time)
245                 return;
246
247         if (self.tur_head.frame >= 9)
248         {
249                 self.tur_head.frame = 1;
250                 self.wait = 0;
251         }
252
253         if(self.wait != -10)
254         if(!self.owner.BUTTON_ATCK2)
255                 return;
256                 
257         if(forbidWeaponUse(self.owner))
258                 return;
259
260         v = gettaginfo(self.tur_head,gettagindex(self.tur_head,"tag_fire"));
261
262         switch(self.vehicle_weapon2mode)
263         {
264                 case SBRM_VOLLY:
265                         rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav",
266                                                                    v, normalize(randomvec() * autocvar_g_vehicle_spiderbot_rocket_spread + v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed,
267                                                                    autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1,
268                                                                    DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, true, self.owner);
269                         crosshair_trace(self.owner);
270                         float _dist = (random() * autocvar_g_vehicle_spiderbot_rocket_radius) + vlen(v - trace_endpos);
271                         _dist -= (random() * autocvar_g_vehicle_spiderbot_rocket_radius) ;
272                         rocket.nextthink  = time + (_dist / autocvar_g_vehicle_spiderbot_rocket_speed);
273                         rocket.think     = vehicles_projectile_explode;
274
275                         if(self.owner.BUTTON_ATCK2 && self.tur_head.frame == 1)
276                                 self.wait = -10;
277                         break;
278                 case SBRM_GUIDE:
279                         rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav",
280                                                                    v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed,
281                                                                    autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1,
282                                                                    DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, false, self.owner);
283                         crosshair_trace(self.owner);
284                         rocket.pos1        = trace_endpos;
285                         rocket.nextthink  = time;
286                         rocket.think      = spiderbot_rocket_guided;
287
288
289                 break;
290                 case SBRM_ARTILLERY:
291                         rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav",
292                                                                    v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed,
293                                                                    autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1,
294                                                                    DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, true, self.owner);
295
296                         crosshair_trace(self.owner);
297
298                         rocket.pos1        = trace_endpos + randomvec() * (0.75 * autocvar_g_vehicle_spiderbot_rocket_radius);
299                         rocket.pos1_z      = trace_endpos_z;
300
301                         traceline(v, v + '0 0 1' * MAX_SHOT_DISTANCE, MOVE_WORLDONLY, self);
302                         float h1 = 0.75 * vlen(v - trace_endpos);
303
304                         //v = trace_endpos;
305                         traceline(v , rocket.pos1 + '0 0 1' * MAX_SHOT_DISTANCE, MOVE_WORLDONLY, self);
306                         float h2 = 0.75 * vlen(rocket.pos1 - v);
307
308                         rocket.velocity  = spiberbot_calcartillery(v, rocket.pos1, ((h1 < h2) ? h1 : h2));
309                         rocket.movetype  = MOVETYPE_TOSS;
310                         rocket.gravity   = 1;
311                         //rocket.think   = spiderbot_rocket_artillery;
312                 break;
313         }
314         rocket.classname  = "spiderbot_rocket";
315
316         rocket.cnt = time + autocvar_g_vehicle_spiderbot_rocket_lifetime;
317
318         self.tur_head.frame += 1;
319         if (self.tur_head.frame == 9)
320                 self.attack_finished_single = autocvar_g_vehicle_spiderbot_rocket_reload;
321         else
322                 self.attack_finished_single = ((self.vehicle_weapon2mode ==  SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
323
324         self.gun2.cnt = time + self.attack_finished_single;
325 }
326
327 .float jump_delay;
328 float spiderbot_frame()
329 {
330         vector ad, vf;
331         entity player, spider;
332         float ftmp;
333
334         if(intermission_running)
335         {
336                 self.vehicle.velocity = '0 0 0';
337                 self.vehicle.avelocity = '0 0 0';
338                 return 1;
339         }
340
341         player = self;
342         spider = self.vehicle;
343         self   = spider;
344
345         vehicles_painframe();
346
347         player.BUTTON_ZOOM        = 0;
348         player.BUTTON_CROUCH    = 0;
349         player.switchweapon      = 0;
350         player.vehicle_weapon2mode = spider.vehicle_weapon2mode;
351
352
353 #if 1 // 0 to enable per-gun impact aux crosshairs
354         // Avarage gun impact point's -> aux cross
355         ad = gettaginfo(spider.tur_head, gettagindex(spider.tur_head, "tag_hardpoint01"));
356         vf = v_forward;
357         ad += gettaginfo(spider.tur_head, gettagindex(spider.tur_head, "tag_hardpoint02"));
358         vf += v_forward;
359         ad = ad * 0.5;
360         v_forward = vf * 0.5;
361         traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, spider);
362         UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload1) + ('0 1 0' * (1 - player.vehicle_reload1)), 0);
363 #else
364         ad = gettaginfo(spider.gun1, gettagindex(spider.gun1, "barrels"));
365         traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, spider);
366         UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload1) + ('0 1 0' * (1 - player.vehicle_reload1)), 0);
367         vf = ad;
368         ad = gettaginfo(spider.gun2, gettagindex(spider.gun2, "barrels"));
369         traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, spider);
370         UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload1) + ('0 1 0' * (1 - player.vehicle_reload1)), 1);
371         ad = 0.5 * (ad + vf);
372 #endif
373
374         crosshair_trace(player);
375         ad = vectoangles(normalize(trace_endpos - ad));
376         ad = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(spider.angles), AnglesTransform_FromAngles(ad))) - spider.tur_head.angles;
377         ad = AnglesTransform_Normalize(ad, true);
378         //UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload2) + ('0 1 0' * (1 - player.vehicle_reload2)), 2);
379
380         // Rotate head
381         ftmp = autocvar_g_vehicle_spiderbot_head_turnspeed * sys_frametime;
382         ad_y = bound(-ftmp, ad_y, ftmp);
383         spider.tur_head.angles_y = bound(autocvar_g_vehicle_spiderbot_head_turnlimit * -1, spider.tur_head.angles_y + ad_y, autocvar_g_vehicle_spiderbot_head_turnlimit);
384
385         // Pitch head
386         ad_x = bound(ftmp * -1, ad_x, ftmp);
387         spider.tur_head.angles_x = bound(autocvar_g_vehicle_spiderbot_head_pitchlimit_down, spider.tur_head.angles_x + ad_x, autocvar_g_vehicle_spiderbot_head_pitchlimit_up);
388
389
390         //fixedmakevectors(spider.angles);
391         makevectors(spider.angles + '-2 0 0' * spider.angles_x);
392
393         movelib_groundalign4point(autocvar_g_vehicle_spiderbot_springlength, autocvar_g_vehicle_spiderbot_springup, autocvar_g_vehicle_spiderbot_springblend, autocvar_g_vehicle_spiderbot_tiltlimit);
394
395         if(spider.flags & FL_ONGROUND)
396                 spider.jump_delay = time; // reset now so movement can begin
397
398         //if(spider.flags & FL_ONGROUND)
399         {
400                 if(spider.flags & FL_ONGROUND)
401                 if(spider.frame == 4 && self.tur_head.wait != 0)
402                 {
403                         sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_land.wav", VOL_VEHICLEENGINE, ATTEN_NORM);
404                         spider.frame = 5;
405                 }
406
407                 if(!player.BUTTON_JUMP)
408                         spider.BUTTON_JUMP = 0;
409
410                 if((spider.flags & FL_ONGROUND) && player.BUTTON_JUMP && !spider.BUTTON_JUMP && self.tur_head.wait < time)
411                 {
412                         sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_jump.wav", VOL_VEHICLEENGINE, ATTEN_NORM);
413                         //dprint("spiderbot_jump:", ftos(soundlength("vehicles/spiderbot_jump.wav")), "\n");
414                         self.delay = 0;
415
416                         self.tur_head.wait = time + 2;
417                         spider.jump_delay = time + 2;
418                         spider.BUTTON_JUMP = 1; // set spider's jump
419                         //player.BUTTON_JUMP = 0;
420
421                         vector movefix = '0 0 0';
422                         if(player.movement_x > 0) movefix_x = 1;
423                         if(player.movement_x < 0) movefix_x = -1;
424                         if(player.movement_y > 0) movefix_y = 1;
425                         if(player.movement_y < 0) movefix_y = -1;
426
427                         vector rt = movefix_y * v_right;
428                         vector sd = movefix_x * v_forward;
429                         if(movefix_y == 0 && movefix_x == 0)
430                                 sd = v_forward; // always do forward
431
432                         spider.flags &= ~FL_ONGROUND;
433
434                         spider.velocity = sd * 700 + rt * 600 + v_up * 600;
435                         spider.frame = 4;
436                 }
437                 else if(time >= spider.jump_delay)
438                 {
439                         if(vlen(player.movement) == 0)
440                         {
441                                 if(spider.flags & FL_ONGROUND)
442                                 {
443                                         if(self.sound_nexttime < time || self.delay != 3)
444                                         {
445                                                 self.delay = 3;
446                                                 self.sound_nexttime = time + 6.486500; //soundlength("vehicles/spiderbot_idle.wav");
447                                                 //dprint("spiderbot_idle:", ftos(soundlength("vehicles/spiderbot_idle.wav")), "\n");
448                                                 sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_idle.wav", VOL_VEHICLEENGINE, ATTEN_NORM);
449                                         }
450                                         movelib_beak_simple(autocvar_g_vehicle_spiderbot_speed_stop);
451                                         spider.frame = 5;
452                                 }
453                         }
454                         else
455                         {
456                                 // Turn Body
457                                 if(player.movement_x == 0 && player.movement_y != 0)
458                                         ftmp = autocvar_g_vehicle_spiderbot_turnspeed_strafe * sys_frametime;
459                                 else
460                                         ftmp = autocvar_g_vehicle_spiderbot_turnspeed * sys_frametime;
461
462                                 ftmp = bound(-ftmp, spider.tur_head.angles_y, ftmp);
463                                 spider.angles_y = anglemods(spider.angles_y + ftmp);
464                                 spider.tur_head.angles_y -= ftmp;
465
466                                 if(player.movement_x != 0)
467                                 {
468                                         if(player.movement_x > 0)
469                                         {
470                                                 player.movement_x = 1;
471                                                 if(spider.flags & FL_ONGROUND)
472                                                         spider.frame = 0;
473                                         }
474                                         else if(player.movement_x < 0)
475                                         {
476                                                 player.movement_x = -1;
477                                                 if(spider.flags & FL_ONGROUND)
478                                                         spider.frame = 1;
479                                         }
480                                         player.movement_y = 0;
481                                         float oldvelz = spider.velocity_z;
482                                         movelib_move_simple(normalize(v_forward * player.movement_x),((player.BUTTON_JUMP) ? autocvar_g_vehicle_spiderbot_speed_run : autocvar_g_vehicle_spiderbot_speed_walk),autocvar_g_vehicle_spiderbot_movement_inertia);
483                                         spider.velocity_z = oldvelz;
484                                         float g = ((autocvar_sv_gameplayfix_gravityunaffectedbyticrate) ? 0.5 : 1);
485                                         if(spider.velocity_z <= 20) // not while jumping
486                                                 spider.velocity_z -= g * sys_frametime * autocvar_sv_gravity;
487                                         if(spider.flags & FL_ONGROUND)
488                                         if(self.sound_nexttime < time || self.delay != 1)
489                                         {
490                                                 self.delay = 1;
491                                                 self.sound_nexttime = time + 6.486500; //soundlength("vehicles/spiderbot_walk.wav");
492                                                 sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_walk.wav", VOL_VEHICLEENGINE, ATTEN_NORM);
493                                                 //dprint("spiderbot_walk:", ftos(soundlength("vehicles/spiderbot_walk.wav")), "\n");
494                                         }
495                                 }
496                                 else if(player.movement_y != 0)
497                                 {
498                                         if(player.movement_y < 0)
499                                         {
500                                                 player.movement_y = -1;
501                                                 if(spider.flags & FL_ONGROUND)
502                                                         spider.frame = 2;
503                                         }
504                                         else if(player.movement_y > 0)
505                                         {
506                                                 player.movement_y = 1;
507                                                 if(spider.flags & FL_ONGROUND)
508                                                         spider.frame = 3;
509                                         }
510
511                                         float oldvelz = spider.velocity_z;
512                                         movelib_move_simple(normalize(v_right * player.movement_y),autocvar_g_vehicle_spiderbot_speed_strafe,autocvar_g_vehicle_spiderbot_movement_inertia);
513                                         spider.velocity_z = oldvelz;
514                                         float g = ((autocvar_sv_gameplayfix_gravityunaffectedbyticrate) ? 0.5 : 1);
515                                         if(spider.velocity_z <= 20) // not while jumping
516                                                 spider.velocity_z -= g * sys_frametime * autocvar_sv_gravity;
517                                         if(spider.flags & FL_ONGROUND)
518                                         if(self.sound_nexttime < time || self.delay != 2)
519                                         {
520                                                 self.delay = 2;
521                                                 self.sound_nexttime = time + 6.486500; //soundlength("vehicles/spiderbot_strafe.wav");
522                                                 sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_strafe.wav", VOL_VEHICLEENGINE, ATTEN_NORM);
523                                                 //dprint("spiderbot_strafe:", ftos(soundlength("vehicles/spiderbot_strafe.wav")), "\n");
524                                         }
525                                 }
526                         }
527                 }
528         }
529
530         self.angles_x = bound(-autocvar_g_vehicle_spiderbot_tiltlimit, self.angles_x, autocvar_g_vehicle_spiderbot_tiltlimit);
531         self.angles_z = bound(-autocvar_g_vehicle_spiderbot_tiltlimit, self.angles_z, autocvar_g_vehicle_spiderbot_tiltlimit);
532
533         if(!forbidWeaponUse(player))
534         if(player.BUTTON_ATCK)
535         {
536                 spider.cnt = time;
537                 if(spider.vehicle_ammo1 >= autocvar_g_vehicle_spiderbot_minigun_ammo_cost && spider.tur_head.attack_finished_single <= time)
538                 {
539                         entity gun;
540                         vector v;
541                         spider.misc_bulletcounter += 1;
542
543                         self = player;
544
545                         gun = (spider.misc_bulletcounter % 2) ? spider.gun1 : spider.gun2;
546
547                         v = gettaginfo(gun, gettagindex(gun, "barrels"));
548                         v_forward = normalize(v_forward);
549                         v += v_forward * 50;
550
551                         fireBullet(v, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_solidpenetration,
552                                 autocvar_g_vehicle_spiderbot_minigun_damage, autocvar_g_vehicle_spiderbot_minigun_force, DEATH_VH_SPID_MINIGUN, 0);
553
554                         sound (gun, CH_WEAPON_A, "weapons/uzi_fire.wav", VOL_BASE, ATTEN_NORM);
555                         //trailparticles(self, particleeffectnum("spiderbot_minigun_trail"), v, trace_endpos);
556                         pointparticles(particleeffectnum("spiderbot_minigun_muzzleflash"), v, v_forward * 2500, 1);
557
558                         self = spider;
559
560                         spider.vehicle_ammo1 -= autocvar_g_vehicle_spiderbot_minigun_ammo_cost;
561                         spider.tur_head.attack_finished_single = time + autocvar_g_vehicle_spiderbot_minigun_refire;
562                         player.vehicle_ammo1 = (spider.vehicle_ammo1 / autocvar_g_vehicle_spiderbot_minigun_ammo_max) * 100;
563                         spider.gun1.angles_z += 45;
564                         spider.gun2.angles_z -= 45;
565                         if(spider.gun1.angles_z >= 360)
566                         {
567                                 spider.gun1.angles_z = 0;
568                                 spider.gun2.angles_z = 0;
569                         }
570                 }
571         }
572         else
573                 vehicles_regen(spider.cnt, vehicle_ammo1, autocvar_g_vehicle_spiderbot_minigun_ammo_max,
574                                                                                    autocvar_g_vehicle_spiderbot_minigun_ammo_regen_pause,
575                                                                                    autocvar_g_vehicle_spiderbot_minigun_ammo_regen, frametime, false);
576
577
578         spiderbot_rocket_do();
579
580         if(self.vehicle_flags  & VHF_SHIELDREGEN)
581                 vehicles_regen(spider.dmg_time, vehicle_shield, autocvar_g_vehicle_spiderbot_shield, autocvar_g_vehicle_spiderbot_shield_regen_pause, autocvar_g_vehicle_spiderbot_shield_regen, frametime, true);
582
583         if(self.vehicle_flags  & VHF_HEALTHREGEN)
584                 vehicles_regen(spider.dmg_time, vehicle_health, autocvar_g_vehicle_spiderbot_health, autocvar_g_vehicle_spiderbot_health_regen_pause, autocvar_g_vehicle_spiderbot_health_regen, frametime, false);
585
586         player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0;
587         //player.vehicle_ammo2 = spider.tur_head.frame;
588         player.vehicle_ammo2 = (9 - spider.tur_head.frame) / 8 * 100; // Percentage, like ammo1
589
590         if(spider.gun2.cnt <= time)
591                 player.vehicle_reload2 = 100;
592         else
593                 player.vehicle_reload2 = 100 - ((spider.gun2.cnt - time) / spider.attack_finished_single) * 100;
594
595         setorigin(player, spider.origin + '0 0 1' * spider.maxs_z);
596         player.velocity = spider.velocity;
597
598         VEHICLE_UPDATE_PLAYER(player, health, spiderbot);
599
600         if(self.vehicle_flags & VHF_HASSHIELD)
601                 VEHICLE_UPDATE_PLAYER(player, shield, spiderbot);
602
603         self = player;
604         return 1;
605 }
606
607 void spiderbot_exit(float eject)
608 {
609         entity e;
610         vector spot;
611
612         e = findchain(classname,"spiderbot_rocket");
613         while(e)
614         {
615                 if(e.owner == self.owner)
616                 {
617                         e.realowner = self.owner;
618                         e.owner = world;
619                 }
620                 e = e.chain;
621         }
622
623         self.think = vehicles_think;
624         self.nextthink = time;
625         self.frame = 5;
626         self.movetype = MOVETYPE_WALK;
627
628         if(!self.owner)
629                 return;
630
631         makevectors(self.angles);
632         if(eject)
633         {
634                 spot = self.origin + v_forward * 100 + '0 0 64';
635                 spot = vehicles_findgoodexit(spot);
636                 setorigin(self.owner , spot);
637                 self.owner.velocity = (v_up + v_forward * 0.25) * 750;
638                 self.owner.oldvelocity = self.owner.velocity;
639         }
640         else
641         {
642                 if(vlen(self.velocity) > autocvar_g_vehicle_spiderbot_speed_strafe)
643                 {
644                         self.owner.velocity = normalize(self.velocity) * vlen(self.velocity);
645                         self.owner.velocity_z += 200;
646                         spot = self.origin + v_forward * 128 + '0 0 64';
647                         spot = vehicles_findgoodexit(spot);
648                 }
649                 else
650                 {
651                         self.owner.velocity = self.velocity * 0.5;
652                         self.owner.velocity_z += 10;
653                         spot = self.origin + v_forward * 256 + '0 0 64';
654                         spot = vehicles_findgoodexit(spot);
655                 }
656                 self.owner.oldvelocity = self.owner.velocity;
657                 setorigin(self.owner , spot);
658         }
659
660         antilag_clear(self.owner);
661         self.owner = world;
662 }
663
664 void spiderbot_headfade()
665 {
666         self.think = spiderbot_headfade;
667         self.nextthink = self.fade_time;
668         self.alpha = 1 - (time - self.fade_time) * self.fade_rate;
669
670         if(self.cnt < time || self.alpha < 0.1)
671         {
672                 if(self.alpha > 0.1)
673                 {
674                         sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
675                         Send_Effect("explosion_big", self.origin + '0 0 100', '0 0 0', 1);
676                 }
677                 remove(self);
678         }
679 }
680
681 void spiderbot_blowup()
682 {
683         if(self.cnt > time)
684         {
685                 if(random() < 0.1)
686                 {
687                         sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
688                         Send_Effect("explosion_small", randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
689                 }
690                 self.nextthink = time + 0.1;
691                 return;
692         }
693
694         entity h, g1, g2, b;
695         b = spawn();
696         h = spawn();
697         g1 = spawn();
698         g2 = spawn();
699
700         setmodel(b, "models/vehicles/spiderbot.dpm");
701         setmodel(h, "models/vehicles/spiderbot_top.dpm");
702         setmodel(g1, "models/vehicles/spiderbot_barrels.dpm");
703         setmodel(g2, "models/vehicles/spiderbot_barrels.dpm");
704
705         setorigin(b, self.origin);
706         b.frame = 11;
707         b.angles = self.angles;
708         setsize(b, self.mins, self.maxs);
709
710         setorigin(h, gettaginfo(self, gettagindex(self, "tag_head")));
711         h.movetype = MOVETYPE_BOUNCE;
712         h.solid = SOLID_BBOX;
713         h.velocity = v_up * (500 + random() * 500) + randomvec() * 128;
714         h.modelflags = MF_ROCKET;
715         h.effects = EF_FLAME | EF_LOWPRECISION;
716         h.avelocity = randomvec() * 360;
717
718         h.alpha = 1;
719         h.cnt = time + (3.5 * random());
720         h.fade_rate = 1 / min(self.respawntime, 10);
721         h.fade_time = time;
722         h.think = spiderbot_headfade;
723         h.nextthink = time;
724
725         setorigin(g1, gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_hardpoint01")));
726         g1.movetype = MOVETYPE_TOSS;
727         g1.solid = SOLID_CORPSE;
728         g1.velocity = v_forward * 700 + (randomvec() * 32);
729         g1.avelocity = randomvec() * 180;
730
731         setorigin(g2, gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_hardpoint02")));
732         g2.movetype = MOVETYPE_TOSS;
733         g2.solid = SOLID_CORPSE;
734         g2.velocity = v_forward * 700 + (randomvec() * 32);
735         g2.avelocity = randomvec() * 180;
736
737         h.colormod = b.colormod = g1.colormod = g2.colormod = '-2 -2 -2';
738
739         SUB_SetFade(b,  time + 5, min(self.respawntime, 1));
740         //SUB_SetFade(h,  time, min(self.respawntime, 10));
741         SUB_SetFade(g1, time, min(self.respawntime, 10));
742         SUB_SetFade(g2, time, min(self.respawntime, 10));
743
744         RadiusDamage (self, self.enemy, 250, 15, 250, world, world, 250, DEATH_VH_SPID_DEATH, world);
745
746         self.alpha = self.tur_head.alpha = self.gun1.alpha = self.gun2.alpha = -1;
747         self.movetype = MOVETYPE_NONE;
748         self.deadflag = DEAD_DEAD;
749         self.solid = SOLID_NOT;
750         self.tur_head.effects &= ~EF_FLAME;
751         self.vehicle_hudmodel.viewmodelforclient = self;
752 }
753
754 bool spiderbot_impulse(int _imp)
755 {
756         switch(_imp)
757         {
758                 case 1:
759                 case 230:
760                         self.vehicle.vehicle_weapon2mode = SBRM_VOLLY;
761                         CSQCVehicleSetup(self, 0);
762                         return true;
763                 case 2:
764                 case 231:
765                         self.vehicle.vehicle_weapon2mode = SBRM_GUIDE;
766                         CSQCVehicleSetup(self, 0);
767                         return true;
768                 case 3:
769                 case 232:
770                 case 251:
771                         self.vehicle.vehicle_weapon2mode = SBRM_ARTILLERY;
772                         CSQCVehicleSetup(self, 0);
773                         return true;
774
775                 case 10:
776                 case 15:
777                 case 18:
778                         self.vehicle.vehicle_weapon2mode += 1;
779                         if(self.vehicle.vehicle_weapon2mode > SBRM_LAST)
780                                 self.vehicle.vehicle_weapon2mode = SBRM_FIRST;
781
782                         //centerprint(self, strcat("Rocket mode is ", ftos(self.vehicle.vehicle_weapon2mode)));
783                         CSQCVehicleSetup(self, 0);
784                         return true;
785                 case 11:
786                 case 12:
787                 case 16:
788                 case 19:
789                         self.vehicle.vehicle_weapon2mode -= 1;
790                         if(self.vehicle.vehicle_weapon2mode < SBRM_FIRST)
791                                 self.vehicle.vehicle_weapon2mode = SBRM_LAST;
792
793                         //centerprint(self, strcat("Rocket mode is ", ftos(self.vehicle.vehicle_weapon2mode)));
794                         CSQCVehicleSetup(self, 0);
795                         return true;
796
797                 /*
798                 case 17: // toss gun, could be used to exit?
799                         break;
800                 case 20: // Manual minigun reload?
801                         break;
802                 */
803         }
804         return false;
805 }
806
807 void spawnfunc_vehicle_spiderbot()
808 {
809         if(!autocvar_g_vehicle_spiderbot) { remove(self); return; }
810         if(!vehicle_initialize(VEH_SPIDERBOT, false)) { remove(self); return; }
811 }
812
813 float v_spiderbot(float req)
814 {
815         switch(req)
816         {
817                 case VR_IMPACT:
818                 {
819                         if(autocvar_g_vehicle_spiderbot_bouncepain)
820                                 vehicles_impact(autocvar_g_vehicle_spiderbot_bouncepain_x, autocvar_g_vehicle_spiderbot_bouncepain_y, autocvar_g_vehicle_spiderbot_bouncepain_z);
821                 
822                         return true;
823                 }
824                 case VR_ENTER:
825                 {
826                         self.vehicle_weapon2mode = SBRM_GUIDE;
827                         self.movetype = MOVETYPE_WALK;
828                         CSQCVehicleSetup(self.owner, 0);
829                         self.owner.vehicle_health = (self.vehicle_health / autocvar_g_vehicle_spiderbot_health) * 100;
830                         self.owner.vehicle_shield = (self.vehicle_shield / autocvar_g_vehicle_spiderbot_shield) * 100;
831
832                         if(self.owner.flagcarried)
833                         {
834                                 setattachment(self.owner.flagcarried, self.tur_head, "");
835                                 setorigin(self.owner.flagcarried, '-20 0 120');
836                         }
837                 
838                         return true;
839                 }
840                 case VR_THINK:
841                 {
842                         if(self.flags & FL_ONGROUND)
843                                 movelib_beak_simple(autocvar_g_vehicle_spiderbot_speed_stop);
844                         
845                         return true;
846                 }
847                 case VR_DEATH:
848                 {
849                         self.health                             = 0;
850                         self.event_damage               = func_null;
851                         self.takedamage                 = DAMAGE_NO;
852                         self.touch                              = func_null;
853                         self.cnt                                = 3.4 + time + random() * 2;
854                         self.think                              = spiderbot_blowup;
855                         self.nextthink                  = time;
856                         self.deadflag                   = DEAD_DYING;
857                         self.frame                              = 5;
858                         self.tur_head.effects  |= EF_FLAME;
859                         self.colormod                   = self.tur_head.colormod = '-1 -1 -1';
860                         self.frame                              = 10;
861                         self.movetype                   = MOVETYPE_TOSS;
862                         
863                         CSQCModel_UnlinkEntity(); // networking the death scene would be a nightmare
864
865                         return true;
866                 }
867                 case VR_SPAWN:
868                 {
869                         if(!self.gun1)
870                         {
871                                 self.vehicles_impulse = spiderbot_impulse;
872                                 self.gun1 = spawn();
873                                 self.gun2 = spawn();
874                                 setmodel(self.gun1, "models/vehicles/spiderbot_barrels.dpm");
875                                 setmodel(self.gun2, "models/vehicles/spiderbot_barrels.dpm");
876                                 setattachment(self.gun1, self.tur_head, "tag_hardpoint01");
877                                 setattachment(self.gun2, self.tur_head, "tag_hardpoint02");
878                                 self.gravity = 2;
879                                 self.mass = 5000;
880                         }
881
882                         self.frame = 5;
883                         self.tur_head.frame = 1;
884                         self.movetype = MOVETYPE_WALK;
885                         self.solid = SOLID_SLIDEBOX;
886                         self.alpha = self.tur_head.alpha = self.gun1.alpha = self.gun2.alpha = 1;
887                         self.tur_head.angles = '0 0 0';
888                         self.vehicle_exit = spiderbot_exit;
889
890                         setorigin(self, self.pos1 + '0 0 128');
891                         self.angles = self.pos2;
892                         self.damageforcescale = 0.03;
893                         self.vehicle_health = autocvar_g_vehicle_spiderbot_health;
894                         self.vehicle_shield = autocvar_g_vehicle_spiderbot_shield;
895                         
896                         self.PlayerPhysplug = spiderbot_frame;
897
898                         return true;
899                 }
900                 case VR_SETUP:
901                 {
902                         if(autocvar_g_vehicle_spiderbot_shield)
903                                 self.vehicle_flags |= VHF_HASSHIELD;
904
905                         if(autocvar_g_vehicle_spiderbot_shield_regen)
906                                 self.vehicle_flags |= VHF_SHIELDREGEN;
907
908                         if(autocvar_g_vehicle_spiderbot_health_regen)
909                                 self.vehicle_flags |= VHF_HEALTHREGEN;
910
911                         self.respawntime = autocvar_g_vehicle_spiderbot_respawntime;
912                         self.vehicle_health = autocvar_g_vehicle_spiderbot_health;
913                         self.vehicle_shield = autocvar_g_vehicle_spiderbot_shield;
914                         self.max_health = self.vehicle_health;
915                         self.pushable = true; // spiderbot can use jumppads
916
917                         return true;
918                 }
919                 case VR_PRECACHE:
920                 {
921                         precache_model ("models/vhshield.md3");
922                         precache_model ("models/vehicles/spiderbot.dpm");
923                         precache_model ("models/vehicles/spiderbot_top.dpm");
924                         precache_model ("models/vehicles/spiderbot_barrels.dpm");
925                         precache_model ("models/vehicles/spiderbot_cockpit.dpm");
926                         precache_model ( "models/uziflash.md3");
927
928                         precache_sound ("weapons/uzi_fire.wav" );
929                         precache_sound ("weapons/rocket_impact.wav");
930
931                         precache_sound ("vehicles/spiderbot_die.wav");
932                         precache_sound ("vehicles/spiderbot_idle.wav");
933                         precache_sound ("vehicles/spiderbot_jump.wav");
934                         precache_sound ("vehicles/spiderbot_strafe.wav");
935                         precache_sound ("vehicles/spiderbot_walk.wav");
936                         precache_sound ("vehicles/spiderbot_land.wav");
937                         return true;
938                 }
939         }
940
941         return true;
942 }
943
944 #endif // SVQC
945 #ifdef CSQC
946 float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6;
947 float autocvar_cl_vehicle_spiderbot_cross_size = 1;
948
949 float v_spiderbot(float req)
950 {
951         switch(req)
952         {
953                 case VR_HUD:
954                 {
955                         string crosshair;
956
957                         switch(weapon2mode)
958                         {
959                                 case SBRM_VOLLY:     crosshair = vCROSS_BURST; break;
960                                 case SBRM_GUIDE:     crosshair = vCROSS_GUIDE; break;
961                                 case SBRM_ARTILLERY: crosshair = vCROSS_RAIN;  break;
962                                 default:             crosshair = vCROSS_BURST;
963                         }
964
965                         Vehicles_drawHUD("vehicle_spider", "vehicle_spider_weapon1", "vehicle_spider_weapon2",
966                                                          "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
967                                                          "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color,
968                                                          crosshair);
969                         return true;
970                 }
971                 case VR_SETUP:
972                 {
973                         AuxiliaryXhair[0].axh_image = vCROSS_HINT; // Minigun1
974                         AuxiliaryXhair[1].axh_image = vCROSS_HINT; // Minigun2
975                 
976                         return true;
977                 }
978                 case VR_PRECACHE:
979                 {
980                         return true;
981                 }
982         }
983
984         return true;
985 }
986
987 #endif // CSQC
988 #endif // REGISTER_VEHICLE