1 void info_player_start (void)
3 self.classname = "info_player_deathmatch";
6 void info_player_deathmatch (void)
10 float spawn_goodspots, spawn_badspots;
11 entity Spawn_ClassifyPoints(entity firstspot, entity playerlist, float mindist, float goodspotnum, float badspotnum)
13 local entity spot, player;
25 if (vlen(player.origin - spot.origin) < 100)
27 player = player.chain;
31 if (spawn_goodspots >= badspotnum)
33 spawn_badspots = spawn_badspots + 1;
37 if (spawn_goodspots >= goodspotnum)
39 spawn_goodspots = spawn_goodspots + 1;
41 spot = find(spot, classname, "info_player_deathmatch");
46 entity Spawn_FurthestPoint(entity firstspot, entity playerlist)
48 local entity best, spot, player;
49 local float bestrating, rating;
51 bestrating = -1000000;
60 rating = min(rating, vlen(player.origin - spot.origin));
61 player = player.chain;
63 rating = rating + random() * 16;
64 if (bestrating < rating)
69 spot = find(spot, classname, "info_player_deathmatch");
78 Finds a point to respawn
81 entity SelectSpawnPoint (float anypoint)
83 local entity spot, firstspot, playerlist;
86 spot = find (world, classname, "testplayerstart");
90 spotname = "info_player_deathmatch";
92 if(!anypoint && cvar("g_ctf") )
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";
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)
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)
115 spot = Spawn_ClassifyPoints(firstspot, playerlist, 100, min(floor(random() * spawn_goodspots), spawn_goodspots - 1), 1000000);
117 spot = Spawn_FurthestPoint(firstspot, playerlist);
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));
128 error ("PutClientInServer: no start points on level");
129 else // try again with deathmatch spots
130 spot = SelectSpawnPoint(TRUE);
140 Checks if the argument string can be a valid playermodel.
141 Returns a valid one in doubt.
144 string CheckPlayerModel(string plyermodel) {
145 if( substring(plyermodel,0,14) != "models/player/") plyermodel = "models/player/marine.zym";
147 /* Possible Fixme: Check if server can open the model?
148 This would kill custom models, however. */
157 putting a client as observer in the server
160 void PutObserverInServer (void)
163 spot = SelectSpawnPoint (FALSE);
164 RemoveGrapplingHook(self); // Wazat's Grappling Hook
166 self.classname = "observer";
168 self.takedamage = DAMAGE_NO;
169 self.solid = SOLID_NOT;
170 self.movetype = MOVETYPE_NOCLIP;
171 self.armorvalue = 666;
173 self.armorvalue = cvar("g_balance_armor_start");
174 self.pauserotarmor_finished = 0;
175 self.pauserothealth_finished = 0;
176 self.pauseregen_finished = 0;
177 self.damageforcescale = 0;
186 self.pain_finished = 0;
187 self.strength_finished = 0;
188 self.invincible_finished = 0;
190 self.vote_finished = 0;
191 self.think = SUB_Null;
195 self.deadflag = DEAD_NO;
196 self.angles = spot.angles;
198 self.fixangle = TRUE;
200 self.view_ofs = PL_VIEW_OFS;
201 setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24));
202 self.oldorigin = self.origin;
207 self.weaponmodel = "";
208 self.weaponframe = 0;
209 self.weaponentity = world;
210 self.killcount = -666;
212 //stuffcmd(self, "set viewsize 120 \n");
213 bprint (strcat("^4", self.netname, " is spectating now\n"));
221 Called when a client spawns in the server
224 void PutClientInServer (void)
226 if(self.classname == "player") {
229 spot = SelectSpawnPoint (FALSE);
231 RemoveGrapplingHook(self); // Wazat's Grappling Hook
233 self.classname = "player";
234 self.iscreature = TRUE;
235 self.movetype = MOVETYPE_WALK;
236 self.solid = SOLID_SLIDEBOX;
237 self.flags = FL_CLIENT;
238 self.takedamage = DAMAGE_AIM;
240 self.health = cvar("g_balance_health_start");
241 self.armorvalue = cvar("g_balance_armor_start");
242 self.pauserotarmor_finished = time + 10;
243 self.pauserothealth_finished = time + 10;
244 self.pauseregen_finished = 0;
245 self.damageforcescale = 2;
254 self.pain_finished = 0;
255 self.strength_finished = 0;
256 self.invincible_finished = 0;
258 //self.speed_finished = 0;
259 //self.slowmo_finished = 0;
260 self.vote_finished = 0;
261 // players have no think function
262 self.think = SUB_Null;
269 self.deadflag = DEAD_NO;
271 self.angles = spot.angles;
273 self.angles_z = 0; // never spawn tilted even if the spot says to
274 self.fixangle = TRUE; // turn this way immediately
275 self.velocity = '0 0 0';
276 self.avelocity = '0 0 0';
277 self.punchangle = '0 0 0';
278 self.punchvector = '0 0 0';
279 self.oldvelocity = self.velocity;
283 if(cvar("sv_defaultcharacter") == 1) {
284 local string defaultmodel;
285 defaultmodel = CheckPlayerModel(cvar_string("sv_defaultplayermodel"));
287 precache_model (defaultmodel);
288 setmodel (self, defaultmodel);
289 self.skin = stof(cvar_string("sv_defaultplayerskin"));
291 self.playermodel = CheckPlayerModel(self.playermodel);
293 precache_model (self.playermodel);
294 setmodel (self, self.playermodel);
295 self.skin = stof(self.playerskin);
300 self.view_ofs = PL_VIEW_OFS;
301 setsize (self, PL_MIN, PL_MAX);
302 setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24));
303 // don't reset back to last position, even if new position is stuck in solid
304 self.oldorigin = self.origin;
306 if (cvar("g_use_ammunition")) {
307 self.ammo_shells = cvar("g_start_ammo_shells");
308 self.ammo_nails = cvar("g_start_ammo_nails");
309 self.ammo_rockets = cvar("g_start_ammo_rockets");
310 self.ammo_cells = cvar("g_start_ammo_cells");
312 self.ammo_shells = 999;
313 self.ammo_nails = 999;
314 self.ammo_rockets = 999;
315 self.ammo_cells = 999;
319 if (cvar("g_start_weapon_laser"))
321 self.items = self.items | IT_LASER;
322 self.switchweapon = WEP_LASER;
324 if (cvar("g_start_weapon_shotgun"))
326 self.items = self.items | IT_SHOTGUN;
327 self.switchweapon = WEP_SHOTGUN;
329 if (cvar("g_start_weapon_uzi"))
331 self.items = self.items | IT_UZI;
332 self.switchweapon = WEP_UZI;
334 if (cvar("g_start_weapon_grenadelauncher"))
336 self.items = self.items | IT_GRENADE_LAUNCHER;
337 self.switchweapon = WEP_GRENADE_LAUNCHER;
339 if (cvar("g_start_weapon_electro"))
341 self.items = self.items | IT_ELECTRO;
342 self.switchweapon = WEP_ELECTRO;
344 if (cvar("g_start_weapon_crylink"))
346 self.items = self.items | IT_CRYLINK;
347 self.switchweapon = WEP_CRYLINK;
349 if (cvar("g_start_weapon_nex"))
351 self.items = self.items | IT_NEX;
352 self.switchweapon = WEP_NEX;
354 if (cvar("g_start_weapon_hagar"))
356 self.items = self.items | IT_HAGAR;
357 self.switchweapon = WEP_HAGAR;
359 if (cvar("g_start_weapon_rocketlauncher"))
361 self.items = self.items | IT_ROCKET_LAUNCHER;
362 self.switchweapon = WEP_ROCKET_LAUNCHER;
365 self.event_damage = PlayerDamage;
367 self.statdraintime = time + 5;
368 self.button0 = self.button1 = self.button2 = self.button3 = 0;
370 if(self.frags == -666 && self.killcount == -666) {
379 CL_SpawnWeaponentity();
381 //stuffcmd(self, "chase_active 0");
382 //stuffcmd(self, "set viewsize $tmpviewsize \n");
383 } else if(self.classname == "observer") {
384 PutObserverInServer ();
393 void SetNewParms (void)
403 void SetChangeParms (void)
412 Called when a client types 'kill' in the console
415 void ClientKill (void)
417 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
424 Called when a client connects to the server
427 string ColoredTeamName(float t);
428 //void dom_player_join_team(entity pl);
429 void ClientConnect (void)
431 self.classname = "player_joining";
433 //if(cvar("g_domination"))
434 // dom_player_join_team(self);
436 JoinBestTeam(self, FALSE);
438 if(cvar("sv_spectate") == 1) {
439 self.classname = "observer";
441 self.classname = "player";
444 //stuffcmd(self, "set tmpviewsize $viewsize \n");
446 bprint ("^4",self.netname);
447 bprint (" connected");
449 if(cvar("g_domination") || cvar("g_ctf"))
451 bprint(" and joined the ");
452 bprint(ColoredTeamName(self.team));
457 self.welcomemessage_time = time + cvar("welcome_message_time");
458 self.welcomemessage_time2 = 0;
460 stuffcmd(self, strcat("exec maps/", mapname, ".cfg\n"));
461 // send prediction settings to the client
462 stuffcmd(self, strcat("cl_movement_maxspeed ", ftos(cvar("sv_maxspeed")), "\n"));
463 stuffcmd(self, strcat("cl_movement_maxairspeed ", ftos(cvar("sv_maxairspeed")), "\n"));
464 stuffcmd(self, strcat("cl_movement_accelerate ", ftos(cvar("sv_accelerate")), "\n"));
465 stuffcmd(self, strcat("cl_movement_friction ", ftos(cvar("sv_friction")), "\n"));
466 stuffcmd(self, strcat("cl_movement_stopspeed ", ftos(cvar("sv_stopspeed")), "\n"));
467 stuffcmd(self, strcat("cl_movement_jumpvelocity ", ftos(cvar("g_balance_jumpheight")), "\n"));
468 stuffcmd(self, strcat("cl_movement_stepheight ", ftos(cvar("sv_stepheight")), "\n"));
469 stuffcmd(self, strcat("cl_movement_edgefriction 0\n"));
471 // Wazat's grappling hook
472 SetGrappleHookBindings();
474 // get autoswitch state from player
475 stuffcmd(self, "alias autoswitch \"set cl_autoswitch $1; cmd autoswitch $1\"\n");
476 stuffcmd(self, "cmd autoswitch $cl_autoswitch\n");
478 // get version info from player
479 stuffcmd(self, "cmd clientversion $g_nexuizversion\n");
486 Called when a client disconnects from the server
489 .entity chatbubbleentity;
490 void ClientDisconnect (void)
492 bprint ("^4",self.netname);
493 bprint (" disconnected\n");
495 if (self.chatbubbleentity)
497 remove (self.chatbubbleentity);
498 self.chatbubbleentity = world;
501 //stuffcmd(self, "set viewsize $tmpviewsize \n");
505 void() ChatBubbleThink =
507 self.nextthink = time;
508 if (!self.owner.modelindex || self.owner.chatbubbleentity != self)
513 setorigin(self, self.owner.origin + '0 0 15' + self.owner.maxs_z * '0 0 1');
514 if (self.owner.buttonchat && !self.owner.deadflag)
515 self.model = self.mdl;
520 void() UpdateChatBubble =
522 if (!self.modelindex)
524 // spawn a chatbubble entity if needed
525 if (!self.chatbubbleentity)
527 self.chatbubbleentity = spawn();
528 self.chatbubbleentity.owner = self;
529 self.chatbubbleentity.exteriormodeltoclient = self;
530 self.chatbubbleentity.think = ChatBubbleThink;
531 self.chatbubbleentity.nextthink = time;
532 setmodel(self.chatbubbleentity, "models/misc/chatbubble.spr");
533 setorigin(self.chatbubbleentity, self.origin + '0 0 15' + self.maxs_z * '0 0 1');
534 self.chatbubbleentity.mdl = self.chatbubbleentity.model;
535 self.chatbubbleentity.model = "";
539 // LordHavoc: this hack will be removed when proper _pants/_shirt layers are
540 // added to the model skins
541 /*void() UpdateColorModHack =
544 c = self.clientcolors & 15;
545 // LordHavoc: only bothering to support white, green, red, yellow, blue
546 if (teamplay == 0) self.colormod = '0 0 0';
547 else if (c == 0) self.colormod = '1.00 1.00 1.00';
548 else if (c == 3) self.colormod = '0.10 1.73 0.10';
549 else if (c == 4) self.colormod = '1.73 0.10 0.10';
550 else if (c == 12) self.colormod = '1.22 1.22 0.10';
551 else if (c == 13) self.colormod = '0.10 0.10 1.73';
552 else self.colormod = '1 1 1';
555 void UpdatePlayerColors () {
556 if(self.weaponentity) {
557 self.weaponentity.colormap = self.colormap;
558 self.exteriorweaponentity.colormap = self.colormap;
565 When you press the jump key
568 void PlayerJump (void)
572 mjumpheight = cvar("g_balance_jumpheight");
573 if (self.waterlevel >= 2)
575 if (self.watertype == CONTENT_WATER)
576 self.velocity_z = 200;
577 else if (self.watertype == CONTENT_SLIME)
578 self.velocity_z = 80;
580 self.velocity_z = 50;
586 if (!(self.flags & FL_ONGROUND))
589 if (!(self.flags & FL_JUMPRELEASED))
592 if(cvar("g_runematch"))
594 if(self.runes & RUNE_SPEED)
596 if(self.runes & CURSE_SLOW)
597 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_combo_jumpheight");
599 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_jumpheight");
601 else if(self.runes & CURSE_SLOW)
603 mjumpheight = mjumpheight * cvar("g_balance_curse_slow_jumpheight");
607 self.velocity_z = self.velocity_z + mjumpheight;
608 self.oldvelocity_z = self.velocity_z;
610 self.flags = self.flags - FL_ONGROUND;
611 self.flags = self.flags - FL_JUMPRELEASED;
614 void() CheckWaterJump =
616 local vector start, end;
618 // check for a jump-out-of-water
619 makevectors (self.angles);
621 start_z = start_z + 8;
623 normalize(v_forward);
624 end = start + v_forward*24;
625 traceline (start, end, TRUE, self);
626 if (trace_fraction < 1)
628 start_z = start_z + self.maxs_z - 8;
629 end = start + v_forward*24;
630 self.movedir = trace_plane_normal * -50;
631 traceline (start, end, TRUE, self);
632 if (trace_fraction == 1)
633 { // open at eye level
634 self.flags = self.flags | FL_WATERJUMP;
635 self.velocity_z = 225;
636 self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
637 self.teleport_time = time + 2; // safety net
650 void player_powerups (void)
652 self.effects = self.effects - (self.effects & (EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT));
653 if (self.items & IT_STRENGTH)
655 self.effects = self.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
656 if (time > self.strength_finished)
658 self.items = self.items - (self.items & IT_STRENGTH);
659 sprint(self, "^3Strength has worn off\n");
664 if (time < self.strength_finished)
666 self.items = self.items | IT_STRENGTH;
667 sprint(self, "^3Strength infuses your weapons with devestating power\n");
670 if (self.items & IT_INVINCIBLE)
672 self.effects = self.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
673 if (time > self.invincible_finished)
675 self.items = self.items - (self.items & IT_INVINCIBLE);
676 sprint(self, "^3Shield has worn off\n");
681 if (time < self.invincible_finished)
683 self.items = self.items | IT_INVINCIBLE;
684 sprint(self, "^3Shield surrounds you\n");
688 if (cvar("g_fullbrightplayers"))
689 self.effects = EF_FULLBRIGHT;
693 void player_regen (void)
695 float maxh, maxa, max_mod, regen_mod, rot_mod;
696 maxh = cvar("g_balance_health_stable");
697 maxa = cvar("g_balance_armor_stable");
699 if(cvar("g_runematch"))
701 max_mod = regen_mod = rot_mod = 1;
702 if (self.runes & RUNE_REGEN)
704 if (self.runes & CURSE_VENOM) // do we have both rune/curse?
706 regen_mod = cvar("g_balance_rune_regen_combo_regenrate");
707 max_mod = cvar("g_balance_rune_regen_combo_hpmod");
711 regen_mod = cvar("g_balance_rune_regen_regenrate");
712 max_mod = cvar("g_balance_rune_regen_hpmod");
715 else if (self.runes & CURSE_VENOM)
717 max_mod = cvar("g_balance_curse_venom_hpmod");
718 if (self.runes & RUNE_REGEN) // do we have both rune/curse?
719 rot_mod = cvar("g_balance_rune_regen_combo_rotrate");
721 rot_mod = cvar("g_balance_curse_venom_rotrate");
722 //if (!self.runes & RUNE_REGEN)
723 // rot_mod = cvar("g_balance_curse_venom_rotrate");
725 maxh = maxh * max_mod;
726 //maxa = maxa * max_mod;
728 if (time > self.pauserotarmor_finished)
730 if (self.armorvalue > maxa)
731 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_rot") * frametime, 1000);
733 if (time > self.pauserothealth_finished)
735 if (self.health > maxh)
736 self.health = bound(0, self.health + (maxh - self.health) * rot_mod*cvar("g_balance_health_rot") * frametime, 1000);
738 if (time > self.pauseregen_finished)
740 if (self.health < maxh)
741 self.health = bound(0, self.health + (maxh- self.health) * regen_mod*cvar("g_balance_health_regen") * frametime, 1000);
742 if (self.armorvalue < maxa)
743 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_regen") * frametime, 1000);
748 if (time > self.pauserothealth_finished)
749 if (self.health > maxh)
750 self.health = bound(0, self.health + (maxh - self.health) * cvar("g_balance_health_rot") * frametime, 1000);
751 if (time > self.pauserotarmor_finished)
752 if (self.armorvalue > maxa)
753 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_rot") * frametime, 1000);
754 if (time > self.pauseregen_finished)
756 if (self.health < maxh)
757 self.health = bound(0, self.health + (maxh- self.health) * cvar("g_balance_health_regen") * frametime, 1000);
758 if (self.armorvalue < maxa)
759 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_regen") * frametime, 1000);
765 ======================
766 spectate mode routines
767 ======================
769 void SpectateCopy(entity spectatee) {
770 self.armortype = spectatee.armortype;
771 self.armorvalue = spectatee.armorvalue;
772 self.currentammo = spectatee.currentammo;
773 self.effects = spectatee.effects;
774 self.health = spectatee.health;
776 self.items = spectatee.items;
777 self.punchangle = spectatee.punchangle;
778 self.view_ofs = spectatee.view_ofs;
779 self.v_angle = spectatee.v_angle;
780 self.viewzoom = spectatee.viewzoom;
781 setorigin(self, spectatee.origin);
782 setsize(self, spectatee.mins, spectatee.maxs);
785 void SpectateUpdate() {
786 if (self != self.enemy) {
787 SpectateCopy(self.enemy);
789 WriteByte(MSG_ONE, SVC_SETANGLE);
790 WriteAngle(MSG_ONE, self.enemy.v_angle_x);
791 WriteAngle(MSG_ONE, self.enemy.v_angle_y);
792 WriteAngle(MSG_ONE, self.enemy.v_angle_z);
796 float SpectateNext() {
797 other = find(self.enemy, classname, "player");
799 other = find(other, classname, "player");
804 if(self.enemy.classname == "player") {
806 WriteByte(MSG_ONE, SVC_SETVIEW);
807 WriteEntity(MSG_ONE, self.enemy);
808 //stuffcmd(self, "set viewsize $tmpviewsize \n");
820 Called every frame for each client before the physics are run
823 void PlayerPreThink (void)
825 if(self.classname == "player") {
830 // if(self.netname == "Wazat")
831 // bprint(strcat(self.classname, "\n"));
835 if (intermission_running)
837 IntermissionThink (); // otherwise a button could be missed between
838 return; // the think tics
841 if (self.deadflag != DEAD_NO)
845 if (self.deadflag == DEAD_DYING)
847 if (time > self.dead_time)
848 self.deadflag = DEAD_DEAD;
850 else if (self.deadflag == DEAD_DEAD)
852 if (!self.button0 && !self.button2 && !self.button3)
853 self.deadflag = DEAD_RESPAWNABLE;
855 else if (self.deadflag == DEAD_RESPAWNABLE)
857 if (self.button0 || self.button2 || self.button3 || self.button4)
868 self.view_ofs = PL_CROUCH_VIEW_OFS;
869 setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX);
876 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, FALSE, self);
877 if (!trace_startsolid)
880 self.view_ofs = PL_VIEW_OFS;
881 setsize (self, PL_MIN, PL_MAX);
886 if(cvar("sv_defaultcharacter") == 1) {
887 local string defaultmodel;
888 defaultmodel = CheckPlayerModel(cvar_string("sv_defaultplayermodel"));
890 if (defaultmodel != self.model)
894 precache_model (defaultmodel);
895 setmodel (self, defaultmodel);
896 setsize (self, m1, m2);
899 if (self.skin != stof(cvar_string("sv_defaultplayerskin")))
900 self.skin = stof(cvar_string("sv_defaultplayerskin"));
902 if (self.playermodel != self.model)
904 self.playermodel = CheckPlayerModel(self.playermodel);
907 precache_model (self.playermodel);
908 setmodel (self, self.playermodel);
909 setsize (self, m1, m2);
912 if (self.skin != stof(self.playerskin))
913 self.skin = stof(self.playerskin);
915 // Savage: Check for nameless players
916 if (strlen(self.netname) < 1) {
917 self.netname = "Player";
918 stuffcmd(self, "name Player\n");
921 GrapplingHookFrame();
925 if (self.button4 || (self.weapon == WEP_NEX && self.button3))
927 if (self.viewzoom > 0.4)
928 self.viewzoom = max (0.4, self.viewzoom - frametime * 2);
930 else if (self.viewzoom < 1.0)
931 self.viewzoom = min (1.0, self.viewzoom + frametime);
937 self.flags = self.flags | FL_JUMPRELEASED;
939 if (self.vote_finished > 0 // this player has called a vote
940 && time > self.vote_finished) // time is up
949 //self.angles_y=self.v_angle_y + 90; // temp
951 if (self.waterlevel == 2)
954 //if (TetrisPreFrame()) return;
955 } else if(self.classname == "observer") {
956 if (self.flags & FL_JUMPRELEASED) {
958 self.flags = self.flags & !FL_JUMPRELEASED;
959 self.classname = "player";
960 bprint (strcat("^4", self.netname, " is playing now\n"));
962 centerprint(self,"");
964 } else if(self.button0) {
965 self.flags = self.flags & !FL_JUMPRELEASED;
966 if(SpectateNext() == 1) {
967 self.classname = "spectator";
971 if (!(self.button0 || self.button2)) {
972 self.flags = self.flags | FL_JUMPRELEASED;
975 centerprint(self, strcat("\n", "\n", "\n", "press jump to play", "\n", "press attack to spectate other players"));
976 } else if(self.classname == "spectator") {
977 if (self.flags & FL_JUMPRELEASED) {
979 self.flags = self.flags & !FL_JUMPRELEASED;
980 if(SpectateNext() == 1) {
981 self.classname = "spectator";
983 self.classname = "observer";
985 WriteByte(MSG_ONE, SVC_SETVIEW);
986 WriteEntity(MSG_ONE, self);
989 } else if (self.button3) {
990 self.flags = self.flags & !FL_JUMPRELEASED;
991 self.classname = "observer";
993 WriteByte(MSG_ONE, SVC_SETVIEW);
994 WriteEntity(MSG_ONE, self);
1000 if (!(self.button0 || self.button3)) {
1001 self.flags = self.flags | FL_JUMPRELEASED;
1004 centerprint(self, strcat("spectating ", self.enemy.netname, "\n", "\n", "\n", "press attack for next player", "\n", "press attack2 for free fly mode"));
1013 Called every frame for each client after the physics are run
1016 void PlayerPostThink (void)
1018 if(self.classname == "player") {
1019 CheckRules_Player();
1021 UpdatePlayerColors();
1022 if (self.deadflag == DEAD_NO)
1025 if (intermission_running)
1026 return; // intermission or finale
1028 PrintWelcomeMessage(self);
1029 //if (TetrisPostFrame()) return;
1030 } else if (self.classname == "observer") {
1032 } else if (self.classname == "spectator") {