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