]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/vehicles/vehicles.qc
008e8a0ff99e2c02989716cb4fc88cfa64058319
[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 .entity AuxiliaryXhair;
6 float AuxiliaryXhair_customizeentityforclient()
7 {
8     if(other == self.owner)
9         return TRUE;
10
11     return FALSE;
12 }
13 float AuxiliaryXhair_SendEntity(entity to, float sf)
14 {
15         WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
16         WriteCoord(MSG_ENTITY, self.origin_x);
17         WriteCoord(MSG_ENTITY, self.origin_y);
18         WriteCoord(MSG_ENTITY, self.origin_z);
19         return TRUE;
20 }
21
22 void SpawnOrUpdateAuxiliaryXhair(entity own, vector loc)
23 {
24
25     if(own.AuxiliaryXhair == world || wasfreed(own.AuxiliaryXhair))
26     {
27         own.AuxiliaryXhair = spawn();
28         own.AuxiliaryXhair.owner = own;
29         //own.AuxiliaryXhair.customizeentityforclient = AuxiliaryXhair_customizeentityforclient;
30         own.AuxiliaryXhair.drawonlytoclient = own;
31         setorigin(own.AuxiliaryXhair, loc);
32         Net_LinkEntity(own.AuxiliaryXhair, FALSE, 0, AuxiliaryXhair_SendEntity);
33         return;
34     }
35
36     setorigin(own.AuxiliaryXhair, loc);
37         own.AuxiliaryXhair.SendFlags |= 0x01;
38 }
39
40 void Release_AuxiliaryXhair(entity from)
41 {
42     // from.AuxiliaryXhair.drawonlytoclient = from.AuxiliaryXhair;
43     if not (from.AuxiliaryXhair == world || wasfreed(from.AuxiliaryXhair))
44         remove(from.AuxiliaryXhair);
45
46     from.AuxiliaryXhair = world;
47 }
48
49 #define VEHICLE_UPDATE_PLAYER(fld,vhname) \
50 self.owner.vehicle_##fld = self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld
51
52 #define vehicles_sweap_collision(orig,vel,dt,acm,mult) \
53 traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \
54 if(trace_fraction != 1) \
55     acm += normalize(self.origin - trace_endpos) * (vlen(vel) * mult)
56
57 float  force_fromtag_power;
58 float  force_fromtag_normpower;
59 vector force_fromtag_origin;
60 vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power)
61 {
62     force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
63     v_forward  = normalize(v_forward) * -1;
64     traceline(force_fromtag_origin, force_fromtag_origin - (v_forward  * spring_length), MOVE_NORMAL, self);
65
66     force_fromtag_power = (1 - trace_fraction) * max_power;
67     force_fromtag_normpower = force_fromtag_power / max_power;
68
69     return v_forward  * force_fromtag_power;
70 }
71
72 vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power)
73 {
74
75     force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name));
76     v_forward  = normalize(v_forward) * -1;
77     traceline(force_fromtag_origin, force_fromtag_origin - (v_forward  * spring_length), MOVE_NORMAL, self);
78
79     if(trace_fraction == 1.0)
80     {
81         force_fromtag_normpower = -0.25;
82         return '0 0 -200';
83     }
84
85     force_fromtag_power = ((1 - trace_fraction) - trace_fraction) * max_power;
86     force_fromtag_normpower = force_fromtag_power / max_power;
87
88     return v_forward  * force_fromtag_power;
89 }
90
91
92 void vehicles_touch()
93 {
94     if(other.classname != "player")
95         return;
96
97     if(other.deadflag != DEAD_NO)
98         return;
99
100     if(other.vehicle != world)
101         return;
102
103     // Remove this when bots know how to use vehicles.
104     if (clienttype(other) != CLIENTTYPE_REAL)
105         return;
106
107     self.vehicle_enter();
108 }
109
110 void vehicles_enter()
111 {
112    // Remove this when bots know how to use vehicles
113     if (clienttype(other) != CLIENTTYPE_REAL)
114         return;
115
116     self.colormod = self.tur_head.colormod = '0 0 0';
117
118     if(teams_matter)
119     if(self.team)
120     if(self.team != other.team)
121         return;
122
123     self.owner          = other;
124     self.switchweapon   = other.switchweapon;
125
126     self.vehicle_hudmodel.viewmodelforclient = self.owner;
127     self.event_damage         = vehicles_damage;
128     self.nextthink            = 0;
129     self.owner.angles         = self.angles;
130     self.owner.takedamage     = DAMAGE_NO;
131     self.owner.solid          = SOLID_NOT;
132     self.owner.movetype       = MOVETYPE_NOCLIP;
133     self.owner.alpha          = -1;
134     self.owner.vehicle        = self;
135     self.owner.event_damage   = SUB_Null;
136     self.owner.view_ofs       = '0 0 0';
137     self.colormap             = self.owner.colormap;
138     if(self.tur_head)
139         self.tur_head.colormap    = self.owner.colormap;
140
141     self.owner.hud            = self.hud;
142     self.owner.PlayerPhysplug = self.PlayerPhysplug;
143
144     self.owner.vehicle_ammo1    = self.vehicle_ammo1;
145     self.owner.vehicle_ammo2    = self.vehicle_ammo2;
146     self.owner.vehicle_reload1  = self.vehicle_reload1;
147     self.owner.vehicle_reload2  = self.vehicle_reload2;
148
149     other.flags &~= FL_ONGROUND;
150     self.flags  &~= FL_ONGROUND;
151
152     self.team                 = self.owner.team;
153     self.flags               -= FL_NOTARGET;
154
155     msg_entity = other;
156     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
157     WriteEntity(MSG_ONE, self.vehicle_viewport);
158
159     WriteByte (MSG_ONE, SVC_SETVIEWANGLES);  // 10 = SVC_SETVIEWANGLES
160     if(self.tur_head)
161     {
162         WriteAngle(MSG_ONE, self.tur_head.angles_x + self.angles_x);    // tilt
163         WriteAngle(MSG_ONE, self.tur_head.angles_y + self.angles_y);    // yaw
164         WriteAngle(MSG_ONE, 0);    // roll
165     }
166     else
167     {
168         WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES
169         WriteAngle(MSG_ONE,  self.angles_x * -1);    // tilt
170         WriteAngle(MSG_ONE,  self.angles_y);    // yaw
171         WriteAngle(MSG_ONE,  0);                // roll
172     }
173
174     vehicles_clearrturn();
175
176     if(self.vehicle_enter)
177         self.vehicle_enter();
178 }
179
180 void vehicles_exit(float eject)
181 {
182         self.colormap   = 1024;
183         self.tur_head.colormap   = 1024;
184
185     if (teams_matter)
186     {
187         if (self.team == COLOR_TEAM1)
188             self.colormod = '1.4 0.8 0.8';
189
190         if (self.team == COLOR_TEAM2)
191             self.colormod = '0.8 0.8 1.4';
192
193         self.tur_head.colormod = self.colormod;
194     }
195
196
197         self.flags |= FL_NOTARGET;
198
199     if (self.owner)
200     {
201         msg_entity = self.owner;
202         WriteByte (MSG_ONE, SVC_SETVIEWPORT);
203         WriteEntity( MSG_ONE, self.owner);
204
205         WriteByte (MSG_ONE, SVC_SETVIEWANGLES);    // 10 = SVC_SETVIEWANGLES
206         WriteAngle(MSG_ONE,  0);                   // tilt
207         WriteAngle(MSG_ONE,  self.angles_y);        // yaw
208         WriteAngle(MSG_ONE,  0);                   // roll
209
210         setsize(self.owner,PL_MIN,PL_MAX);
211
212         self.owner.takedamage     = DAMAGE_AIM;
213         self.owner.solid          = SOLID_SLIDEBOX;
214         self.owner.movetype       = MOVETYPE_WALK;
215         self.owner.effects        &~= EF_NODRAW;
216         self.owner.alpha          = 1;
217         self.owner.PlayerPhysplug = SUB_Null;
218         self.owner.vehicle        = world;
219         self.owner.view_ofs       = PL_VIEW_OFS;
220         self.owner.event_damage   = PlayerDamage;
221         self.owner.hud            = HUD_NORMAL;
222         self.owner.switchweapon   = self.switchweapon;
223     }
224
225     self.vehicle_hudmodel.viewmodelforclient = self;
226         self.tur_head.nodrawtoclient             = self;
227
228     if(self.vehicle_exit)
229         self.vehicle_exit(eject);
230
231     self.owner = world;
232 }
233
234
235 void vehicles_regen(.float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time)
236 {
237     if(self.regen_field < field_max)
238     if(self.timer + rpause < time)
239     {
240         self.regen_field = min(self.regen_field + regen * delta_time, field_max);
241
242         if(self.owner)
243             self.owner.regen_field = self.regen_field / field_max;
244     }
245 }
246
247 void shieldhit_think()
248 {
249     self.alpha -= 0.1;
250     if (self.alpha <= 0)
251     {
252         setmodel(self, "");
253         self.alpha = -1;
254     }
255     else
256     {
257         self.nextthink = time + 0.1;
258     }
259 }
260
261 void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
262 {
263     float ddmg_take;
264
265     self.dmg_time = time;
266
267     if((self.vehicle_flags & VHF_HASSHIELD) && (self.vehicle_shield > 0))
268     {
269         if (wasfreed(self.tur_head.enemy) || self.tur_head.enemy == world)
270         {
271             self.tur_head.enemy = spawn();
272             self.tur_head.enemy.effects = EF_LOWPRECISION;
273         }
274
275         setmodel(self.tur_head.enemy, "models/vhshield.md3");
276         setattachment(self.tur_head.enemy, self, "");
277
278         self.tur_head.enemy.colormod    = '1 1 1';
279         self.tur_head.enemy.alpha       = 0.45;
280         self.tur_head.enemy.scale       = (256 / vlen(self.maxs - self.mins));
281         self.tur_head.enemy.angles      = vectoangles(normalize(hitloc - self.origin)) - self.angles;
282         self.tur_head.enemy.think       = shieldhit_think;
283         self.tur_head.enemy.nextthink   = time;
284
285         self.vehicle_shield -= damage;
286         if(self.vehicle_shield < 0)
287         {
288             self.tur_head.enemy.colormod = '10 0 -1';
289             ddmg_take = fabs(self.vehicle_shield);
290             self.vehicle_shield         = 0;
291             self.tur_head.enemy.alpha   = 0.75;
292             self.vehicle_health         -= ddmg_take;
293         }
294     }
295     else
296         self.vehicle_health -= damage;
297
298     if(self.vehicle_health <= 0)
299     {
300         if(self.owner)
301             if(self.vehicle_flags & VHF_DEATHEJECT)
302                 vehicles_exit(VHEF_EJECT);
303             else
304                 vehicles_exit(VHEF_RELESE);
305
306         self.vehicle_die();
307     }
308 }
309
310 void vehicles_return()
311 {
312     pointparticles(particleeffectnum("teleport"), self.enemy.origin + '0 0 64', '0 0 0', 1);
313     self.enemy.think = self.use;
314     self.enemy.nextthink = time;
315     remove(self);
316 }
317
318 void vehicles_clearrturn()
319 {
320     entity ret;
321     // Remove "return helper", if any.
322     ret = findchain(classname, "vehicle_return");
323     while(ret)
324     {
325         if(ret.enemy == self)
326         {
327             ret.think = SUB_Remove;
328             ret.nextthink = time + 0.1;
329             return;
330         }
331         ret = ret.chain;
332     }
333 }
334
335 void vehicles_setreturn(float retime, void() respawn_proc)
336 {
337     vehicles_clearrturn();
338
339     if (self.deadflag == DEAD_NO)
340     {
341         entity ret;
342
343         ret = spawn();
344         ret.classname = "vehicle_return";
345         ret.enemy = self;
346         ret.think = vehicles_return;
347         ret.nextthink = time + retime;
348         ret.use = respawn_proc;
349     }
350 }
351
352 float vehicles_customizeentityforclient()
353 {
354     if(self.deadflag == DEAD_DEAD)
355         return FALSE;
356
357     return TRUE;
358 }
359
360 void vehicles_configcheck(string  configname, float   check_cvar)
361 {
362     if(check_cvar == 0)
363         localcmd(strcat("exec ", configname, "\n"));
364 }
365
366 float vehicle_initialize(string  net_name,
367                          string  bodymodel,
368                          string  topmodel,
369                          string  hudmodel,
370                          string  toptag,
371                          string  hudtag,
372                          string  viewtag,
373                          float   vhud,
374                          vector min_s,
375                          vector max_s,
376                          float  nodrop,
377                          void()  spawnproc,
378                          float() physproc,
379                          void()  enterproc,
380                          void(float extflag) exitfunc,
381                          void() dieproc,
382                          void() thinkproc )
383 {
384     addstat(STAT_HUD, AS_INT,  hud);
385         addstat(STAT_VEHICLESTAT_HEALTH,  AS_FLOAT, vehicle_health);
386         addstat(STAT_VEHICLESTAT_SHIELD,  AS_FLOAT, vehicle_shield);
387         addstat(STAT_VEHICLESTAT_ENERGY,  AS_FLOAT, vehicle_energy);
388
389         addstat(STAT_VEHICLESTAT_AMMO1,   AS_INT,   vehicle_ammo1);
390         addstat(STAT_VEHICLESTAT_RELOAD1, AS_FLOAT, vehicle_reload1);
391
392         addstat(STAT_VEHICLESTAT_AMMO2,   AS_INT,   vehicle_ammo2);
393         addstat(STAT_VEHICLESTAT_RELOAD2, AS_FLOAT, vehicle_reload2);
394
395     if(bodymodel == "")
396         error("vehicles: missing bodymodel!");
397
398     if(hudmodel == "")
399         error("vehicles: missing hudmodel!");
400
401     if(net_name == "")
402         self.netname = self.classname;
403     else
404         self.netname = net_name;
405
406     if(self.team && !teams_matter)
407         self.team = 0;
408
409     setmodel(self, bodymodel);
410
411     self.vehicle_viewport   = spawn();
412     self.vehicle_hudmodel   = spawn();
413     self.tur_head           = spawn();
414     self.tur_head.owner     = self;
415     self.takedamage         = DAMAGE_AIM;
416     self.bot_attack         = TRUE;
417     self.iscreature         = TRUE;
418     self.hud                = vhud;
419
420     self.customizeentityforclient = vehicles_customizeentityforclient;
421     self.vehicle_die        = dieproc;
422     self.vehicle_exit       = exitfunc;
423     self.vehicle_enter      = enterproc;
424     self.PlayerPhysplug     = physproc;
425     self.event_damage       = vehicles_damage;
426     self.touch              = vehicles_touch;
427     self.think              = spawnproc;
428     self.nextthink          = time;
429
430     setmodel(self.vehicle_hudmodel, hudmodel);
431     setmodel(self.vehicle_viewport, "null");
432
433     if(topmodel != "")
434     {
435         setmodel(self.tur_head, topmodel);
436         setattachment(self.tur_head, self, toptag);
437         setattachment(self.vehicle_hudmodel, self.tur_head, hudtag);
438         setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
439     }
440     else
441     {
442         setattachment(self.tur_head, self, "");
443         setattachment(self.vehicle_hudmodel, self, hudtag);
444         setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag);
445     }
446
447     setsize(self, min_s, max_s);
448     if not (nodrop)
449     {
450         setorigin(self, self.origin);
451         tracebox(self.origin + '0 0 100', min_s, max_s, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
452         setorigin(self, trace_endpos);
453     }
454
455     self.pos1 = self.origin;
456     self.pos2 = self.angles;
457
458     return TRUE;
459 }
460
461 void bugmenot()
462 {
463     self.vehicle_exit       = self.vehicle_exit;
464     self.vehicle_enter      = self.vehicle_exit;
465     self.vehicle_die        = self.vehicle_exit;
466     self.vehicle_spawn      = self.vehicle_exit;
467     //self.vehicle_message    = self.vehicle_exit;
468 }