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. */
158 Called when a client spawns in the server
161 void PutClientInServer (void)
165 spot = SelectSpawnPoint (FALSE);
167 RemoveGrapplingHook(self); // Wazat's Grappling Hook
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;
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;
190 self.pain_finished = 0;
191 self.strength_finished = 0;
192 self.invincible_finished = 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;
205 self.deadflag = DEAD_NO;
207 self.angles = spot.angles;
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;
220 self.playermodel = CheckPlayerModel(self.playermodel);
222 precache_model (self.playermodel);
223 setmodel (self, self.playermodel);
224 self.skin = stof(self.playerskin);
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;
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");
238 self.ammo_shells = 999;
239 self.ammo_nails = 999;
240 self.ammo_rockets = 999;
241 self.ammo_cells = 999;
245 if (cvar("g_start_weapon_laser"))
247 self.items = self.items | IT_LASER;
248 self.switchweapon = WEP_LASER;
250 if (cvar("g_start_weapon_shotgun"))
252 self.items = self.items | IT_SHOTGUN;
253 self.switchweapon = WEP_SHOTGUN;
255 if (cvar("g_start_weapon_uzi"))
257 self.items = self.items | IT_UZI;
258 self.switchweapon = WEP_UZI;
260 if (cvar("g_start_weapon_grenadelauncher"))
262 self.items = self.items | IT_GRENADE_LAUNCHER;
263 self.switchweapon = WEP_GRENADE_LAUNCHER;
265 if (cvar("g_start_weapon_electro"))
267 self.items = self.items | IT_ELECTRO;
268 self.switchweapon = WEP_ELECTRO;
270 if (cvar("g_start_weapon_crylink"))
272 self.items = self.items | IT_CRYLINK;
273 self.switchweapon = WEP_CRYLINK;
275 if (cvar("g_start_weapon_nex"))
277 self.items = self.items | IT_NEX;
278 self.switchweapon = WEP_NEX;
280 if (cvar("g_start_weapon_hagar"))
282 self.items = self.items | IT_HAGAR;
283 self.switchweapon = WEP_HAGAR;
285 if (cvar("g_start_weapon_rocketlauncher"))
287 self.items = self.items | IT_ROCKET_LAUNCHER;
288 self.switchweapon = WEP_ROCKET_LAUNCHER;
291 self.event_damage = PlayerDamage;
293 self.statdraintime = time + 5;
294 self.button0 = self.button1 = self.button2 = self.button3 = 0;
300 CL_SpawnWeaponentity();
302 //stuffcmd(self, "chase_active 0");
310 void SetNewParms (void)
320 void SetChangeParms (void)
329 Called when a client types 'kill' in the console
332 void ClientKill (void)
334 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
341 Called when a client connects to the server
344 string ColoredTeamName(float t);
345 //void dom_player_join_team(entity pl);
346 void ClientConnect (void)
348 self.classname = "player_joining";
350 //if(cvar("g_domination"))
351 // dom_player_join_team(self);
353 JoinBestTeam(self, FALSE);
355 self.classname = "player";
359 bprint ("^4",self.netname);
360 bprint (" connected");
362 if(cvar("g_domination") || cvar("g_ctf"))
364 bprint(" and joined the ");
365 bprint(ColoredTeamName(self.team));
370 self.welcomemessage_time = time + cvar("welcome_message_time");
371 self.welcomemessage_time2 = 0;
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"));
385 // Wazat's grappling hook
386 SetGrappleHookBindings();
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");
392 // get version info from player
393 stuffcmd(self, "cmd clientversion $g_nexuizversion\n");
400 Called when a client disconnects from the server
403 .entity chatbubbleentity;
404 void ClientDisconnect (void)
406 bprint ("^4",self.netname);
407 bprint (" disconnected\n");
409 if (self.chatbubbleentity)
411 remove (self.chatbubbleentity);
412 self.chatbubbleentity = world;
418 void() ChatBubbleThink =
420 self.nextthink = time;
421 if (!self.owner.modelindex || self.owner.chatbubbleentity != self)
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;
433 void() UpdateChatBubble =
435 if (!self.modelindex)
437 // spawn a chatbubble entity if needed
438 if (!self.chatbubbleentity)
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 = "";
452 // LordHavoc: this hack will be removed when proper _pants/_shirt layers are
453 // added to the model skins
454 void() UpdateColorModHack =
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';
472 When you press the jump key
475 void PlayerJump (void)
479 mjumpheight = cvar("g_balance_jumpheight");
480 if (self.waterlevel >= 2)
482 if (self.watertype == CONTENT_WATER)
483 self.velocity_z = 200;
484 else if (self.watertype == CONTENT_SLIME)
485 self.velocity_z = 80;
487 self.velocity_z = 50;
493 if (!(self.flags & FL_ONGROUND))
496 if (!(self.flags & FL_JUMPRELEASED))
499 if(cvar("g_runematch"))
501 if(self.runes & RUNE_SPEED)
503 if(self.runes & CURSE_SLOW)
504 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_combo_jumpheight");
506 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_jumpheight");
508 else if(self.runes & CURSE_SLOW)
510 mjumpheight = mjumpheight * cvar("g_balance_curse_slow_jumpheight");
514 self.velocity_z = self.velocity_z + mjumpheight;
515 self.oldvelocity_z = self.velocity_z;
517 self.flags = self.flags - FL_ONGROUND;
518 self.flags = self.flags - FL_JUMPRELEASED;
521 void() CheckWaterJump =
523 local vector start, end;
525 // check for a jump-out-of-water
526 makevectors (self.angles);
528 start_z = start_z + 8;
530 normalize(v_forward);
531 end = start + v_forward*24;
532 traceline (start, end, TRUE, self);
533 if (trace_fraction < 1)
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
557 void player_powerups (void)
559 self.effects = self.effects - (self.effects & (EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT));
560 if (self.items & IT_STRENGTH)
562 self.effects = self.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
563 if (time > self.strength_finished)
565 self.items = self.items - (self.items & IT_STRENGTH);
566 sprint(self, "^3Strength has worn off\n");
571 if (time < self.strength_finished)
573 self.items = self.items | IT_STRENGTH;
574 sprint(self, "^3Strength infuses your weapons with devestating power\n");
577 if (self.items & IT_INVINCIBLE)
579 self.effects = self.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
580 if (time > self.invincible_finished)
582 self.items = self.items - (self.items & IT_INVINCIBLE);
583 sprint(self, "^3Shield has worn off\n");
588 if (time < self.invincible_finished)
590 self.items = self.items | IT_INVINCIBLE;
591 sprint(self, "^3Shield surrounds you\n");
595 if (cvar("g_fullbrightplayers"))
596 self.effects = EF_FULLBRIGHT;
600 void player_regen (void)
602 float maxh, maxa, max_mod, regen_mod, rot_mod;
603 maxh = cvar("g_balance_health_stable");
604 maxa = cvar("g_balance_armor_stable");
606 if(cvar("g_runematch"))
608 max_mod = regen_mod = rot_mod = 1;
609 if (self.runes & RUNE_REGEN)
611 if (self.runes & CURSE_VENOM) // do we have both rune/curse?
613 regen_mod = cvar("g_balance_rune_regen_combo_regenrate");
614 max_mod = cvar("g_balance_rune_regen_combo_hpmod");
618 regen_mod = cvar("g_balance_rune_regen_regenrate");
619 max_mod = cvar("g_balance_rune_regen_hpmod");
622 else if (self.runes & CURSE_VENOM)
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");
628 rot_mod = cvar("g_balance_curse_venom_rotrate");
629 //if (!self.runes & RUNE_REGEN)
630 // rot_mod = cvar("g_balance_curse_venom_rotrate");
632 maxh = maxh * max_mod;
633 //maxa = maxa * max_mod;
635 if (time > self.pauserotarmor_finished)
637 if (self.armorvalue > maxa)
638 self.armorvalue = bound(0, self.armorvalue + (maxa - self.armorvalue) * cvar("g_balance_armor_rot") * frametime, 1000);
640 if (time > self.pauserothealth_finished)
642 if (self.health > maxh)
643 self.health = bound(0, self.health + (maxh - self.health) * rot_mod*cvar("g_balance_health_rot") * frametime, 1000);
645 if (time > self.pauseregen_finished)
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);
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)
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);
675 Called every frame for each client before the physics are run
678 void PlayerPreThink (void)
684 // if(self.netname == "Wazat")
685 // bprint(strcat(self.classname, "\n"));
689 if (intermission_running)
691 IntermissionThink (); // otherwise a button could be missed between
692 return; // the think tics
695 if (self.deadflag != DEAD_NO)
699 if (self.deadflag == DEAD_DYING)
701 if (time > self.dead_time)
702 self.deadflag = DEAD_DEAD;
704 else if (self.deadflag == DEAD_DEAD)
706 if (!self.button0 && !self.button2 && !self.button3)
707 self.deadflag = DEAD_RESPAWNABLE;
709 else if (self.deadflag == DEAD_RESPAWNABLE)
711 if (self.button0 || self.button2 || self.button3 || self.button4)
722 self.view_ofs = PL_CROUCH_VIEW_OFS;
723 setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX);
730 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, FALSE, self);
731 if (!trace_startsolid)
734 self.view_ofs = PL_VIEW_OFS;
735 setsize (self, PL_MIN, PL_MAX);
740 if (self.playermodel != self.model)
742 self.playermodel = CheckPlayerModel(self.playermodel);
745 precache_model (self.playermodel);
746 setmodel (self, self.playermodel);
747 setsize (self, m1, m2);
750 // Savage: Check for nameless players
751 if (strlen(self.netname) < 1) {
752 self.netname = "Player";
753 stuffcmd(self, "name Player\n");
756 if (self.skin != stof(self.playerskin))
757 self.skin = stof(self.playerskin);
759 GrapplingHookFrame();
763 if (self.button4 || (self.weapon == WEP_NEX && self.button3))
765 if (self.viewzoom > 0.4)
766 self.viewzoom = max (0.4, self.viewzoom - frametime * 2);
768 else if (self.viewzoom < 1.0)
769 self.viewzoom = min (1.0, self.viewzoom + frametime);
775 self.flags = self.flags | FL_JUMPRELEASED;
777 if (self.vote_finished > 0 // this player has called a vote
778 && time > self.vote_finished) // time is up
787 //self.angles_y=self.v_angle_y + 90; // temp
789 if (self.waterlevel == 2)
792 //if (TetrisPreFrame()) return;
799 Called every frame for each client after the physics are run
802 void PlayerPostThink (void)
806 UpdateColorModHack();
807 if (self.deadflag == DEAD_NO)
810 if (intermission_running)
811 return; // intermission or finale
813 PrintWelcomeMessage(self);
814 //if (TetrisPostFrame()) return;