]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/vehicles/vehicles.qc
save state before removing stale code
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / vehicles / vehicles.qc
1 void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
2 void vehicles_return();
3 void vehicles_clearrturn();
4
5 #define MAX_AXH 4
6 .entity AuxiliaryXhair[MAX_AXH];
7
8 float SendAuxiliaryXhair(entity to, float sf)
9 {
10
11         WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
12
13         WriteByte(MSG_ENTITY, self.cnt);
14
15         WriteCoord(MSG_ENTITY, self.origin_x);
16         WriteCoord(MSG_ENTITY, self.origin_y);
17         WriteCoord(MSG_ENTITY, self.origin_z);
18
19     WriteByte(MSG_ENTITY, rint(self.colormod_x * 255));
20     WriteByte(MSG_ENTITY, rint(self.colormod_y * 255));
21     WriteByte(MSG_ENTITY, rint(self.colormod_z * 255));
22
23     return TRUE;
24 }
25
26 void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id)
27 {
28     entity axh;
29
30     axh_id = bound(0, axh_id, MAX_AXH);
31     axh = own.AuxiliaryXhair[axh_id];
32
33     if(axh == world || wasfreed(axh))  // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
34     {
35         axh                     = spawn();
36         axh.cnt                 = axh_id;
37         axh.drawonlytoclient    = own;
38         axh.owner               = own;
39         Net_LinkEntity(axh, FALSE, 0, SendAuxiliaryXhair);
40     }
41
42     setorigin(axh, loc);
43     axh.colormod            = clr;
44     axh.SendFlags           = 0x01;
45     own.AuxiliaryXhair[axh_id] = axh;
46 }
47
48 /*
49 // SVC_TEMPENTITY based, horrible with even 50 ping. hm.
50 void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id)
51 {
52         msg_entity = own;
53
54         WriteByte(MSG_ONE, SVC_TEMPENTITY);
55         WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR);
56
57         WriteByte(MSG_ONE, axh_id);
58
59         WriteCoord(MSG_ONE, loc_x);
60         WriteCoord(MSG_ONE, loc_y);
61         WriteCoord(MSG_ONE, loc_z);
62
63     WriteByte(MSG_ONE, rint(clr_x * 255));
64     WriteByte(MSG_ONE, rint(clr_y * 255));
65     WriteByte(MSG_ONE, rint(clr_z * 255));
66
67 }
68 */
69
70 void CSQCVehicleSetup(entity own, float vehicle_id)
71 {
72         msg_entity = own;
73
74         WriteByte(MSG_ONE, SVC_TEMPENTITY);
75         WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP);
76         WriteByte(MSG_ONE, vehicle_id);
77 }
78
79 .entity lock_target;
80 .float  lock_strength;
81 .float  lock_time;
82 void vehicles_locktarget(float deltatime)
83 {
84     // no target hit by trace
85     if(trace_ent == world)
86     {
87         self.lock_strength = max(self.lock_strength - deltatime, 0);
88         if(self.lock_strength == 0)
89             self.lock_target = world;
90
91         return;
92     }
93
94     // Current have no target
95     if(self.lock_target == world)
96     {
97         // aquire
98         if(trace_ent != world)
99         {
100             self.lock_target = trace_ent;
101             self.lock_strength = deltatime;
102         }
103         return;
104     }
105
106     // Have a locking target
107     // Trace hit current target
108     if(trace_ent == self.lock_target)
109     {
110         self.lock_strength = min(self.lock_strength + deltatime, 1);
111     }
112     else
113     {
114         self.lock_strength = max(self.lock_strength - deltatime, 0);
115         if(self.lock_strength == 0)
116             self.lock_target = world;
117     }
118 }
119
120
121 void vehicles_locktarget2(float incr, float decr, float _lock_time)
122 {
123     if(self.lock_time > time)
124         return;
125
126
127
128     if not (trace_ent.vehicle_flags & VHF_ISVEHICLE || trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
129         self.lock_strength = min(self.lock_strength - decr, 1);
130     else if(trace_ent.deadflag != DEAD_NO)
131         self.lock_strength = min(self.lock_strength - decr, 1);
132
133     if(self.lock_target == world && trace_ent != world)
134         self.lock_target = trace_ent;
135
136     // Have a locking target
137     // Trace hit current target
138     if(trace_ent == self.lock_target && trace_ent != world)
139     {
140         self.lock_strength = min(self.lock_strength + incr, 1);
141         if(self.lock_strength == 1)
142             self.lock_time = time + _lock_time;
143     }
144     else
145     {
146         self.lock_strength = max(self.lock_strength - decr, 0);
147
148         if(self.lock_strength == 0)
149             self.lock_target = world;
150     }
151 }
152
153
154 #define VEHICLE_UPDATE_PLAYER(fld,vhname) \
155 self.owner.vehicle_##fld = self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld
156
157 #define vehicles_sweap_collision(orig,vel,dt,acm,mult) \
158 traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \
159 if(trace_fraction != 1) \
160     acm += normalize(self.origin - trace_endpos) * (vlen(vel) * mult)
161
162 float  force_fromtag_power;
163 float  force_fromtag_normpower;
164 vector force_fromtag_origin;
165 vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power)
166 {
167     force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
168     v_forward  = normalize(v_forward) * -1;
169     traceline(force_fromtag_origin, force_fromtag_origin - (v_forward  * spring_length), MOVE_NORMAL, self);
170
171     force_fromtag_power = (1 - trace_fraction) * max_power;
172     force_fromtag_normpower = force_fromtag_power / max_power;
173
174     return v_forward  * force_fromtag_power;
175 }
176
177 vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power)
178 {
179
180     force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
181     v_forward  = normalize(v_forward) * -1;
182     traceline(force_fromtag_origin, force_fromtag_origin - (v_forward  * spring_length), MOVE_NORMAL, self);
183
184     if(trace_fraction == 1.0)
185     {
186         force_fromtag_normpower = -0.25;
187         return '0 0 -200';
188     }
189
190     force_fromtag_power = ((1 - trace_fraction) - trace_fraction) * max_power;
191     force_fromtag_normpower = force_fromtag_power / max_power;
192
193     return v_forward  * force_fromtag_power;
194 }
195
196
197 void vehicles_touch()
198 {
199     if(other.classname != "player")
200         return;
201
202     if(other.deadflag != DEAD_NO)
203         return;
204
205     if(other.vehicle != world)
206         return;
207
208     // Remove this when bots know how to use vehicles.
209     if (clienttype(other) != CLIENTTYPE_REAL)
210         return;
211
212     self.vehicle_enter();
213 }
214
215 void vehicles_enter()
216 {
217    // Remove this when bots know how to use vehicles
218     if (clienttype(other) != CLIENTTYPE_REAL)
219         return;
220
221     self.colormod = self.tur_head.colormod = '0 0 0';
222
223     if(teams_matter)
224     if(self.team)
225     if(self.team != other.team)
226         return;
227
228     self.owner          = other;
229     self.switchweapon   = other.switchweapon;
230
231     self.vehicle_hudmodel.viewmodelforclient = self.owner;
232     self.event_damage         = vehicles_damage;
233     self.nextthink            = 0;
234     self.owner.angles         = self.angles;
235     self.owner.takedamage     = DAMAGE_NO;
236     self.owner.solid          = SOLID_NOT;
237     self.owner.movetype       = MOVETYPE_NOCLIP;
238     self.owner.alpha          = -1;
239     self.owner.vehicle        = self;
240     self.owner.event_damage   = SUB_Null;
241     self.owner.view_ofs       = '0 0 0';
242     self.colormap             = self.owner.colormap;
243     if(self.tur_head)
244         self.tur_head.colormap    = self.owner.colormap;
245
246     self.owner.hud            = self.hud;
247     self.owner.PlayerPhysplug = self.PlayerPhysplug;
248
249     self.owner.vehicle_ammo1    = self.vehicle_ammo1;
250     self.owner.vehicle_ammo2    = self.vehicle_ammo2;
251     self.owner.vehicle_reload1  = self.vehicle_reload1;
252     self.owner.vehicle_reload2  = self.vehicle_reload2;
253
254     other.flags &~= FL_ONGROUND;
255     self.flags  &~= FL_ONGROUND;
256
257     self.team                 = self.owner.team;
258     self.flags               -= FL_NOTARGET;
259
260     msg_entity = other;
261     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
262     WriteEntity(MSG_ONE, self.vehicle_viewport);
263
264     WriteByte (MSG_ONE, SVC_SETVIEWANGLES);  // 10 = SVC_SETVIEWANGLES
265     if(self.tur_head)
266     {
267         WriteAngle(MSG_ONE, self.tur_head.angles_x + self.angles_x);    // tilt
268         WriteAngle(MSG_ONE, self.tur_head.angles_y + self.angles_y);    // yaw
269         WriteAngle(MSG_ONE, 0);    // roll
270     }
271     else
272     {
273         WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES
274         WriteAngle(MSG_ONE,  self.angles_x * -1);    // tilt
275         WriteAngle(MSG_ONE,  self.angles_y);    // yaw
276         WriteAngle(MSG_ONE,  0);                // roll
277     }
278
279     vehicles_clearrturn();
280
281     CSQCVehicleSetup(self.owner, self.hud);
282
283     if(self.vehicle_enter)
284         self.vehicle_enter();
285 }
286
287 void vehicles_exit(float eject)
288 {
289         self.colormap   = 1024;
290         self.tur_head.colormap   = 1024;
291
292     if (teams_matter)
293     {
294         if (self.team == COLOR_TEAM1)
295             self.colormod = '1.4 0.8 0.8';
296
297         if (self.team == COLOR_TEAM2)
298             self.colormod = '0.8 0.8 1.4';
299
300         self.tur_head.colormod = self.colormod;
301     }
302
303
304         self.flags |= FL_NOTARGET;
305
306     if (self.owner)
307     {
308         msg_entity = self.owner;
309         WriteByte (MSG_ONE, SVC_SETVIEWPORT);
310         WriteEntity( MSG_ONE, self.owner);
311
312         WriteByte (MSG_ONE, SVC_SETVIEWANGLES);    // 10 = SVC_SETVIEWANGLES
313         WriteAngle(MSG_ONE,  0);                   // tilt
314         WriteAngle(MSG_ONE,  self.angles_y);        // yaw
315         WriteAngle(MSG_ONE,  0);                   // roll
316
317         setsize(self.owner,PL_MIN,PL_MAX);
318
319         self.owner.takedamage     = DAMAGE_AIM;
320         self.owner.solid          = SOLID_SLIDEBOX;
321         self.owner.movetype       = MOVETYPE_WALK;
322         self.owner.effects        &~= EF_NODRAW;
323         self.owner.alpha          = 1;
324         self.owner.PlayerPhysplug = SUB_Null;
325         self.owner.vehicle        = world;
326         self.owner.view_ofs       = PL_VIEW_OFS;
327         self.owner.event_damage   = PlayerDamage;
328         self.owner.hud            = HUD_NORMAL;
329         self.owner.switchweapon   = self.switchweapon;
330     }
331
332     self.vehicle_hudmodel.viewmodelforclient = self;
333         self.tur_head.nodrawtoclient             = self;
334
335     if(self.vehicle_exit)
336         self.vehicle_exit(eject);
337
338     self.owner = world;
339 }
340
341
342 void vehicles_regen(.float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time)
343 {
344     if(self.regen_field < field_max)
345     if(self.timer + rpause < time)
346     {
347         self.regen_field = min(self.regen_field + regen * delta_time, field_max);
348
349         if(self.owner)
350             self.owner.regen_field = self.regen_field / field_max;
351     }
352 }
353
354 void shieldhit_think()
355 {
356     self.alpha -= 0.1;
357     if (self.alpha <= 0)
358     {
359         setmodel(self, "");
360         self.alpha = -1;
361     }
362     else
363     {
364         self.nextthink = time + 0.1;
365     }
366 }
367
368 void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
369 {
370     float ddmg_take;
371
372     self.dmg_time = time;
373
374     if((self.vehicle_flags & VHF_HASSHIELD) && (self.vehicle_shield > 0))
375     {
376         if (wasfreed(self.tur_head.enemy) || self.tur_head.enemy == world)
377         {
378             self.tur_head.enemy = spawn();
379             self.tur_head.enemy.effects = EF_LOWPRECISION;
380         }
381
382         setmodel(self.tur_head.enemy, "models/vhshield.md3");
383         setattachment(self.tur_head.enemy, self, "");
384
385         self.tur_head.enemy.colormod    = '1 1 1';
386         self.tur_head.enemy.alpha       = 0.45;
387         self.tur_head.enemy.scale       = (256 / vlen(self.maxs - self.mins));
388         self.tur_head.enemy.angles      = vectoangles(normalize(hitloc - self.origin)) - self.angles;
389         self.tur_head.enemy.think       = shieldhit_think;
390         self.tur_head.enemy.nextthink   = time;
391
392         self.vehicle_shield -= damage;
393         if(self.vehicle_shield < 0)
394         {
395             self.tur_head.enemy.colormod = '10 0 -1';
396             ddmg_take = fabs(self.vehicle_shield);
397             self.vehicle_shield         = 0;
398             self.tur_head.enemy.alpha   = 0.75;
399             self.vehicle_health         -= ddmg_take;
400         }
401     }
402     else
403         self.vehicle_health -= damage;
404
405     if(self.vehicle_health <= 0)
406     {
407         if(self.owner)
408             if(self.vehicle_flags & VHF_DEATHEJECT)
409                 vehicles_exit(VHEF_EJECT);
410             else
411                 vehicles_exit(VHEF_RELESE);
412
413         self.vehicle_die();
414     }
415 }
416
417 void vehicles_return()
418 {
419     pointparticles(particleeffectnum("teleport"), self.enemy.origin + '0 0 64', '0 0 0', 1);
420     self.enemy.think = self.use;
421     self.enemy.nextthink = time;
422     remove(self);
423 }
424
425 void vehicles_clearrturn()
426 {
427     entity ret;
428     // Remove "return helper", if any.
429     ret = findchain(classname, "vehicle_return");
430     while(ret)
431     {
432         if(ret.enemy == self)
433         {
434             ret.think = SUB_Remove;
435             ret.nextthink = time + 0.1;
436             return;
437         }
438         ret = ret.chain;
439     }
440 }
441
442 void vehicles_setreturn(float retime, void() respawn_proc)
443 {
444     vehicles_clearrturn();
445
446     if (self.deadflag == DEAD_NO)
447     {
448         entity ret;
449
450         ret = spawn();
451         ret.classname = "vehicle_return";
452         ret.enemy = self;
453         ret.think = vehicles_return;
454         ret.nextthink = time + retime;
455         ret.use = respawn_proc;
456     }
457 }
458
459 float vehicles_customizeentityforclient()
460 {
461     if(self.deadflag == DEAD_DEAD)
462         return FALSE;
463
464     return TRUE;
465 }
466
467 void vehicles_configcheck(string  configname, float   check_cvar)
468 {
469     if(check_cvar == 0)
470         localcmd(strcat("exec ", configname, "\n"));
471 }
472
473 void vehicles_common_spawn()
474 {
475     entity e;
476     float _effects, _colormap;
477     vector _glowmod, _colormod;
478
479     if(autocvar_g_nodepthtestplayers)
480         _effects = EF_NODEPTHTEST;
481
482     if(autocvar_g_fullbrightplayers)
483         _colormap |= EF_FULLBRIGHT;
484
485     if(self.team == COLOR_TEAM1)
486         _colormap = 1;
487     else if (self.team == COLOR_TEAM2)
488         _colormap = 2;
489
490     _glowmod = '0 0 0';
491     _colormod = '0 0 0';
492
493     e = findchainentity(tag_entity, self);
494     while(e)
495     {
496         e.colormap = _colormap;
497         e.effects = _effects;
498         e.colormod = _colormod;
499         e.colormap = _colormap;
500         e = e.chain;
501     }
502
503     self.effects  = _effects;
504     self.colormap = _colormap;
505     self.colormod = _colormod;
506     self.colormap = _colormap;
507 }
508
509 float vehicle_initialize(string  net_name,
510                          string  bodymodel,
511                          string  topmodel,
512                          string  hudmodel,
513                          string  toptag,
514                          string  hudtag,
515                          string  viewtag,
516                          float   vhud,
517                          vector min_s,
518                          vector max_s,
519                          float  nodrop,
520                          void()  spawnproc,
521                          float() physproc,
522                          void()  enterproc,
523                          void(float extflag) exitfunc,
524                          void() dieproc,
525                          void() thinkproc )
526 {
527     addstat(STAT_HUD, AS_INT,  hud);
528         addstat(STAT_VEHICLESTAT_HEALTH,  AS_FLOAT, vehicle_health);
529         addstat(STAT_VEHICLESTAT_SHIELD,  AS_FLOAT, vehicle_shield);
530         addstat(STAT_VEHICLESTAT_ENERGY,  AS_FLOAT, vehicle_energy);
531
532         addstat(STAT_VEHICLESTAT_AMMO1,   AS_INT,   vehicle_ammo1);
533         addstat(STAT_VEHICLESTAT_RELOAD1, AS_FLOAT, vehicle_reload1);
534
535         addstat(STAT_VEHICLESTAT_AMMO2,   AS_INT,   vehicle_ammo2);
536         addstat(STAT_VEHICLESTAT_RELOAD2, AS_FLOAT, vehicle_reload2);
537
538
539     if(bodymodel == "")
540         error("vehicles: missing bodymodel!");
541
542     if(hudmodel == "")
543         error("vehicles: missing hudmodel!");
544
545     if(net_name == "")
546         self.netname = self.classname;
547     else
548         self.netname = net_name;
549
550     if(self.team && !teams_matter)
551         self.team = 0;
552
553     self.vehicle_flags |= VHF_ISVEHICLE;
554
555     setmodel(self, bodymodel);
556
557     self.vehicle_viewport   = spawn();
558     self.vehicle_hudmodel   = spawn();
559     self.tur_head           = spawn();
560     self.tur_head.owner     = self;
561     self.takedamage         = DAMAGE_AIM;
562     self.bot_attack         = TRUE;
563     self.iscreature         = TRUE;
564     self.hud                = vhud;
565
566     self.customizeentityforclient = vehicles_customizeentityforclient;
567     self.vehicle_die        = dieproc;
568     self.vehicle_exit       = exitfunc;
569     self.vehicle_enter      = enterproc;
570     self.PlayerPhysplug     = physproc;
571     self.event_damage       = vehicles_damage;
572     self.touch              = vehicles_touch;
573     self.think              = spawnproc;
574     self.nextthink          = time;
575
576     if(autocvar_g_nodepthtestplayers)
577         self.effects = self.effects | EF_NODEPTHTEST;
578
579     if(autocvar_g_fullbrightplayers)
580         self.effects = self.effects | EF_FULLBRIGHT;
581
582     setmodel(self.vehicle_hudmodel, hudmodel);
583     setmodel(self.vehicle_viewport, "null");
584
585     if(topmodel != "")
586     {
587         setmodel(self.tur_head, topmodel);
588         setattachment(self.tur_head, self, toptag);
589         setattachment(self.vehicle_hudmodel, self.tur_head, hudtag);
590         setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
591     }
592     else
593     {
594         setattachment(self.tur_head, self, "");
595         setattachment(self.vehicle_hudmodel, self, hudtag);
596         setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
597     }
598
599     setsize(self, min_s, max_s);
600     if not (nodrop)
601     {
602         setorigin(self, self.origin);
603         tracebox(self.origin + '0 0 100', min_s, max_s, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
604         setorigin(self, trace_endpos);
605     }
606
607     self.pos1 = self.origin;
608     self.pos2 = self.angles;
609
610     return TRUE;
611 }
612
613 void bugmenot()
614 {
615     self.vehicle_exit       = self.vehicle_exit;
616     self.vehicle_enter      = self.vehicle_exit;
617     self.vehicle_die        = self.vehicle_exit;
618     self.vehicle_spawn      = self.vehicle_exit;
619     //self.vehicle_message    = self.vehicle_exit;
620 }