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