]> icculus.org git repositories - divverent/nexuiz.git/blob - attic/TeamNexuiz/game/gamec/cl_client.c
moved navnodeedit & TeamNexuiz to attic
[divverent/nexuiz.git] / attic / TeamNexuiz / game / gamec / cl_client.c
1 void info_player_start (void)\r
2 {\r
3         if (self.allowteams != "")\r
4         {\r
5                 if (self.allowteams == "blue")\r
6                         self.team_no = 1;\r
7                 if (self.allowteams == "red")\r
8                         self.team_no = 2;\r
9                 if (!self.goal_state)\r
10                         self.goal_state = 1;\r
11                 if (!self.group_no)\r
12                         self.group_no = 1;\r
13                 i_p_t();\r
14                 return;\r
15         }\r
16         else\r
17         {\r
18                 self.classname = "info_player_deathmatch";\r
19         }\r
20 };\r
21 \r
22 void info_player_deathmatch (void)\r
23 {\r
24 }\r
25 /*\r
26 ===============\r
27  Find Team Spawn Point (NexTF!)\r
28                                  ===============\r
29 */\r
30 entity (float team_num) FindTeamSpawnPoint =\r
31 {\r
32         local entity spot;\r
33         local entity at_spot;\r
34         local float spot_found;\r
35         local float attempts;\r
36 \r
37         if ((team_num == 1))\r
38         {\r
39                 spot = lastspawn_team1;\r
40                 attempts = 0;\r
41                 while (1)\r
42                 {\r
43                         attempts = (attempts + 1);\r
44                         spot = find (spot, team_str_home, "ts1");\r
45                         if ((spot == world))\r
46                         {\r
47                                 spot = find (world, team_str_home, "ts1");\r
48                         }\r
49                         if ((spot == world))\r
50                         {\r
51                                 return (world);\r
52                         }\r
53                         at_spot = findradius (spot.origin, 40);\r
54                         spot_found = 1;\r
55                         while ((at_spot != world))\r
56                         {\r
57                                 if (((at_spot.classname == "player") && (at_spot.deadflag == 0)))\r
58                                 {\r
59                                         spot_found = 0;\r
60                                 }\r
61                                 at_spot = at_spot.chain;\r
62                         }\r
63                         if (!Activated (spot, self))\r
64                         {\r
65                                 spot_found = 0;\r
66                         }\r
67                         if ((spot_found || (attempts >= 30)))\r
68                         {\r
69                                 lastspawn_team1 = spot;\r
70                                 return (spot);\r
71                         }\r
72                 }\r
73         }\r
74         else\r
75         {\r
76                 if ((team_num == 2))\r
77                 {\r
78                         spot = lastspawn_team2;\r
79                         attempts = 0;\r
80                         while (1)\r
81                         {\r
82                                 attempts = (attempts + 1);\r
83                                 spot = find (spot, team_str_home, "ts2");\r
84                                 if ((spot == world))\r
85                                 {\r
86                                         spot = find (world, team_str_home, "ts2");\r
87                                 }\r
88                                 if ((spot == world))\r
89                                 {\r
90                                         return (world);\r
91                                 }\r
92                                 at_spot = findradius (spot.origin, 40);\r
93                                 spot_found = 1;\r
94                                 while ((at_spot != world))\r
95                                 {\r
96                                         if (((at_spot.classname == "player") && (at_spot.deadflag == 0)))\r
97                                         {\r
98                                                 spot_found = 0;\r
99                                         }\r
100                                         at_spot = at_spot.chain;\r
101                                 }\r
102                                 if (!Activated (spot, self))\r
103                                 {\r
104                                         spot_found = 0;\r
105                                 }\r
106                                 if ((spot_found || (attempts >= 30)))\r
107                                 {\r
108                                         lastspawn_team2 = spot;\r
109                                         return (spot);\r
110                                 }\r
111                         }\r
112                 }\r
113                 else\r
114                 {\r
115                         if ((team_num == 3))\r
116                         {\r
117                                 spot = lastspawn_team3;\r
118                                 attempts = 0;\r
119                                 while (1)\r
120                                 {\r
121                                         attempts = (attempts + 1);\r
122                                         spot = find (spot, team_str_home, "ts3");\r
123                                         if ((spot == world))\r
124                                         {\r
125                                                 spot = find (world, team_str_home, "ts3");\r
126                                         }\r
127                                         if ((spot == world))\r
128                                         {\r
129                                                 return (world);\r
130                                         }\r
131                                         at_spot = findradius (spot.origin, 40);\r
132                                         spot_found = 1;\r
133                                         while ((at_spot != world))\r
134                                         {\r
135                                                 if (((at_spot.classname == "player") && (at_spot.deadflag == 0)))\r
136                                                 {\r
137                                                         spot_found = 0;\r
138                                                 }\r
139                                                 at_spot = at_spot.chain;\r
140                                         }\r
141                                         if (!Activated (spot, self))\r
142                                         {\r
143                                                 spot_found = 0;\r
144                                         }\r
145                                         if ((spot_found || (attempts >= 30)))\r
146                                         {\r
147                                                 lastspawn_team3 = spot;\r
148                                                 return (spot);\r
149                                         }\r
150                                 }\r
151                         }\r
152                         else\r
153                         {\r
154                                 if ((team_num == 4))\r
155                                 {\r
156                                         spot = lastspawn_team4;\r
157                                         attempts = 0;\r
158                                         while (1)\r
159                                         {\r
160                                                 attempts = (attempts + 1);\r
161                                                 spot = find (spot, team_str_home, "ts4");\r
162                                                 if ((spot == world))\r
163                                                 {\r
164                                                         spot = find (world, team_str_home, "ts4");\r
165                                                 }\r
166                                                 if ((spot == world))\r
167                                                 {\r
168                                                         return (world);\r
169                                                 }\r
170                                                 at_spot = findradius (spot.origin, 40);\r
171                                                 spot_found = 1;\r
172                                                 while ((at_spot != world))\r
173                                                 {\r
174                                                         if (((at_spot.classname == "player") && (at_spot.deadflag == 0)))\r
175                                                         {\r
176                                                                 spot_found = 0;\r
177                                                         }\r
178                                                         at_spot = at_spot.chain;\r
179                                                 }\r
180                                                 if (!Activated (spot, self))\r
181                                                 {\r
182                                                         spot_found = 0;\r
183                                                 }\r
184                                                 if ((spot_found || (attempts >= 30)))\r
185                                                 {\r
186                                                         lastspawn_team4 = spot;\r
187                                                         return (spot);\r
188                                                 }\r
189                                         }\r
190                                 }\r
191                         }\r
192                 }\r
193         }\r
194         return (world);\r
195 };\r
196 \r
197 /*\r
198 =============\r
199 SelectSpawnPoint\r
200 \r
201 Finds a point to respawn\r
202 =============\r
203 */\r
204 entity () SelectSpawnPoint =\r
205 {\r
206         local entity spot;\r
207         local entity at_spot;\r
208         local float spot_found;\r
209         local float attempts;\r
210 \r
211         if (self.team_no < 1)\r
212         {\r
213 //              self.origin_z = self.origin_z + 30;\r
214                 if (!cvar("g_teamnexuiz_version"))\r
215                         self.current_menu = MENU_NEED_TN;\r
216                 else\r
217                 {\r
218                         stuffcmd(self, "alias menu_showteamselect \"set scmenu_directmenu TeamSelect; togglemenu\"\n");\r
219                         stuffcmd(self, "set scmenu_directmenu TeamSelect; togglemenu\n");\r
220                         stuffcmd(self, "alias classmenu \"impulse 73\"\n");\r
221                         stuffcmd(self, "cl_bobmodel 0\n");              // So the HUD items dont bob around\r
222                 }\r
223 //              spot = find (world, classname, "item_tfgoal");\r
224 //              return (spot);\r
225         }\r
226         self.is_dead = 0;               //TEMP\r
227 \r
228         if ((self.team_no != 0))\r
229         {\r
230                 spot = FindTeamSpawnPoint (self.team_no);\r
231                 if ((spot != world))\r
232                 {\r
233                         return (spot);\r
234                 }\r
235         }\r
236         if (coop)\r
237         {\r
238                 lastspawn = find (lastspawn, classname, "info_player_coop");\r
239                 if ((lastspawn == world))\r
240                 {\r
241                         lastspawn = find (world, classname, "info_player_coop");\r
242                 }\r
243                 if ((lastspawn != world))\r
244                 {\r
245                         return (lastspawn);\r
246                 }\r
247         }\r
248         else\r
249         {\r
250                 if (deathmatch)\r
251                 {\r
252                         spot = find (lastspawn, classname, "info_player_deathmatch");\r
253                         if ((spot == world))\r
254                         {\r
255                                 spot = find (world, classname, "info_player_deathmatch");\r
256                         }\r
257                         attempts = 0;\r
258                         while (((spot != world) && (attempts < 100)))\r
259                         {\r
260                                 attempts = (attempts + 1);\r
261                                 at_spot = findradius (spot.origin, 40);\r
262                                 spot_found = 1;\r
263                                 while (at_spot)\r
264                                 {\r
265                                         if (((at_spot.classname == "player") && (at_spot.deadflag == 0)))\r
266                                         {\r
267                                                 spot_found = 0;\r
268                                         }\r
269                                         at_spot = at_spot.chain;\r
270                                 }\r
271                                 if ((spot_found || (attempts >= 10)))\r
272                                 {\r
273                                         lastspawn = spot;\r
274                                         return (spot);\r
275                                 }\r
276                                 spot = find (spot, classname, "info_player_deathmatch");\r
277                                 if ((spot == world))\r
278                                 {\r
279                                         spot = find (world, classname, "info_player_deathmatch");\r
280                                 }\r
281                         }\r
282                 }\r
283         }\r
284         if (serverflags)\r
285         {\r
286                 spot = find (world, classname, "info_player_start2");\r
287                 if (spot)\r
288                 {\r
289                         return (spot);\r
290                 }\r
291         }\r
292         spot = find (world, classname, "info_player_start");\r
293         /*if (!spot)\r
294         {\r
295                 spot = find (world, is_converted_goal, "yes");\r
296         }*/\r
297         spot = find(world, classname, "info_player_start");\r
298         if (!spot)\r
299         {\r
300                 spot = find (world, classname, "info_player_intermission");\r
301         }\r
302         if (!spot)\r
303         {\r
304                 spot = find (world, classname, "info_tfgoal");\r
305         }\r
306         if (!spot)\r
307         {\r
308                 error ("PutClientInServer: no info_player_start on level\n");\r
309         }\r
310         return (spot);\r
311 };\r
312 \r
313 /*entity SelectSpawnPoint (void)                // Old, non-tf code\r
314 {\r
315         local entity spot, thing;\r
316         local float pcount;\r
317 \r
318         spot = find (world, classname, "testplayerstart");\r
319         if (spot)\r
320                 return spot;\r
321 \r
322         spot = lastspawn;\r
323         while (1)\r
324         {\r
325                 spot = find(spot, classname, "info_player_deathmatch");\r
326                 if (spot != world)\r
327                 {\r
328                         if (spot == lastspawn)\r
329                                 return lastspawn;\r
330                         pcount = 0;\r
331                         thing = findradius(spot.origin, 70);\r
332                         while(thing)\r
333                         {\r
334                                 if (thing.classname == "player")\r
335                                         pcount = pcount + 1;\r
336                                 thing = thing.chain;\r
337                         }\r
338                         if (pcount == 0)\r
339                         {\r
340                                 lastspawn = spot;\r
341                                 return spot;\r
342                         }\r
343                 }\r
344         }\r
345 \r
346         spot = find (world, classname, "info_player_start");\r
347         if (!spot)\r
348                 error ("PutClientInServer: no info_player_start on level");\r
349 \r
350         return spot;\r
351 }*/\r
352 \r
353 /*\r
354 =============\r
355 CheckPlayerModel\r
356 \r
357 Checks if the argument string can be a valid playermodel.\r
358 Returns a valid one in doubt.\r
359 =============\r
360 */\r
361 string CheckPlayerModel(string playermodel) {\r
362         if( substring(playermodel,0,13) != "models/class/") playermodel = "models/class/scout.zym";\r
363 \r
364         /* Possible Fixme: Check if server can open the model?\r
365            This would kill custom models, however. */\r
366 \r
367         return playermodel;\r
368 }\r
369 \r
370 \r
371 /*\r
372 =============\r
373 PutClientInServer\r
374 \r
375 Called when a client spawns in the server\r
376 =============\r
377 */\r
378 void PutClientInServer (void)\r
379 {\r
380         entity  spot;\r
381         float oldcl;\r
382         if (self.team_no < 1)\r
383         {\r
384         self.movetype = 0;\r
385         self.solid = 0;\r
386         self.flags = FL_CLIENT;\r
387         self.takedamage = DAMAGE_AIM;\r
388         self.effects = 0;\r
389         self.health = cvar("g_balance_health_start");\r
390         self.max_health = cvar("g_balance_health_stable");\r
391         self.armorvalue = cvar("g_balance_armor_start");\r
392         self.max_armor = self.armorvalue;\r
393         self.damageforcescale = 2;\r
394         self.death_time = 0;\r
395         self.dead_time = 0;\r
396         self.dead_frame = 0;\r
397         self.die_frame = 0;\r
398         self.alpha = 0;\r
399         self.scale = 0;\r
400         self.fade_time = 0;\r
401         self.pain_frame = 0;\r
402         self.pain_finished = 0;\r
403         self.strength_finished = 0;\r
404         self.invincible_finished = 0;\r
405         //self.speed_finished = 0;\r
406         //self.slowmo_finished = 0;\r
407         // players have no think function\r
408         self.think = SUB_Null;\r
409         self.nextthink = 0;\r
410         self.speed = -1;\r
411         self.jump_pad = 0;\r
412         spot = SelectSpawnPoint();\r
413         setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 14));\r
414 //      setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z + 24));\r
415 //      setorigin (self, spot.origin + '-2 0 4' * (1 - self.mins_z + 24));\r
416 //      self.angles_y = self.angles_y + 180;\r
417         return;\r
418         }\r
419         if (self.playerclass < 1)\r
420         {\r
421                 stuffcmd(self, "set scmenu_directmenu ClassSelect; togglemenu\n");\r
422                 return;\r
423         }\r
424 \r
425         // fixme: are these the right teams & colors?\r
426         /*if(self.team == 5)            // Wazat -- I'm using TeamFortress_TeamSet for this now\r
427         {\r
428                 self.team_no = 1;\r
429         }\r
430         if(self.team == 14)\r
431         {\r
432                 self.team_no = 2;\r
433         }\r
434         if(self.team == 4)\r
435         {\r
436                 self.team_no = 3;\r
437         }\r
438         if(self.team == 13)\r
439         {\r
440                 self.team_no = 4;\r
441         }*/\r
442 \r
443         DoTFAliases ();\r
444 \r
445 //      spot = SelectSpawnPoint ();             // moved down\r
446         self.classname = "player";\r
447         self.movetype = MOVETYPE_WALK;\r
448         self.solid = SOLID_SLIDEBOX;\r
449         self.flags = FL_CLIENT;\r
450         self.takedamage = DAMAGE_AIM;\r
451         self.effects = 0;\r
452         self.health = cvar("g_balance_health_start");\r
453         self.max_health = cvar("g_balance_health_stable");\r
454         self.armorvalue = cvar("g_balance_armor_start");\r
455         self.max_armor = self.armorvalue;\r
456         self.damageforcescale = 2;\r
457         self.death_time = 0;\r
458         self.dead_time = 0;\r
459         self.dead_frame = 0;\r
460         self.die_frame = 0;\r
461         self.alpha = 0;\r
462         self.scale = 0;\r
463         self.fade_time = 0;\r
464         self.pain_frame = 0;\r
465         self.pain_finished = 0;\r
466         self.strength_finished = 0;\r
467         self.invincible_finished = 0;\r
468         //self.speed_finished = 0;\r
469         //self.slowmo_finished = 0;\r
470         // players have no think function\r
471         self.think = SUB_Null;\r
472         self.nextthink = 0;\r
473         self.speed = -1;\r
474         self.jump_pad = 0;\r
475         //self.wpn5 = 0; // not carrying an extra weapon\r
476         ResetExtraWeapon(); // not carrying an extra weapon\r
477 \r
478         DelayHealthRegen(self);\r
479         DelayArmorRegen(self);\r
480         DelayHealthRot(self);\r
481         DelayArmorRot(self);\r
482 \r
483 \r
484         self.special_active = 0;\r
485         self.special_time = 0;\r
486 \r
487         self.grenade_time = 0;\r
488 \r
489         if(self.onfire != world)\r
490                 remove(self.onfire);\r
491         self.onfire = world;\r
492         self.flame_heat = 0;\r
493         self.flame_heat_time = 0;\r
494 \r
495         self.poison_damage = 0;\r
496         self.poison_rate = 0;\r
497 \r
498         self.is_feigning = 0;\r
499         self.current_menu = 0;\r
500 \r
501         // if the player is supposed to change model (and hence class) on respawn, do it.\r
502         if(self.change_mdl_on_respawn != "")\r
503         {\r
504                 self.playermodel = self.change_mdl_on_respawn;\r
505                 //strunzone(self.change_mdl_on_respawn); // can't unzone or it'll crash later\r
506         }\r
507         // set the class.  If he changed classes while dead it will take effect now.\r
508         oldcl = self.class;\r
509         self.class = GetPlayerClass();\r
510         Do_TFClass_Conversion();\r
511         ChangeClass((oldcl != self.class), FALSE);\r
512 \r
513 \r
514 \r
515         self.deadflag = DEAD_NO;\r
516 \r
517         spot = SelectSpawnPoint ();             // maybe temp\r
518         self.angles = spot.angles;\r
519         self.fixangle = TRUE; // turn this way immediately\r
520         self.velocity = '0 0 0';\r
521         self.avelocity = '0 0 0';\r
522         self.punchangle = '0 0 0';\r
523         self.punchvector = '0 0 0';\r
524 \r
525         self.viewzoom = 0.6;\r
526 \r
527 \r
528         self.playermodel = CheckPlayerModel(self.playermodel);\r
529 \r
530         precache_model (self.playermodel);\r
531         setmodel (self, self.playermodel);\r
532         self.skin = stof(self.playerskin);\r
533         self.mdl = strzone(self.playermodel);\r
534 \r
535         self.crouch = FALSE;\r
536         self.view_ofs = PL_VIEW_OFS;\r
537         setsize (self, PL_MIN, PL_MAX);\r
538         setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24));\r
539         // don't reset back to last position, even if new position is stuck in solid\r
540         self.oldorigin = self.origin;\r
541 \r
542 //      self.items = IT_LASER | IT_UZI| IT_SHOTGUN | IT_GRENADE_LAUNCHER | IT_ELECTRO | IT_CRYLINK | IT_NEX | IT_HAGAR | IT_ROCKET_LAUNCHER;\r
543 //      self.weapon = IT_UZI;\r
544 \r
545 \r
546         // fixme: move this to Become<Class> code\r
547 /*      self.items = IT_WEP1 | IT_WEP2 | IT_WEP3 | IT_WEP4;\r
548         //self.weapon = 1;\r
549         self.switchweapon = IT_WEP2;\r
550         self.ammo_shells = 50;\r
551         self.ammo_nails = 0;\r
552         self.ammo_rockets = 0;\r
553         self.ammo_cells = 0;*/\r
554 \r
555         if (cvar("g_fullbrightplayers") == 1)\r
556                 self.effects = EF_FULLBRIGHT;\r
557 \r
558         self.event_damage = PlayerDamage;\r
559 \r
560         self.statdraintime = time + 5;\r
561         self.button0 = self.button1 = self.button2 = self.button3 = 0;\r
562 \r
563         /*\r
564         W_UpdateWeapon();\r
565         W_UpdateAmmo();\r
566         */\r
567         CL_SpawnWeaponentity();\r
568         self.weaponentity.alpha = self.exteriorweaponentity.alpha = 0;\r
569         self.weaponentity.colormod = '0 0 0';\r
570         self.weaponentity.scale = 0;\r
571 \r
572         //stuffcmd(self, "chase_active 0");\r
573 }\r
574 \r
575 /*\r
576 =============\r
577 SetNewParms\r
578 =============\r
579 */\r
580 void SetNewParms (void)\r
581 {\r
582 \r
583 }\r
584 \r
585 /*\r
586 =============\r
587 SetChangeParms\r
588 =============\r
589 */\r
590 void SetChangeParms (void)\r
591 {\r
592 \r
593 }\r
594 \r
595 /*\r
596 =============\r
597 ClientKill\r
598 \r
599 Called when a client types 'kill' in the console\r
600 =============\r
601 */\r
602 void ClientKill (void)\r
603 {\r
604         Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');\r
605 }\r
606 \r
607 /*\r
608 =============\r
609 ClientConnect\r
610 \r
611 Called when a client connects to the server\r
612 =============\r
613 */\r
614 void ClientConnect (void)\r
615 {\r
616         //ClientInRankings();\r
617         bprint ("^4",self.netname);\r
618         bprint (" connected\n");\r
619         stuffcmd(self, strcat("exec maps/", mapname, ".cfg\n"));\r
620         // send prediction settings to the client\r
621         stuffcmd(self, strcat("cl_movement_maxspeed ", ftos(cvar("sv_maxspeed")), "\n"));\r
622         stuffcmd(self, strcat("cl_movement_maxairspeed ", ftos(cvar("sv_maxairspeed")), "\n"));\r
623         stuffcmd(self, strcat("cl_movement_accelerate ", ftos(cvar("sv_accelerate")), "\n"));\r
624         stuffcmd(self, strcat("cl_movement_friction ", ftos(cvar("sv_friction")), "\n"));\r
625         stuffcmd(self, strcat("cl_movement_stopspeed ", ftos(cvar("sv_stopspeed")), "\n"));\r
626         stuffcmd(self, strcat("cl_movement_jumpvelocity ", ftos(cvar("g_balance_jumpheight")), "\n"));\r
627         stuffcmd(self, strcat("cl_movement_stepheight ", ftos(cvar("sv_stepheight")), "\n"));\r
628         stuffcmd(self, strcat("cl_movement_edgefriction 0\n"));\r
629                         // TEMP FOR TESTING PURPOSES!\r
630         //teamplay = 21?TeamFortress;\r
631         DecodeLevelParms ();\r
632         //cvar_set ("teamplay", "21?TeamFortress");\r
633         //      teamplay = cvar ("teamplay");\r
634 \r
635 /*      joinorder = joinorder + 1;                      // old temp autoteam, but now we have a menu instead :P\r
636         if (joinorder == 1 || joinorder == 3 || joinorder == 5 || joinorder == 7)\r
637                 TeamFortress_TeamSet (1);\r
638         else {\r
639                 TeamFortress_TeamSet (2);\r
640         }*/\r
641 }\r
642 \r
643 /*\r
644 =============\r
645 ClientDisconnect\r
646 \r
647 Called when a client disconnects from the server\r
648 =============\r
649 */\r
650 .entity chatbubbleentity;\r
651 void ClientDisconnect (void)\r
652 {\r
653         //ClientDisconnected();\r
654         self.has_disconnected = 1;\r
655         bprint ("^4",self.netname);\r
656         bprint (" disconnected\n");\r
657 \r
658         if (self.chatbubbleentity)\r
659         {\r
660                 remove (self.chatbubbleentity);\r
661                 self.chatbubbleentity = world;\r
662         }\r
663         \r
664         if (self.teambubble_friendly)\r
665         {\r
666                 remove (self.teambubble_friendly);\r
667                 self.teambubble_friendly = world;\r
668         }\r
669         if (self.teambubble_needhealth)\r
670         {\r
671                 remove (self.teambubble_needhealth);\r
672                 self.teambubble_needhealth = world;\r
673         }\r
674 }\r
675 \r
676 .entity chatbubbleentity;\r
677 .float buttonchat;\r
678 void() ChatBubbleThink =\r
679 {\r
680         self.nextthink = time;\r
681         if (!self.owner.modelindex || self.owner.chatbubbleentity != self)\r
682         {\r
683                 remove(self);\r
684                 return;\r
685         }\r
686         setorigin(self, self.owner.origin + '0 0 15' + self.owner.maxs_z * '0 0 1');\r
687         if (self.owner.buttonchat)\r
688                 self.effects = 0;\r
689         else\r
690                 self.effects = EF_NODRAW;\r
691 };\r
692 \r
693 void() UpdateChatBubble =\r
694 {\r
695         if (!self.modelindex)\r
696                 return;\r
697         // spawn a chatbubble entity if needed\r
698         if (!self.chatbubbleentity)\r
699         {\r
700                 self.chatbubbleentity = spawn();\r
701                 self.chatbubbleentity.owner = self;\r
702                 self.chatbubbleentity.think = ChatBubbleThink;\r
703                 self.chatbubbleentity.nextthink = time;\r
704                 setmodel(self.chatbubbleentity, "models/misc/chatbubble.spr");\r
705                 setorigin(self.chatbubbleentity, self.origin + '0 0 15' + self.maxs_z * '0 0 1');\r
706                 self.chatbubbleentity.effects = EF_NODRAW;\r
707         }\r
708 }\r
709 \r
710 // LordHavoc: this hack will be removed when proper _pants/_shirt layers are\r
711 // added to the model skins\r
712 void() UpdateColorModHack =\r
713 {\r
714         local float c;\r
715         c = self.clientcolors & 15;\r
716         // LordHavoc: only bothering to support white, green, red, yellow, blue\r
717              if (teamplay == 0) self.colormod = '0 0 0';\r
718         else if (c ==  0) self.colormod = '1.00 1.00 1.00';\r
719         else if (c ==  3) self.colormod = '0.10 1.73 0.10';\r
720         else if (c ==  4) self.colormod = '1.73 0.10 0.10';\r
721         else if (c == 12) self.colormod = '1.22 1.22 0.10';\r
722         else if (c == 13) self.colormod = '0.10 0.10 1.73';\r
723         else self.colormod = '1 1 1';\r
724 };\r
725 \r
726 /*\r
727 =============\r
728 PlayerJump\r
729 \r
730 When you press the jump key\r
731 =============\r
732 */\r
733 void PlayerJump (void)\r
734 {\r
735         if (self.waterlevel >= 2)\r
736         {\r
737                 if (self.watertype == CONTENT_WATER)\r
738                         self.velocity_z = 200;\r
739                 else if (self.watertype == CONTENT_SLIME)\r
740                         self.velocity_z = 80;\r
741                 else\r
742                         self.velocity_z = 50;\r
743 \r
744                 return;\r
745         }\r
746         if(self.jump_pad)\r
747                 return;\r
748 \r
749 //      self.jump_pad = 0;\r
750         CapPlayerVelocity(self, self.speed);\r
751 \r
752 \r
753         if (!(self.flags & FL_ONGROUND))\r
754                 return;\r
755 \r
756         if (!(self.flags & FL_JUMPRELEASED))\r
757                 return;\r
758 \r
759         self.velocity_z = self.velocity_z + cvar("g_balance_jumpheight");\r
760 \r
761         self.flags = self.flags - FL_ONGROUND;\r
762         self.flags = self.flags - FL_JUMPRELEASED;\r
763 }\r
764 \r
765 .float watersound_finished;\r
766 void() WaterMove =\r
767 {\r
768         if (self.movetype == MOVETYPE_NOCLIP)\r
769                 return;\r
770         if (self.health < 0)\r
771                 return;\r
772 \r
773         if (self.waterlevel != 3)\r
774         {\r
775                 self.air_finished = time + 12;\r
776                 self.dmg = 2;\r
777         }\r
778         else if (self.air_finished < time)\r
779         {       // drown!\r
780                 if (self.pain_finished < time)\r
781                 {\r
782                         Damage (self, world, world, 5, DEATH_DROWN, self.origin, '0 0 0');\r
783                         self.pain_finished = time + 0.5;\r
784                 }\r
785         }\r
786 \r
787         if (!self.waterlevel)\r
788         {\r
789                 if (self.flags & FL_INWATER)\r
790                 {\r
791                         // play leave water sound\r
792                         self.flags = self.flags - FL_INWATER;\r
793                 }\r
794                 return;\r
795         }\r
796 \r
797         if (self.watersound_finished < time)\r
798         {\r
799                 self.watersound_finished = time + 0.5;\r
800                 if (self.watertype == CONTENT_LAVA)\r
801                         sound (self, CHAN_BODY, "player/lava.wav", 1, ATTN_NORM);\r
802                 if (self.watertype == CONTENT_SLIME)\r
803                         sound (self, CHAN_BODY, "player/slime.wav", 1, ATTN_NORM);\r
804                 //if (self.watertype == CONTENT_WATER)\r
805                 //      sound (self, CHAN_BODY, "player/water.wav", 1, ATTN_NORM);\r
806         }\r
807 \r
808         if (self.watertype == CONTENT_LAVA)\r
809         {       // do damage\r
810 \r
811                 // lava sets me to the maximum heat level, so I'll catch fire easily\r
812                 self.flame_heat = cvar("g_balance_maxheat");\r
813 \r
814                 if (self.dmgtime < time)\r
815                 {\r
816                         self.dmgtime = time + 0.1;\r
817                         Damage (self, world, world, 3 * self.waterlevel, DEATH_LAVA, self.origin, '0 0 0');\r
818                 }\r
819         }\r
820         else if (self.watertype == CONTENT_SLIME)\r
821         {       // do damage\r
822 \r
823                 // cool me off\r
824                 self.flame_heat = 0;\r
825 \r
826                 if (self.dmgtime < time)\r
827                 {\r
828                         self.dmgtime = time + 0.1;\r
829                         Damage (self, world, world, 1 * self.waterlevel, DEATH_SLIME, self.origin, '0 0 0');\r
830                 }\r
831         }\r
832         else if (self.watertype == CONTENT_WATER)\r
833         {\r
834                 // cool me off\r
835                 self.flame_heat = 0;\r
836         }\r
837 \r
838         if ( !(self.flags & FL_INWATER) )\r
839         {\r
840 \r
841                 //if (self.watertype == CONTENT_LAVA)\r
842                 //      sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);\r
843                 //if (self.watertype == CONTENT_WATER)\r
844                 //      sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);\r
845                 //if (self.watertype == CONTENT_SLIME)\r
846                 //      sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);\r
847 \r
848                 self.flags = self.flags + FL_INWATER;\r
849                 self.dmgtime = 0;\r
850         }\r
851 };\r
852 \r
853 void() CheckWaterJump =\r
854 {\r
855         local vector start, end;\r
856 \r
857 // check for a jump-out-of-water\r
858         makevectors (self.angles);\r
859         start = self.origin;\r
860         start_z = start_z + 8;\r
861         v_forward_z = 0;\r
862         normalize(v_forward);\r
863         end = start + v_forward*24;\r
864         traceline (start, end, TRUE, self);\r
865         if (trace_fraction < 1)\r
866         {       // solid at waist\r
867                 start_z = start_z + self.maxs_z - 8;\r
868                 end = start + v_forward*24;\r
869                 self.movedir = trace_plane_normal * -50;\r
870                 traceline (start, end, TRUE, self);\r
871                 if (trace_fraction == 1)\r
872                 {       // open at eye level\r
873                         self.flags = self.flags | FL_WATERJUMP;\r
874                         self.velocity_z = 225;\r
875                         self.flags = self.flags - (self.flags & FL_JUMPRELEASED);\r
876                         self.teleport_time = time + 2;  // safety net\r
877                         return;\r
878                 }\r
879         }\r
880 };\r
881 \r
882 \r
883 void respawn(void)\r
884 {\r
885         CopyBody(1);\r
886         PutClientInServer();\r
887 }\r
888 \r
889 void player_powerups (void)\r
890 {\r
891         self.effects = self.effects - (self.effects & (EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT));\r
892         if (self.items & IT_STRENGTH)\r
893         {\r
894                 self.effects = self.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);\r
895                 if (time > self.strength_finished)\r
896                 {\r
897                         self.items = self.items - (self.items & IT_STRENGTH);\r
898                         sprint(self, "^3Strength has worn off\n");\r
899                 }\r
900         }\r
901         else\r
902         {\r
903                 if (time < self.strength_finished)\r
904                 {\r
905                         self.items = self.items | IT_STRENGTH;\r
906                         sprint(self, "^3Strength infuses your weapons with devestating power\n");\r
907                 }\r
908         }\r
909         if (self.items & IT_INVINCIBLE)\r
910         {\r
911                 self.effects = self.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);\r
912                 if (time > self.invincible_finished)\r
913                 {\r
914                         self.items = self.items - (self.items & IT_INVINCIBLE);\r
915                         sprint(self, "^3Shield has worn off\n");\r
916                 }\r
917         }\r
918         else\r
919         {\r
920                 if (time < self.invincible_finished)\r
921                 {\r
922                         self.items = self.items | IT_INVINCIBLE;\r
923                         sprint(self, "^3Shield surrounds you\n");\r
924                 }\r
925         }\r
926 }\r
927 \r
928 void player_regen_health (float maxh, float regen_rate_mod)\r
929 {\r
930         if (self.health < maxh && time > self.health_regen_delay && self.health > 2)            // dont regen is HP is 2\r
931                 self.health = bound(0, self.health + regen_rate_mod*(maxh- self.health) * cvar("g_balance_health_regen") * frametime, 1000);\r
932 }\r
933 void player_rot_health (float maxh, float rot_rate_mod)\r
934 {\r
935         if (self.health > maxh && time > self.health_rot_delay)\r
936                 self.health = bound(0, self.health + rot_rate_mod*(maxh - self.health) * cvar("g_balance_health_rot") * frametime, 1000);\r
937 }\r
938 void player_regen_armor (float maxa, float regen_rate_mod)\r
939 {\r
940         if (self.armorvalue < maxa && time > self.armor_regen_delay)\r
941                 self.armorvalue = bound(0, self.armorvalue + regen_rate_mod*(maxa - self.armorvalue) * cvar("g_balance_armor_regen") * frametime, 1000);\r
942 }\r
943 void player_rot_armor (float maxa, float regen_rot_mod)\r
944 {\r
945         if (self.armorvalue > maxa && time > self.armor_rot_delay)\r
946                 self.armorvalue = bound(0, self.armorvalue + regen_rot_mod*(maxa - self.armorvalue) * cvar("g_balance_armor_rot") * frametime, 1000);\r
947 }\r
948 \r
949 void player_clearpoison(entity targ)\r
950 {\r
951         targ.poison_damage = targ.poison_rate = 0;\r
952 }\r
953 \r
954 void DelayHealthRegen(entity e) {       e.health_regen_delay = time + cvar("g_balance_regen_wait");}\r
955 void DelayHealthRot(entity e)   {       e.health_rot_delay = time + cvar("g_balance_rot_wait");}\r
956 void DelayArmorRegen(entity e)  {       e.armor_regen_delay = time + cvar("g_balance_regen_wait");}\r
957 void DelayArmorRot(entity e)    {       e.armor_rot_delay = time + cvar("g_balance_rot_wait");}\r
958 \r
959 \r
960 void player_takepoison()\r
961 {\r
962         float oldhealth, take;\r
963         if(self.health <= 5)\r
964         {\r
965                 player_clearpoison(self);\r
966                 return;\r
967         }\r
968         oldhealth = self.health;\r
969 \r
970         take = bound(0, self.poison_rate * frametime, self.health - 5);\r
971         if(take <= 0)\r
972         {\r
973                 player_clearpoison(self);\r
974                 return;\r
975         }\r
976 \r
977         DelayHealthRegen(self);\r
978         self.health = self.health - take;\r
979         self.poison_damage = self.poison_damage - take;\r
980 \r
981         if(self.health <= 5 || self.poison_damage <= 0)\r
982         {\r
983                 player_clearpoison(self);\r
984                 return;\r
985         }\r
986 }\r
987 \r
988 // cool off so you're not so vulnerable to fire\r
989 void player_cooloff ()\r
990 {\r
991         if(self.flame_heat_time > time)//heat up\r
992                 self.flame_heat = bound(0, self.flame_heat + self.flame_heat * cvar("g_balance_heatup_rate")  * frametime, cvar("g_balance_maxheat"));\r
993         else//cool off\r
994                 self.flame_heat = bound(0, self.flame_heat - self.flame_heat * cvar("g_balance_cooloff_rate") * frametime, cvar("g_balance_maxheat"));\r
995 }\r
996 \r
997 void player_regen (void)\r
998 {\r
999         local float maxh;\r
1000         local float maxa;\r
1001         maxh = self.max_health;//cvar("g_balance_health_stable");\r
1002         maxa = self.max_armor;//cvar("g_balance_armor_stable");\r
1003 \r
1004         if(self.poison_damage)\r
1005         {\r
1006                 player_takepoison();\r
1007                 return;\r
1008         }\r
1009 \r
1010         if(self.class == CLASS_SPY)\r
1011         {// don't let spy regenerate if cloaked, but do allow rot if above max\r
1012                 if(self.special_active)\r
1013                 {\r
1014                         //if(self.health > maxh)\r
1015                                 player_rot_health(maxh, 1.0);\r
1016                         //if(self.armorvalue > maxa)\r
1017                                 player_rot_armor(maxa, 1.0);\r
1018                 }\r
1019                 else\r
1020                 {\r
1021                         player_regen_health(maxh, 0.1); // spies regenerate slowly, and mostly rely on health packs\r
1022                         player_regen_armor(maxa, 1.0);\r
1023                         player_rot_health(maxh, 1.0);\r
1024                         player_rot_armor(maxa, 1.0);\r
1025                 }\r
1026         }\r
1027         else\r
1028         {\r
1029                 player_regen_health(maxh, 1.0);\r
1030                 player_regen_armor(maxa, 1.0);\r
1031                 player_rot_health(maxh, 1.0);\r
1032                 player_rot_armor(maxa, 1.0);\r
1033         }\r
1034 \r
1035         player_cooloff();\r
1036 }\r
1037 \r
1038 /*\r
1039 =============\r
1040 PlayerPreThink\r
1041 \r
1042 Called every frame for each client before the physics are run\r
1043 =============\r
1044 */\r
1045 .float attack_finished;\r
1046 void PlayerPreThink (void)\r
1047 {\r
1048         local vector m1, m2;\r
1049 \r
1050         CheckRules_Player();\r
1051 \r
1052         if (intermission_running)\r
1053         {\r
1054                 IntermissionThink ();   // otherwise a button could be missed between\r
1055                 return;                                 // the think tics\r
1056         }\r
1057 \r
1058         if (self.deadflag != DEAD_NO)\r
1059         {\r
1060                 player_anim();\r
1061                 weapon_freeze();\r
1062                 if (self.deadflag == DEAD_DYING)\r
1063                 {\r
1064                         if (time > self.dead_time)\r
1065                                 self.deadflag = DEAD_DEAD;\r
1066                 }\r
1067                 else if (self.deadflag == DEAD_DEAD)\r
1068                 {\r
1069                         if (!self.button0 && !self.button2 && !self.button3)\r
1070                                 self.deadflag = DEAD_RESPAWNABLE;\r
1071                 }\r
1072                 else if (self.deadflag == DEAD_RESPAWNABLE)\r
1073                 {\r
1074                         if (self.button0 || self.button2 || self.button3  || self.button4)\r
1075                                 respawn();\r
1076                 }\r
1077                 return;\r
1078         }\r
1079 \r
1080         if (self.button5)\r
1081         {\r
1082                 if (!self.crouch)\r
1083                 {\r
1084                         self.crouch = TRUE;\r
1085                         self.view_ofs = PL_CROUCH_VIEW_OFS;\r
1086                         setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX);\r
1087                 }\r
1088         }\r
1089         else\r
1090         {\r
1091                 if (self.crouch)\r
1092                 {\r
1093                         tracebox(self.origin, PL_MIN, PL_MAX, self.origin, FALSE, self);\r
1094                         if (!trace_startsolid)\r
1095                         {\r
1096                                 self.crouch = FALSE;\r
1097                                 self.view_ofs = PL_VIEW_OFS;\r
1098                                 setsize (self, PL_MIN, PL_MAX);\r
1099                         }\r
1100                 }\r
1101         }\r
1102 \r
1103         if (self.playermodel != self.mdl)\r
1104         {\r
1105                 //bprint("playermodel changed\n");\r
1106                 self.playermodel = CheckPlayerModel(self.playermodel);\r
1107                 if(CheckForClassChange()) // check if we'll allow it\r
1108                         return; // if there's a return value, drop what you're doing and let the player respawn\r
1109 \r
1110                 if(self.playermodel != self.mdl) // if change has been allowed\r
1111                 {\r
1112                         m1 = self.mins;\r
1113                         m2 = self.maxs;\r
1114                         precache_model (self.playermodel);\r
1115                         if(self.model != "")\r
1116                         {\r
1117                                 setmodel (self, self.playermodel);\r
1118                                 setsize (self, m1, m2);\r
1119                         }\r
1120                         self.mdl = strzone(self.playermodel);\r
1121                 }\r
1122         }\r
1123 \r
1124         ClassPreThink();\r
1125 \r
1126         if (self.skin != stof(self.playerskin))\r
1127                 self.skin = stof(self.playerskin);\r
1128 \r
1129         if(self.class == CLASS_SCOUT)\r
1130                 GrapplingHookFrame();\r
1131 \r
1132         W_WeaponFrame();\r
1133 \r
1134         if (self.button4 || (self.weapon == WEP_NEX && self.button3))\r
1135         {\r
1136                 if (self.viewzoom > 0.4)\r
1137                         self.viewzoom = max (0.4, self.viewzoom - frametime * 2);\r
1138         }\r
1139         else if (self.viewzoom < 1.0)\r
1140                 self.viewzoom = min (1.0, self.viewzoom + frametime);\r
1141 \r
1142 \r
1143         if (self.button2)\r
1144                 PlayerJump ();\r
1145         else\r
1146                 self.flags = self.flags | FL_JUMPRELEASED;\r
1147 \r
1148 \r
1149         player_powerups();\r
1150         player_regen();\r
1151         player_anim();\r
1152 \r
1153         //self.angles_y=self.v_angle_y + 90;   // temp\r
1154 \r
1155         WaterMove ();\r
1156         if (self.waterlevel == 2)\r
1157                 CheckWaterJump ();\r
1158 \r
1159         //if (TetrisPreFrame()) return;\r
1160 \r
1161         PlayerLasergatePreThink();\r
1162 }\r
1163 \r
1164 // Update weapon colors\r
1165 void UpdatePlayerColors () {\r
1166         if(self.weaponentity) {\r
1167                 self.weaponentity.colormap = self.colormap;\r
1168                 self.exteriorweaponentity.colormap = self.colormap;\r
1169         }\r
1170 }\r
1171 \r
1172 /*\r
1173 =============\r
1174 PlayerPostThink\r
1175 \r
1176 Called every frame for each client after the physics are run\r
1177 =============\r
1178 */\r
1179 void PlayerPostThink (void)\r
1180 {\r
1181         float soundrandom;\r
1182         CheckRules_Player();\r
1183         UpdateChatBubble();\r
1184         UpdateColorModHack();\r
1185         UpdateTeamBubble();\r
1186         UpdatePlayerColors();\r
1187         if (self.deadflag == DEAD_NO)\r
1188         if (self.impulse)\r
1189                 ImpulseCommands ();\r
1190         if (intermission_running)\r
1191                 return;         // intermission or finale\r
1192 \r
1193         // VorteX: landing on floor, landing damage etc.\r
1194         // LordHavoc: removed 'big fall' death code that VorteX added\r
1195         if (self.flags & FL_ONGROUND || (self.waterlevel >= 2 && self.velocity_z <= 0))\r
1196                         self.jump_pad = 0;\r
1197 \r
1198         if (self.flags & FL_ONGROUND)\r
1199         {\r
1200                 CapPlayerVelocity(self, self.speed);\r
1201 \r
1202                 if (self.jump_flag < -100 && !self.watertype == CONTENT_WATER) // HitGround\r
1203                 {\r
1204                         soundrandom = random() * 4;\r
1205 \r
1206                         self.air_time = time;           //temp BH var\r
1207 \r
1208                         if (soundrandom < 1)\r
1209                                 sound (self, CHAN_BODY, "misc/hitground1.wav", 1, ATTN_NORM);\r
1210                         else if (soundrandom < 2)\r
1211                                 sound (self, CHAN_BODY, "misc/hitground2.wav", 1, ATTN_NORM);\r
1212                         else if (soundrandom < 3)\r
1213                                 sound (self, CHAN_BODY, "misc/hitground3.wav", 1, ATTN_NORM);\r
1214                         else if (soundrandom < 4)\r
1215                                 sound (self, CHAN_BODY, "misc/hitground4.wav", 1, ATTN_NORM);\r
1216                         if (self.jump_flag < -650) // landing damage\r
1217                         {\r
1218                                 local float dm;\r
1219                                 dm = bound(0, 0.1*(fabs(self.jump_flag) - 600), 5);\r
1220                                 Damage (self, world, world, dm, DEATH_FALL, self.origin, '0 0 0');\r
1221                         }\r
1222                         self.jump_flag = 0;\r
1223                 }\r
1224         }\r
1225         else\r
1226                 self.jump_flag = self.velocity_z;\r
1227 \r
1228         ClassPostThink();\r
1229 \r
1230         //if (TetrisPostFrame()) return;\r
1231         PlayerLasergatePostThink();\r
1232 }\r
1233 \r