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