if (mutator_returnvalue) {
// mutator prevents resetting teams+score
} else {
+ int oldteam = this.team;
this.team = -1; // move this as it is needed to log the player spectating in eventlog
+ MUTATOR_CALLHOOK(Player_ChangedTeam, this, oldteam, this.team); // Lyberta: added hook
this.frags = FRAGS_SPECTATOR;
PlayerScore_Clear(this); // clear scores when needed
}
if(this.killindicator_teamchange)
ClientKill_Now_TeamChange(this);
- if(!IS_SPEC(this) && !IS_OBSERVER(this))
+ if (!IS_SPEC(this) && !IS_OBSERVER(this) && MUTATOR_CALLHOOK(ClientKill_Now, this) == false)
+ {
Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0');
+ }
// now I am sure the player IS dead
}
// If so, lets continue and finally move the player
client.team_forced = 0;
- MoveToTeam(client, team_id, 6);
- successful = strcat(successful, (successful ? ", " : ""), playername(client, false));
- LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") has been moved to the ", Team_ColoredFullName(team_id), "^7.\n");
+ if (MoveToTeam(client, team_id, 6))
+ {
+ successful = strcat(successful, (successful ? ", " : ""), playername(client, false));
+ LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") has been moved to the ", Team_ColoredFullName(team_id), "^7.\n");
+ }
+ else
+ {
+ LOG_INFO("Unable to move player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ")");
+ }
continue;
}
else
/**/
MUTATOR_HOOKABLE(CheckAllowedTeams, EV_CheckAllowedTeams);
+/** allows overriding best team */
+#define EV_JoinBestTeam(i, o) \
+ /** player checked */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** team number */ i(float, MUTATOR_ARGV_1_float) \
+ /**/ o(float, MUTATOR_ARGV_1_float) \
+ /**/
+MUTATOR_HOOKABLE(JoinBestTeam, EV_JoinBestTeam);
+
/** copies variables for spectating "spectatee" to "this" */
#define EV_SpectateCopy(i, o) \
/** spectatee */ i(entity, MUTATOR_ARGV_0_entity) \
/**/
MUTATOR_HOOKABLE(ClientKill, EV_ClientKill);
+/** called when player is about to be killed during kill command or changing teams */
+#define EV_ClientKill_Now(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(ClientKill_Now, EV_ClientKill_Now);
+
#define EV_FixClientCvars(i, o) \
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
/**/
/**/
MUTATOR_HOOKABLE(MonsterModel, EV_MonsterModel);
-/**/
+/**
+ * Called before player changes their team. Return true to block team change.
+ */
#define EV_Player_ChangeTeam(i, o) \
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
/** current team */ i(float, MUTATOR_ARGV_1_float) \
/**/
MUTATOR_HOOKABLE(Player_ChangeTeam, EV_Player_ChangeTeam);
+/**
+ * Called after player has changed their team.
+ */
+#define EV_Player_ChangedTeam(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** old team */ i(float, MUTATOR_ARGV_1_float) \
+ /** current team */ i(float, MUTATOR_ARGV_2_float) \
+ /**/
+MUTATOR_HOOKABLE(Player_ChangedTeam, EV_Player_ChangedTeam);
+
+/**
+ * Called when player is about to be killed when changing teams. Return true to block killing.
+ */
+#define EV_Player_ChangeTeamKill(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(Player_ChangeTeamKill, EV_Player_ChangeTeamKill);
+
/**/
#define EV_URI_GetCallback(i, o) \
/** id */ i(float, MUTATOR_ARGV_0_float) \
}
}
-void MoveToTeam(entity client, int team_colour, int type)
+bool MoveToTeam(entity client, int team_colour, int type)
{
int lockteams_backup = lockteams; // backup any team lock
lockteams = 0; // disable locked teams
TeamchangeFrags(client); // move the players frags
- SetPlayerColors(client, team_colour - 1); // set the players colour
+ if (!SetPlayerTeamSimple(client, team_colour))
+ {
+ return false;
+ }
Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0'); // kill the player
lockteams = lockteams_backup; // restore the team lock
LogTeamchange(client.playerid, client.team, type);
+ return true;
}
/** print(), but only print if the server is not local */
void ClientKill_Now_TeamChange(entity this);
-void MoveToTeam(entity client, float team_colour, float type);
+/// \brief Moves player to the specified team.
+/// \param[in,out] client Client to move.
+/// \param[in] team_colour Color of the team.
+/// \param[in] type ???
+/// \return True on success, false otherwise.
+bool MoveToTeam(entity client, float team_colour, float type);
void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
}
}
-void SetPlayerTeam(entity pl, float t, float s, float noprint)
+bool SetPlayerTeamSimple(entity player, int teamnum)
{
- float _color;
-
- if(t == 4)
- _color = NUM_TEAM_4 - 1;
- else if(t == 3)
- _color = NUM_TEAM_3 - 1;
- else if(t == 2)
- _color = NUM_TEAM_2 - 1;
- else
- _color = NUM_TEAM_1 - 1;
-
- SetPlayerColors(pl,_color);
-
- if(t != s) {
- LogTeamchange(pl.playerid, pl.team, 3); // log manual team join
-
- if(!noprint)
- bprint(playername(pl, false), "^7 has changed from ", Team_NumberToColoredFullName(s), "^7 to ", Team_NumberToColoredFullName(t), "\n");
+ if (player.team == teamnum)
+ {
+ return true;
}
+ if (MUTATOR_CALLHOOK(Player_ChangeTeam, player, Team_TeamToNumber(
+ player.team), Team_TeamToNumber(teamnum)) == true)
+ {
+ // Mutator has blocked team change.
+ return false;
+ }
+ int oldteam = player.team;
+ SetPlayerColors(player, teamnum - 1);
+ MUTATOR_CALLHOOK(Player_ChangedTeam, player, oldteam, player.team);
+ return true;
+}
+void SetPlayerTeam(entity pl, float t, float s, float noprint)
+{
+ if (t == s)
+ {
+ return;
+ }
+ float teamnum = Team_NumberToTeam(t);
+ SetPlayerTeamSimple(pl, teamnum);
+ LogTeamchange(pl.playerid, pl.team, 3); // log manual team join
+ if (noprint)
+ {
+ return;
+ }
+ bprint(playername(pl, false), "^7 has changed from ", Team_NumberToColoredFullName(s), "^7 to ", Team_NumberToColoredFullName(t), "\n");
}
// set c1...c4 to show what teams are allowed
int JoinBestTeam(entity this, bool only_return_best, bool forcebestteam)
{
- float smallest, selectedteam;
-
// don't join a team if we're not playing a team game
- if(!teamplay)
+ if (!teamplay)
+ {
return 0;
+ }
// find out what teams are available
CheckAllowedTeams(this);
+ float selectedteam;
+
// if we don't care what team he ends up on, put him on whatever team he entered as.
// if he's not on a valid team, then let other code put him on the smallest team
- if(!forcebestteam)
+ if (!forcebestteam)
{
if( c1 >= 0 && this.team == NUM_TEAM_1)
selectedteam = this.team;
else
selectedteam = -1;
- if(selectedteam > 0)
+ if (selectedteam > 0)
{
- if(!only_return_best)
+ if (!only_return_best)
{
- SetPlayerColors(this, selectedteam - 1);
+ SetPlayerTeamSimple(this, selectedteam);
// when JoinBestTeam is called by client.qc/ClientKill_Now_TeamChange the players team is -1 and thus skipped
// when JoinBestTeam is called by client.qc/ClientConnect the player_id is 0 the log attempt is rejected
// otherwise end up on the smallest team (handled below)
}
- smallest = FindSmallestTeam(this, true);
+ float bestteam = FindSmallestTeam(this, true);
+ MUTATOR_CALLHOOK(JoinBestTeam, this, bestteam);
+ bestteam = M_ARGV(1, float);
- if(!only_return_best && !this.bot_forced_team)
+ if (only_return_best || this.bot_forced_team)
+ {
+ return bestteam;
+ }
+ bestteam = Team_NumberToTeam(bestteam);
+ if (bestteam != -1)
{
TeamchangeFrags(this);
- if(smallest == 1)
- {
- SetPlayerColors(this, NUM_TEAM_1 - 1);
- }
- else if(smallest == 2)
- {
- SetPlayerColors(this, NUM_TEAM_2 - 1);
- }
- else if(smallest == 3)
- {
- SetPlayerColors(this, NUM_TEAM_3 - 1);
- }
- else if(smallest == 4)
- {
- SetPlayerColors(this, NUM_TEAM_4 - 1);
- }
- else
- {
- error("smallest team: invalid team\n");
- }
-
- LogTeamchange(this.playerid, this.team, 2); // log auto join
-
- if(!IS_DEAD(this))
- Damage(this, this, this, 100000, DEATH_TEAMCHANGE.m_id, this.origin, '0 0 0');
+ SetPlayerTeamSimple(this, bestteam);
}
-
- return smallest;
+ else
+ {
+ error("JoinBestTeam: invalid team\n");
+ }
+ LogTeamchange(this.playerid, this.team, 2); // log auto join
+ if (!IS_DEAD(this) && (MUTATOR_CALLHOOK(Player_ChangeTeamKill, this) ==
+ false))
+ {
+ Damage(this, this, this, 100000, DEATH_TEAMCHANGE.m_id, this.origin, '0 0 0');
+ }
+ return bestteam;
}
//void() ctf_playerchanged;
// not changing teams
if(scolor == dcolor)
{
- //bprint("same team change\n");
SetPlayerTeam(this, dteam, steam, true);
return;
}
TeamchangeFrags(this);
}
- MUTATOR_CALLHOOK(Player_ChangeTeam, this, steam, dteam);
-
SetPlayerTeam(this, dteam, steam, !IS_CLIENT(this));
- if(IS_PLAYER(this) && steam != dteam)
+ if(!IS_PLAYER(this) || (steam == dteam))
{
- // kill player when changing teams
- if(!IS_DEAD(this))
- Damage(this, this, this, 100000, DEATH_TEAMCHANGE.m_id, this.origin, '0 0 0');
+ return;
}
+ // kill player when changing teams
+ if(IS_DEAD(this) || (MUTATOR_CALLHOOK(Player_ChangeTeamKill, this) == true))
+ {
+ return;
+ }
+ Damage(this, this, this, 100000, DEATH_TEAMCHANGE.m_id, this.origin, '0 0 0');
}
void ShufflePlayerOutOfTeam (float source_team)
TeamchangeFrags(selected);
SetPlayerTeam(selected, smallestteam, source_team, false);
- if(!IS_DEAD(selected))
- Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE.m_id, selected.origin, '0 0 0');
+ if (IS_DEAD(selected) || MUTATOR_CALLHOOK(Player_ChangeTeamKill, selected) == true)
+ {
+ return;
+ }
+ Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE.m_id, selected.origin, '0 0 0');
Send_Notification(NOTIF_ONE, selected, MSG_CENTER, CENTER_DEATH_SELF_AUTOTEAMCHANGE, selected.team);
}
void SetPlayerColors(entity pl, float _color);
+/// \brief Sets the team of the player.
+/// \param[in,out] player Player to adjust.
+/// \param[in] teamnum Team number to set. See TEAM_NUM constants.
+/// \return True if team switch was successful, false otherwise.
+bool SetPlayerTeamSimple(entity player, int teamnum);
+
void SetPlayerTeam(entity pl, float t, float s, float noprint);
// set c1...c4 to show what teams are allowed