]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/gamec/cl_client.c
use all 4 hitground sounds, not just the first 3
[divverent/nexuiz.git] / qcsrc / gamec / cl_client.c
1
2 void info_player_start (void)
3 {
4         self.classname = "info_player_deathmatch";
5 }
6
7 void info_player_deathmatch (void)
8 {
9 }
10
11 /*
12 =============
13 SelectSpawnPoint
14
15 Finds a point to respawn
16 =============
17 */
18 entity SelectSpawnPoint (void)
19 {
20         local entity spot, thing;
21         local float pcount;
22
23         spot = find (world, classname, "testplayerstart");
24         if (spot)
25                 return spot;
26
27         spot = lastspawn;
28         while (1)
29         {
30                 spot = find(spot, classname, "info_player_deathmatch");
31                 if (spot != world)
32                 {
33                         if (spot == lastspawn)
34                                 return lastspawn;
35                         pcount = 0;
36                         thing = findradius(spot.origin, 70);
37                         while(thing)
38                         {
39                                 if (thing.classname == "player")
40                                         pcount = pcount + 1;
41                                 thing = thing.chain;
42                         }
43                         if (pcount == 0)
44                         {
45                                 lastspawn = spot;
46                                 return spot;
47                         }
48                 }
49         }
50
51         spot = find (world, classname, "info_player_start");
52         if (!spot)
53                 error ("PutClientInServer: no info_player_start on level");
54
55         return spot;
56 }
57
58
59 /*
60 =============
61 PutClientInServer
62
63 Called when a client spawns in the server
64 =============
65 */
66 void PutClientInServer (void)
67 {
68         entity  spot;
69         float mdlrandom;
70
71         spot = SelectSpawnPoint ();
72
73         self.classname = "player";
74         self.movetype = MOVETYPE_WALK;
75         self.solid = SOLID_SLIDEBOX;
76         self.flags = FL_CLIENT;
77         self.takedamage = DAMAGE_YES;
78         self.effects = 0;
79         self.health = 150;
80         self.damageforcescale = 2;
81         self.death_time = 0;
82         self.dead_time = 0;
83         self.dead_frame = 0;
84         self.die_frame = 0;
85         self.alpha = 0;
86         self.scale = 0;
87         self.fade_time = 0;
88         self.pain_frame = 0;
89         self.pain_finished = 0;
90         self.strength_finished = 0;
91         self.invincible_finished = 0;
92         self.speed_finished = 0;
93         self.slowmo_finished = 0;
94         // players have no think function
95         self.think = nullfunction;
96         self.nextthink = 0;
97
98         self.deadflag = DEAD_NO;
99
100         self.view_ofs = PL_VIEW_OFS;
101         self.angles = spot.angles;
102         self.velocity = '0 0 0';
103         self.avelocity = '0 0 0';
104
105         self.viewzoom = 0.6;
106
107         setmodel (self, self.playermodel);
108         setsize (self, PL_MIN, PL_MAX);
109         setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24));
110         // don't reset back to last position, even if new position is stuck in solid
111         self.oldorigin = self.origin;
112
113 //      self.items = IT_LASER | IT_UZI| IT_SHOTGUN | IT_GRENADE_LAUNCHER | IT_ELECTRO | IT_CRYLINK | IT_NEX | IT_HAGAR | IT_ROCKET_LAUNCHER;
114 //      self.weapon = IT_UZI;
115
116         if (game & GAME_INSTAGIB)
117         {
118                 self.items = IT_NEX;
119                 self.switchweapon = WEP_NEX;
120                 self.ammo_shells = 0;
121                 self.ammo_nails = 0;
122                 self.ammo_rockets = 0;
123                 self.ammo_cells = 999;
124         }
125         else if (game & GAME_ROCKET_ARENA)
126         {
127                 self.items = IT_ROCKET_LAUNCHER;
128                 self.switchweapon = WEP_ROCKET_LAUNCHER;
129                 self.ammo_shells = 0;
130                 self.ammo_nails = 0;
131                 self.ammo_rockets = 999;
132                 self.ammo_cells = 0;
133         }
134         else
135         {
136                 self.items = IT_LASER | IT_SHOTGUN;
137                 self.switchweapon = WEP_SHOTGUN;
138                 self.ammo_shells = 25;
139                 self.ammo_nails = 0;
140                 self.ammo_rockets = 0;
141                 self.ammo_cells = 0;
142         }
143
144         if (game & GAME_FULLBRIGHT_PLAYERS)
145                 self.effects = EF_FULLBRIGHT;
146
147         self.event_damage = PlayerDamage;
148
149         self.statdraintime = time + 5;
150         self.button0 = self.button1 = self.button2 = self.button3 = 0;
151
152         /*
153         W_UpdateWeapon();
154         W_UpdateAmmo();
155         */
156         CL_SpawnWeaponentity();
157
158         //stuffcmd(self, "chase_active 0");
159 }
160
161 /*
162 =============
163 SetNewParms
164 =============
165 */
166 void SetNewParms (void)
167 {
168
169 }
170
171 /*
172 =============
173 SetChangeParms
174 =============
175 */
176 void SetChangeParms (void)
177 {
178
179 }
180
181 /*
182 =============
183 ClientKill
184
185 Called when a client types 'kill' in the console
186 =============
187 */
188 void ClientKill (void)
189 {
190
191 }
192
193 /*
194 =============
195 ClientConnect
196
197 Called when a client connects to the server
198 =============
199 */
200 void ClientConnect (void)
201 {
202         //ClientInRankings();
203         bprint (self.netname);
204         bprint (" connected\n");
205 }
206
207 /*
208 =============
209 ClientDisconnect
210
211 Called when a client disconnects from the server
212 =============
213 */
214 void ClientDisconnect (void)
215 {
216         //ClientDisconnected();
217         bprint (self.netname);
218         bprint (" disconnected\n");
219 }
220
221 /*
222 =============
223 PlayerJump
224
225 When you press the jump key
226 =============
227 */
228 void PlayerJump (void)
229 {
230         if (self.waterlevel >= 2)
231         {
232                 if (self.watertype == CONTENT_WATER)
233                         self.velocity_z = 200;
234                 else if (self.watertype == CONTENT_SLIME)
235                         self.velocity_z = 80;
236                 else
237                         self.velocity_z = 50;
238
239                 return;
240         }
241
242
243         if (!(self.flags & FL_ONGROUND))
244                 return;
245
246         if (!(self.flags & FL_JUMPRELEASED))
247                 return;
248
249         if (self.items & IT_SPEED)
250                 self.velocity_z = self.velocity_z + POWERUP_SPEED_JUMPVELOCITY;
251         else
252                 self.velocity_z = self.velocity_z + JUMP_VELOCITY;
253
254         self.flags = self.flags - FL_ONGROUND;
255         self.flags = self.flags - FL_JUMPRELEASED;
256 }
257
258 void() WaterMove =
259 {
260         if (self.movetype == MOVETYPE_NOCLIP)
261                 return;
262         if (self.health < 0)
263                 return;
264
265         if (self.waterlevel != 3)
266         {
267                 self.air_finished = time + 12;
268                 self.dmg = 2;
269         }
270         else if (self.air_finished < time)
271         {       // drown!
272                 if (self.pain_finished < time)
273                 {
274                         Damage (self, world, world, 5, DEATH_DROWN, '0 0 0', '0 0 0');
275                         self.pain_finished = time + 0.5;
276                 }
277         }
278
279         if (!self.waterlevel)
280         {
281                 if (self.flags & FL_INWATER)
282                 {
283                         // play leave water sound
284                         sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
285                         self.flags = self.flags - FL_INWATER;
286                 }
287                 return;
288         }
289
290         if (self.watertype == CONTENT_LAVA)
291         {       // do damage
292                 if (self.dmgtime < time)
293                 {
294                         self.dmgtime = time + 0.2;
295                         Damage (self, world, world, 5, DEATH_LAVA, '0 0 0', '0 0 0');
296                 }
297         }
298         else if (self.watertype == CONTENT_SLIME)
299         {       // do damage
300                 if (self.dmgtime < time)
301                 {
302                         self.dmgtime = time + 1;
303                         Damage (self, world, world, 5, DEATH_SLIME, '0 0 0', '0 0 0');
304                 }
305         }
306
307         if ( !(self.flags & FL_INWATER) )
308         {
309
310                 //if (self.watertype == CONTENT_LAVA)
311                 //      sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
312                 //if (self.watertype == CONTENT_WATER)
313                 //      sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
314                 //if (self.watertype == CONTENT_SLIME)
315                 //      sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
316
317                 self.flags = self.flags + FL_INWATER;
318                 self.dmgtime = 0;
319         }
320 };
321
322 void() CheckWaterJump =
323 {
324         local vector start, end;
325
326 // check for a jump-out-of-water
327         makevectors (self.angles);
328         start = self.origin;
329         start_z = start_z + 8;
330         v_forward_z = 0;
331         normalize(v_forward);
332         end = start + v_forward*24;
333         traceline (start, end, TRUE, self);
334         if (trace_fraction < 1)
335         {       // solid at waist
336                 start_z = start_z + self.maxs_z - 8;
337                 end = start + v_forward*24;
338                 self.movedir = trace_plane_normal * -50;
339                 traceline (start, end, TRUE, self);
340                 if (trace_fraction == 1)
341                 {       // open at eye level
342                         self.flags = self.flags | FL_WATERJUMP;
343                         self.velocity_z = 225;
344                         self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
345                         self.teleport_time = time + 2;  // safety net
346                         return;
347                 }
348         }
349 };
350
351
352 void respawn(void)
353 {
354         CopyBody();
355         PutClientInServer();
356 }
357
358 void player_powerups (void)
359 {
360         if (self.items & IT_STRENGTH)
361         {
362                 if (time > self.strength_finished)
363                 {
364                         self.items = self.items - (self.items & IT_STRENGTH);
365                         sprint(self, "Strength has worn off\n");
366                 }
367         }
368         else
369         {
370                 if (time < self.strength_finished)
371                 {
372                         self.items = self.items | IT_STRENGTH;
373                         sprint(self, "Strength infuses your weapons with devestating power\n");
374                 }
375         }
376         if (self.items & IT_INVINCIBLE)
377         {
378                 if (time > self.invincible_finished)
379                 {
380                         self.items = self.items - (self.items & IT_INVINCIBLE);
381                         sprint(self, "Invincible has worn off\n");
382                 }
383         }
384         else
385         {
386                 if (time < self.invincible_finished)
387                 {
388                         self.items = self.items | IT_INVINCIBLE;
389                         sprint(self, "Invincible shielding surrounds you\n");
390                 }
391         }
392         if (self.items & IT_SPEED)
393         {
394                 if (time > self.speed_finished)
395                 {
396                         self.items = self.items - (self.items & IT_SPEED);
397                         sprint(self, "Speed has worn off\n");
398                 }
399         }
400         else
401         {
402                 if (time < self.speed_finished)
403                 {
404                         self.items = self.items | IT_SPEED;
405                         sprint(self, "Speed makes you run faster than ever before\n");
406                 }
407         }
408         if (self.items & IT_SLOWMO)
409         {
410                 if (time > self.slowmo_finished)
411                 {
412                         self.items = self.items - (self.items & IT_SLOWMO);
413                         sprint(self, "Slow Motion has worn off\n");
414                 }
415         }
416         else
417         {
418                 if (time < self.slowmo_finished)
419                 {
420                         self.items = self.items | IT_SLOWMO;
421                         sprint(self, "Slow Motion slows time around you\n");
422                 }
423         }
424         /*
425         self.items = self.items - (self.items & (IT_STRENGTH + IT_INVINCIBLE + IT_SLOWMO + IT_SPEED));
426         if (time < self.strength_finished)
427                 self.items = self.items | IT_STRENGTH;
428         if (time < self.invincible_finished)
429                 self.items = self.items | IT_INVINCIBLE;
430         if (time < self.slowmo_finished)
431                 self.items = self.items | IT_SLOWMO;
432         if (time < self.speed_finished)
433                 self.items = self.items | IT_SPEED;
434         */
435 }
436
437 void player_regen (void)
438 {
439         // GAME_REGENERATION does fast health regeneration up to 200. Note that your armour doesn't rot anymore either.
440         if (game & GAME_REGENERATION)
441         {
442                 self.health = self.health + (200 - self.health) * 0.2 * frametime;
443                 self.armorvalue = bound(0, self.armorvalue, 1000);
444         }
445         else
446         {
447                 self.health = bound(0, self.health + (100 - self.health) * 0.05 * frametime, 1000);
448                 if (self.armorvalue > 100)
449                         self.armorvalue = bound(100, self.armorvalue + (100 - self.armorvalue) * 0.1 * frametime, 1000);
450         }
451 }
452
453 /*
454 =============
455 PlayerPreThink
456
457 Called every frame for each client before the physics are run
458 =============
459 */
460 .float attack_finished;
461 void PlayerPreThink (void)
462 {
463         //if (BotPreFrame())
464         //      return;
465
466         if (self.deadflag != DEAD_NO)
467         {
468                 player_anim();
469                 weapon_freeze();
470                 if (self.deadflag == DEAD_DYING)
471                 {
472                         if (time > self.dead_time)
473                                 self.deadflag = DEAD_DEAD;
474                 }
475                 else if (self.deadflag == DEAD_DEAD)
476                 {
477                         if (!self.button0 && !self.button2 && !self.button3)
478                                 self.deadflag = DEAD_RESPAWNABLE;
479                 }
480                 else if (self.deadflag == DEAD_RESPAWNABLE)
481                 {
482                         if (self.button0 || self.button2 || self.button3  || self.button4)
483                                 respawn();
484                 }
485                 return;
486         }
487
488         W_WeaponFrame();
489
490         if (self.button4)
491         {
492                 if (self.viewzoom > 0.4)
493                         self.viewzoom = max (0.4, self.viewzoom - frametime * 2);
494         }
495         else if (self.viewzoom < 1.0)
496                 self.viewzoom = min (1.0, self.viewzoom + frametime);
497
498
499         if (self.button2)
500                 PlayerJump ();
501         else
502                 self.flags = self.flags | FL_JUMPRELEASED;
503
504
505         player_powerups();
506         player_regen();
507         player_anim();
508
509         self.angles_y=self.v_angle_y + 90;   // temp
510
511         WaterMove ();
512         if (self.waterlevel == 2)
513                 CheckWaterJump ();
514
515         //if (TetrisPreFrame()) return;
516 }
517
518 /*
519 =============
520 PlayerPostThink
521
522 Called every frame for each client after the physics are run
523 =============
524 */
525 void PlayerPostThink (void)
526 {
527         float soundrandom;
528         //if (BotPostFrame())
529         //      return;
530         if (self.health > 0)
531         if (self.impulse)
532                 ImpulseCommands ();
533
534         // VorteX: landing on floor, landing damage etc.
535         if (self.flags & FL_ONGROUND)
536         {
537                 if (fabs(self.jump_flag) > 100)
538                 {
539                         if (self.jump_flag < -100 && !self.watertype == CONTENT_WATER) // HitGround
540                         {
541                                 soundrandom = random() * 4;
542                                 if (soundrandom < 1)
543                                         sound (self, CHAN_BODY, "misc/hitground1.wav", 1, ATTN_NORM);
544                                 if (soundrandom < 2)
545                                         sound (self, CHAN_BODY, "misc/hitground2.wav", 1, ATTN_NORM);
546                                 if (soundrandom < 3)
547                                         sound (self, CHAN_BODY, "misc/hitground3.wav", 1, ATTN_NORM);
548                                 if (soundrandom < 4)
549                                         sound (self, CHAN_BODY, "misc/hitground4.wav", 1, ATTN_NORM);
550                                 if (self.jump_flag < -650) // landing damage
551                                 {
552                                         local float dm;
553                                         dm = bound(0, 0.1*(fabs(self.jump_flag) - 600), 5);
554                                         Damage (self, world, world, dm, DEATH_FALL, '0 0 0', '0 0 0');
555                                 }
556                                 self.jump_flag = 0;
557                         }
558                 }
559         }
560         else
561         {
562                 if (self.jump_flag != -10000) // not in falling death
563                 {
564                         self.jump_flag = self.velocity_z;
565                         // check for falling into the void
566                         if (self.jump_flag < -700)
567                         {
568                                 tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 -1'*2048, MOVE_NORMAL, self);
569                                 if (trace_fraction == 1)
570                                 {// VorteX: add player falling sound here
571                                         self.jump_flag = -10000;
572                                         self.lip = time + 1;
573                                 }
574                         }
575                 }
576                 else
577                 {
578                         if (time < self.lip)
579                         {// prevent all inventory drop
580                                 self.weapon = 0;
581                                 Damage (self, world, world, 40000, DEATH_BIGFALL, '0 0 0', '0 0 0');
582                         }
583                 }
584         }
585
586         //if (TetrisPostFrame()) return;
587 }