]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/gamec/cl_client.c
check clientversion on connect, motd prepared
[divverent/nexuiz.git] / data / 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 float spawn_goodspots, spawn_badspots;
11 entity Spawn_ClassifyPoints(entity firstspot, entity playerlist, float mindist, float goodspotnum, float badspotnum)
12 {
13         local entity spot, player;
14         local float pcount;
15         spawn_goodspots = 0;
16         spawn_badspots = 0;
17         spot = firstspot;
18         while (spot)
19         {
20                 pcount = 0;
21                 player = playerlist;
22                 while (player)
23                 {
24                         if (player != self)
25                         if (vlen(player.origin - spot.origin) < 100)
26                                 pcount = pcount + 1;
27                         player = player.chain;
28                 }
29                 if (pcount)
30                 {
31                         if (spawn_goodspots >= badspotnum)
32                                 return spot;
33                         spawn_badspots = spawn_badspots + 1;
34                 }
35                 else
36                 {
37                         if (spawn_goodspots >= goodspotnum)
38                                 return spot;
39                         spawn_goodspots = spawn_goodspots + 1;
40                 }
41                 spot = find(spot, classname, "info_player_deathmatch");
42         }
43         return firstspot;
44 }
45
46 entity Spawn_FurthestPoint(entity firstspot, entity playerlist)
47 {
48         local entity best, spot, player;
49         local float bestrating, rating;
50         best = world;
51         bestrating = -1000000;
52         spot = firstspot;
53         while (spot)
54         {
55                 rating = 1000000000;
56                 player = playerlist;
57                 while (player)
58                 {
59                         if (player != self)
60                                 rating = min(rating, vlen(player.origin - spot.origin));
61                         player = player.chain;
62                 }
63                 rating = rating + random() * 16;
64                 if (bestrating < rating)
65                 {
66                         best = spot;
67                         bestrating = rating;
68                 }
69                 spot = find(spot, classname, "info_player_deathmatch");
70         }
71         return best;
72 }
73
74 /*
75 =============
76 SelectSpawnPoint
77
78 Finds a point to respawn
79 =============
80 */
81 entity SelectSpawnPoint (float anypoint)
82 {
83         local entity spot, firstspot, playerlist;
84         string spotname;
85
86         spot = find (world, classname, "testplayerstart");
87         if (spot)
88                 return spot;
89
90         spotname = "info_player_deathmatch";
91
92         if(!anypoint && cvar("g_ctf") )
93         {
94                 if(self.team == 5)//4)
95                         spotname = "info_player_team1";
96                 if(self.team == 14)//13)
97                         spotname = "info_player_team2";
98                 if(self.team == 4)//3)
99                         spotname = "info_player_team3";
100                 if(self.team == 13)//12)
101                         spotname = "info_player_team4";
102         }
103
104         playerlist = findchain(classname, "player");
105         firstspot = find(world, classname, spotname);
106         Spawn_ClassifyPoints(firstspot, playerlist, 100, 1000000, 1000000);
107         // first check if there are ANY good spots
108         if (spawn_goodspots > 0)
109         {
110                 // good spots exist, there is 50/50 chance of choosing a random good
111                 // spot or the furthest spot
112                 // (this means that roughly every other spawn will be furthest, so you
113                 // usually won't get fragged at spawn twice in a row)
114                 if (random() > 0.5)
115                         spot = Spawn_ClassifyPoints(firstspot, playerlist, 100, min(floor(random() * spawn_goodspots), spawn_goodspots - 1), 1000000);
116                 else
117                         spot = Spawn_FurthestPoint(firstspot, playerlist);
118         }
119         else
120         {
121                 // no good spots exist, pick a random bad spot
122                 spot = Spawn_ClassifyPoints(firstspot, playerlist, 100, 1000000, min(floor(random() * spawn_badspots), spawn_badspots - 1));
123         }
124
125         if (!spot)
126         {
127                 if(anypoint)
128                         error ("PutClientInServer: no start points on level");
129                 else // try again with deathmatch spots
130                         spot = SelectSpawnPoint(TRUE);
131         }
132
133         return spot;
134 }
135
136 /*
137 =============
138 CheckPlayerModel
139
140 Checks if the argument string can be a valid playermodel.
141 Returns a valid one in doubt.
142 =============
143 */
144 string CheckPlayerModel(string plyermodel) {
145         if( substring(plyermodel,0,14) != "models/player/") plyermodel = "models/player/marine.zym";
146
147         /* Possible Fixme: Check if server can open the model?
148            This would kill custom models, however. */
149
150         return plyermodel;
151 }
152
153
154 /*
155 =============
156 PutClientInServer
157
158 Called when a client spawns in the server
159 =============
160 */
161 void PutClientInServer (void)
162 {
163         entity  spot;
164
165         spot = SelectSpawnPoint (FALSE);
166         
167         RemoveGrapplingHook(self); // Wazat's Grappling Hook
168         
169         self.classname = "player";
170         self.iscreature = TRUE;
171         self.movetype = MOVETYPE_WALK;
172         self.solid = SOLID_SLIDEBOX;
173         self.flags = FL_CLIENT;
174         self.takedamage = DAMAGE_AIM;
175         self.effects = 0;
176         self.health = cvar("g_balance_health_start");
177         self.armorvalue = cvar("g_balance_armor_start");
178         self.pauserotarmor_finished = time + 10;
179         self.pauserothealth_finished = time + 10;
180         self.pauseregen_finished = 0;
181         self.damageforcescale = 2;
182         self.death_time = 0;
183         self.dead_time = 0;
184         self.dead_frame = 0;
185         self.die_frame = 0;
186         self.alpha = 0;
187         self.scale = 0;
188         self.fade_time = 0;
189         self.pain_frame = 0;
190         self.pain_finished = 0;
191         self.strength_finished = 0;
192         self.invincible_finished = 0;
193         self.pushltime = 0;
194         //self.speed_finished = 0;
195         //self.slowmo_finished = 0;
196         self.vote_finished = 0;
197         // players have no think function
198         self.think = SUB_Null;
199         self.nextthink = 0;
200
201         self.hook_time = 0;
202
203         self.runes = 0;
204
205         self.deadflag = DEAD_NO;
206
207         self.angles = spot.angles;
208
209         self.angles_z = 0; // never spawn tilted even if the spot says to
210         self.fixangle = TRUE; // turn this way immediately
211         self.velocity = '0 0 0';
212         self.avelocity = '0 0 0';
213         self.punchangle = '0 0 0';
214         self.punchvector = '0 0 0';
215         self.oldvelocity = self.velocity;
216
217         self.viewzoom = 0.6;
218
219
220         self.playermodel = CheckPlayerModel(self.playermodel);
221
222         precache_model (self.playermodel);
223         setmodel (self, self.playermodel);
224         self.skin = stof(self.playerskin);
225         self.crouch = FALSE;
226         self.view_ofs = PL_VIEW_OFS;
227         setsize (self, PL_MIN, PL_MAX);
228         setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24));
229         // don't reset back to last position, even if new position is stuck in solid
230         self.oldorigin = self.origin;
231
232         if (cvar("g_use_ammunition")) {
233                 self.ammo_shells = cvar("g_start_ammo_shells");
234                 self.ammo_nails = cvar("g_start_ammo_nails");
235                 self.ammo_rockets = cvar("g_start_ammo_rockets");
236                 self.ammo_cells = cvar("g_start_ammo_cells");
237         } else {
238                 self.ammo_shells = 999;
239                 self.ammo_nails = 999;
240                 self.ammo_rockets = 999;
241                 self.ammo_cells = 999;
242         }
243
244         self.items = 0;
245         if (cvar("g_start_weapon_laser"))
246         {
247                 self.items = self.items | IT_LASER;
248                 self.switchweapon = WEP_LASER;
249         }
250         if (cvar("g_start_weapon_shotgun"))
251         {
252                 self.items = self.items | IT_SHOTGUN;
253                 self.switchweapon = WEP_SHOTGUN;
254         }
255         if (cvar("g_start_weapon_uzi"))
256         {
257                 self.items = self.items | IT_UZI;
258                 self.switchweapon = WEP_UZI;
259         }
260         if (cvar("g_start_weapon_grenadelauncher"))
261         {
262                 self.items = self.items | IT_GRENADE_LAUNCHER;
263                 self.switchweapon = WEP_GRENADE_LAUNCHER;
264         }
265         if (cvar("g_start_weapon_electro"))
266         {
267                 self.items = self.items | IT_ELECTRO;
268                 self.switchweapon = WEP_ELECTRO;
269         }
270         if (cvar("g_start_weapon_crylink"))
271         {
272                 self.items = self.items | IT_CRYLINK;
273                 self.switchweapon = WEP_CRYLINK;
274         }
275         if (cvar("g_start_weapon_nex"))
276         {
277                 self.items = self.items | IT_NEX;
278                 self.switchweapon = WEP_NEX;
279         }
280         if (cvar("g_start_weapon_hagar"))
281         {
282                 self.items = self.items | IT_HAGAR;
283                 self.switchweapon = WEP_HAGAR;
284         }
285         if (cvar("g_start_weapon_rocketlauncher"))
286         {
287                 self.items = self.items | IT_ROCKET_LAUNCHER;
288                 self.switchweapon = WEP_ROCKET_LAUNCHER;
289         }
290
291         self.event_damage = PlayerDamage;
292
293         self.statdraintime = time + 5;
294         self.button0 = self.button1 = self.button2 = self.button3 = 0;
295
296         /*
297         W_UpdateWeapon();
298         W_UpdateAmmo();
299         */
300         CL_SpawnWeaponentity();
301
302         //stuffcmd(self, "chase_active 0");
303 }
304
305 /*
306 =============
307 SetNewParms
308 =============
309 */
310 void SetNewParms (void)
311 {
312
313 }
314
315 /*
316 =============
317 SetChangeParms
318 =============
319 */
320 void SetChangeParms (void)
321 {
322
323 }
324
325 /*
326 =============
327 ClientKill
328
329 Called when a client types 'kill' in the console
330 =============
331 */
332 void ClientKill (void)
333 {
334         Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
335 }
336
337 /*
338 =============
339 ClientConnect
340
341 Called when a client connects to the server
342 =============
343 */
344 string ColoredTeamName(float t);
345 //void dom_player_join_team(entity pl);
346 void ClientConnect (void)
347 {
348         self.classname = "player_joining";
349
350         //if(cvar("g_domination"))
351         //      dom_player_join_team(self);
352
353         JoinBestTeam(self, FALSE);
354
355         self.classname = "player";
356
357
358
359         bprint ("^4",self.netname);
360         bprint (" connected");
361
362         if(cvar("g_domination") || cvar("g_ctf"))
363         {
364                 bprint(" and joined the ");
365                 bprint(ColoredTeamName(self.team));
366         }
367
368         bprint("\n");
369
370         self.welcomemessage_time = time + cvar("welcome_message_time");
371         self.welcomemessage_time2 = 0;
372
373
374         stuffcmd(self, strcat("exec maps/", mapname, ".cfg\n"));
375         // send prediction settings to the client
376         stuffcmd(self, strcat("cl_movement_maxspeed ", ftos(cvar("sv_maxspeed")), "\n"));
377         stuffcmd(self, strcat("cl_movement_maxairspeed ", ftos(cvar("sv_maxairspeed")), "\n"));
378         stuffcmd(self, strcat("cl_movement_accelerate ", ftos(cvar("sv_accelerate")), "\n"));
379         stuffcmd(self, strcat("cl_movement_friction ", ftos(cvar("sv_friction")), "\n"));
380         stuffcmd(self, strcat("cl_movement_stopspeed ", ftos(cvar("sv_stopspeed")), "\n"));
381         stuffcmd(self, strcat("cl_movement_jumpvelocity ", ftos(cvar("g_balance_jumpheight")), "\n"));
382         stuffcmd(self, strcat("cl_movement_stepheight ", ftos(cvar("sv_stepheight")), "\n"));
383         stuffcmd(self, strcat("cl_movement_edgefriction 0\n"));
384         
385         // Wazat's grappling hook
386         SetGrappleHookBindings();       
387
388         // get autoswitch state from player
389         stuffcmd(self, "alias autoswitch \"set cl_autoswitch $1; cmd autoswitch $1\"\n");
390         stuffcmd(self, "cmd autoswitch $cl_autoswitch\n");
391
392         // get version info from player
393         stuffcmd(self, "cmd clientversion $g_nexuizversion\n");
394 }
395
396 /*
397 =============
398 ClientDisconnect
399
400 Called when a client disconnects from the server
401 =============
402 */
403 .entity chatbubbleentity;
404 void ClientDisconnect (void)
405 {
406         bprint ("^4",self.netname);
407         bprint (" disconnected\n");
408
409         if (self.chatbubbleentity)
410         {
411                 remove (self.chatbubbleentity);
412                 self.chatbubbleentity = world;
413         }
414         DropAllRunes(self);
415 }
416
417 .float buttonchat;
418 void() ChatBubbleThink =
419 {
420         self.nextthink = time;
421         if (!self.owner.modelindex || self.owner.chatbubbleentity != self)
422         {
423                 remove(self);
424                 return;
425         }
426         setorigin(self, self.owner.origin + '0 0 15' + self.owner.maxs_z * '0 0 1');
427         if (self.owner.buttonchat && !self.owner.deadflag)
428                 self.model = self.mdl;
429         else
430                 self.model = "";
431 };
432
433 void() UpdateChatBubble =
434 {
435         if (!self.modelindex)
436                 return;
437         // spawn a chatbubble entity if needed
438         if (!self.chatbubbleentity)
439         {
440                 self.chatbubbleentity = spawn();
441                 self.chatbubbleentity.owner = self;
442                 self.chatbubbleentity.exteriormodeltoclient = self;
443                 self.chatbubbleentity.think = ChatBubbleThink;
444                 self.chatbubbleentity.nextthink = time;
445                 setmodel(self.chatbubbleentity, "models/misc/chatbubble.spr");
446                 setorigin(self.chatbubbleentity, self.origin + '0 0 15' + self.maxs_z * '0 0 1');
447                 self.chatbubbleentity.mdl = self.chatbubbleentity.model;
448                 self.chatbubbleentity.model = "";
449         }
450 }
451
452 // LordHavoc: this hack will be removed when proper _pants/_shirt layers are
453 // added to the model skins
454 void() UpdateColorModHack =
455 {
456         local float c;
457         c = self.clientcolors & 15;
458         // LordHavoc: only bothering to support white, green, red, yellow, blue
459              if (teamplay == 0) self.colormod = '0 0 0';
460         else if (c ==  0) self.colormod = '1.00 1.00 1.00';
461         else if (c ==  3) self.colormod = '0.10 1.73 0.10';
462         else if (c ==  4) self.colormod = '1.73 0.10 0.10';
463         else if (c == 12) self.colormod = '1.22 1.22 0.10';
464         else if (c == 13) self.colormod = '0.10 0.10 1.73';
465         else self.colormod = '1 1 1';
466 };
467
468 /*
469 =============
470 PlayerJump
471
472 When you press the jump key
473 =============
474 */
475 void PlayerJump (void)
476 {
477         float mjumpheight;
478
479         mjumpheight = cvar("g_balance_jumpheight");
480         if (self.waterlevel >= 2)
481         {
482                 if (self.watertype == CONTENT_WATER)
483                         self.velocity_z = 200;
484                 else if (self.watertype == CONTENT_SLIME)
485                         self.velocity_z = 80;
486                 else
487                         self.velocity_z = 50;
488
489                 return;
490         }
491
492
493         if (!(self.flags & FL_ONGROUND))
494                 return;
495
496         if (!(self.flags & FL_JUMPRELEASED))
497                 return;
498
499         if(cvar("g_runematch"))
500         {
501                 if(self.runes & RUNE_SPEED)
502                 {
503                         if(self.runes & CURSE_SLOW)
504                                 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_combo_jumpheight");
505                         else
506                                 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_jumpheight");
507                 }
508                 else if(self.runes & CURSE_SLOW)
509                 {
510                         mjumpheight = mjumpheight * cvar("g_balance_curse_slow_jumpheight");
511                 }
512         }
513
514         self.velocity_z = self.velocity_z + mjumpheight;
515         self.oldvelocity_z = self.velocity_z;
516
517         self.flags = self.flags - FL_ONGROUND;
518         self.flags = self.flags - FL_JUMPRELEASED;
519 }
520
521 void() CheckWaterJump =
522 {
523         local vector start, end;
524
525 // check for a jump-out-of-water
526         makevectors (self.angles);
527         start = self.origin;
528         start_z = start_z + 8;
529         v_forward_z = 0;
530         normalize(v_forward);
531         end = start + v_forward*24;
532         traceline (start, end, TRUE, self);
533         if (trace_fraction < 1)
534         {       // solid at waist
535                 start_z = start_z + self.maxs_z - 8;
536                 end = start + v_forward*24;
537                 self.movedir = trace_plane_normal * -50;
538                 traceline (start, end, TRUE, self);
539                 if (trace_fraction == 1)
540                 {       // open at eye level
541                         self.flags = self.flags | FL_WATERJUMP;
542                         self.velocity_z = 225;
543                         self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
544                         self.teleport_time = time + 2;  // safety net
545                         return;
546                 }
547         }
548 };
549
550
551 void respawn(void)
552 {
553         CopyBody(1);
554         PutClientInServer();
555 }
556
557 void player_powerups (void)
558 {
559         self.effects = self.effects - (self.effects & (EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT));
560         if (self.items & IT_STRENGTH)
561         {
562                 self.effects = self.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
563                 if (time > self.strength_finished)
564                 {
565                         self.items = self.items - (self.items & IT_STRENGTH);
566                         sprint(self, "^3Strength has worn off\n");
567                 }
568         }
569         else
570         {
571                 if (time < self.strength_finished)
572                 {
573                         self.items = self.items | IT_STRENGTH;
574                         sprint(self, "^3Strength infuses your weapons with devestating power\n");
575                 }
576         }
577         if (self.items & IT_INVINCIBLE)
578         {
579                 self.effects = self.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
580                 if (time > self.invincible_finished)
581                 {
582                         self.items = self.items - (self.items & IT_INVINCIBLE);
583                         sprint(self, "^3Shield has worn off\n");
584                 }
585         }
586         else
587         {
588                 if (time < self.invincible_finished)
589                 {
590                         self.items = self.items | IT_INVINCIBLE;
591                         sprint(self, "^3Shield surrounds you\n");
592                 }
593         }
594         
595         if (cvar("g_fullbrightplayers"))
596                 self.effects = EF_FULLBRIGHT;
597         
598 }
599
600 void player_regen (void)
601 {
602         float maxh, maxa, max_mod, regen_mod, rot_mod;
603         maxh = cvar("g_balance_health_stable");
604         maxa = cvar("g_balance_armor_stable");
605
606         if(cvar("g_runematch"))
607         {
608                 max_mod = regen_mod = rot_mod = 1;
609                 if (self.runes & RUNE_REGEN)
610                 {
611                         if (self.runes & CURSE_VENOM) // do we have both rune/curse?
612                         {
613                                 regen_mod = cvar("g_balance_rune_regen_combo_regenrate");
614                                 max_mod = cvar("g_balance_rune_regen_combo_hpmod");
615                         }
616                         else
617                         {
618                                 regen_mod = cvar("g_balance_rune_regen_regenrate");
619                                 max_mod = cvar("g_balance_rune_regen_hpmod");
620                         }
621                 }
622                 else if (self.runes & CURSE_VENOM)
623                 {
624                         max_mod = cvar("g_balance_curse_venom_hpmod");
625                         if (self.runes & RUNE_REGEN) // do we have both rune/curse?
626                                 rot_mod = cvar("g_balance_rune_regen_combo_rotrate");
627                         else
628                                 rot_mod = cvar("g_balance_curse_venom_rotrate");
629                         //if (!self.runes & RUNE_REGEN)
630                         //      rot_mod = cvar("g_balance_curse_venom_rotrate");
631                 }
632                 maxh = maxh * max_mod;
633                 //maxa = maxa * max_mod;
634
635                 if (time > self.pauserotarmor_finished)
636                 {
637                         if (self.armorvalue > maxa)
638                                 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_rot") * frametime, 1000);
639                 }
640                 if (time > self.pauserothealth_finished)
641                 {
642                         if (self.health > maxh)
643                                 self.health = bound(0, self.health + (maxh - self.health) * rot_mod*cvar("g_balance_health_rot") * frametime, 1000);
644                 }
645                 if (time > self.pauseregen_finished)
646                 {
647                         if (self.health < maxh)
648                                 self.health = bound(0, self.health + (maxh- self.health) * regen_mod*cvar("g_balance_health_regen") * frametime, 1000);
649                         if (self.armorvalue < maxa)
650                                 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_regen") * frametime, 1000);
651                 }
652         }
653         else
654         {
655                 if (time > self.pauserothealth_finished)
656                 if (self.health > maxh)
657                         self.health = bound(0, self.health + (maxh - self.health) * cvar("g_balance_health_rot") * frametime, 1000);
658                 if (time > self.pauserotarmor_finished)
659                 if (self.armorvalue > maxa)
660                         self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_rot") * frametime, 1000);
661                 if (time > self.pauseregen_finished)
662                 {
663                         if (self.health < maxh)
664                                 self.health = bound(0, self.health + (maxh- self.health) * cvar("g_balance_health_regen") * frametime, 1000);
665                         if (self.armorvalue < maxa)
666                                 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_regen") * frametime, 1000);
667                 }
668         }
669 }
670
671 /*
672 =============
673 PlayerPreThink
674
675 Called every frame for each client before the physics are run
676 =============
677 */
678 void PlayerPreThink (void)
679 {
680         local vector m1, m2;
681
682 //      MauveBot_AI();
683
684 //      if(self.netname == "Wazat")
685 //              bprint(strcat(self.classname, "\n"));
686
687         CheckRules_Player();
688
689         if (intermission_running)
690         {
691                 IntermissionThink ();   // otherwise a button could be missed between
692                 return;                                 // the think tics
693         }
694
695         if (self.deadflag != DEAD_NO)
696         {
697                 player_anim();
698                 weapon_freeze();
699                 if (self.deadflag == DEAD_DYING)
700                 {
701                         if (time > self.dead_time)
702                                 self.deadflag = DEAD_DEAD;
703                 }
704                 else if (self.deadflag == DEAD_DEAD)
705                 {
706                         if (!self.button0 && !self.button2 && !self.button3)
707                                 self.deadflag = DEAD_RESPAWNABLE;
708                 }
709                 else if (self.deadflag == DEAD_RESPAWNABLE)
710                 {
711                         if (self.button0 || self.button2 || self.button3  || self.button4)
712                                 respawn();
713                 }
714                 return;
715         }
716
717         if (self.button5)
718         {
719                 if (!self.crouch)
720                 {
721                         self.crouch = TRUE;
722                         self.view_ofs = PL_CROUCH_VIEW_OFS;
723                         setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX);
724                 }
725         }
726         else
727         {
728                 if (self.crouch)
729                 {
730                         tracebox(self.origin, PL_MIN, PL_MAX, self.origin, FALSE, self);
731                         if (!trace_startsolid)
732                         {
733                                 self.crouch = FALSE;
734                                 self.view_ofs = PL_VIEW_OFS;
735                                 setsize (self, PL_MIN, PL_MAX);
736                         }
737                 }
738         }
739
740         if (self.playermodel != self.model)
741         {
742                 self.playermodel = CheckPlayerModel(self.playermodel);
743                 m1 = self.mins;
744                 m2 = self.maxs;
745                 precache_model (self.playermodel);
746                 setmodel (self, self.playermodel);
747                 setsize (self, m1, m2);
748         }
749
750         // Savage: Check for nameless players
751         if (strlen(self.netname) < 1) {
752                 self.netname = "Player";
753                 stuffcmd(self, "name Player\n");
754         }
755
756         if (self.skin != stof(self.playerskin))
757                 self.skin = stof(self.playerskin);
758         
759         GrapplingHookFrame();
760
761         W_WeaponFrame();
762
763         if (self.button4 || (self.weapon == WEP_NEX && self.button3))
764         {
765                 if (self.viewzoom > 0.4)
766                         self.viewzoom = max (0.4, self.viewzoom - frametime * 2);
767         }
768         else if (self.viewzoom < 1.0)
769                 self.viewzoom = min (1.0, self.viewzoom + frametime);
770
771
772         if (self.button2)
773                 PlayerJump ();
774         else
775                 self.flags = self.flags | FL_JUMPRELEASED;
776
777         if (self.vote_finished > 0 // this player has called a vote
778             && time > self.vote_finished) // time is up
779         {
780                 VoteCount();
781         }
782
783         player_powerups();
784         player_regen();
785         player_anim();
786
787         //self.angles_y=self.v_angle_y + 90;   // temp
788
789         if (self.waterlevel == 2)
790                 CheckWaterJump ();
791
792         //if (TetrisPreFrame()) return;
793 }
794
795 /*
796 =============
797 PlayerPostThink
798
799 Called every frame for each client after the physics are run
800 =============
801 */
802 void PlayerPostThink (void)
803 {
804         CheckRules_Player();
805         UpdateChatBubble();
806         UpdateColorModHack();
807         if (self.deadflag == DEAD_NO)
808         if (self.impulse)
809                 ImpulseCommands ();
810         if (intermission_running)
811                 return;         // intermission or finale
812
813         PrintWelcomeMessage(self);
814         //if (TetrisPostFrame()) return;
815 }