Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
clientkill.qc
Go to the documentation of this file.
1#include "clientkill.qh"
2
7#include <common/stats.qh>
8#include <common/stats.qh>
11#include <server/client.qh>
12#include <server/damage.qh>
14#include <server/player.qh>
16#include <server/teamplay.qh>
17
19{
20 if (this.killindicator_teamchange == -2)
21 {
23 // shouldn't get here because of condition in ClientCommand_spectate()
24 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
25 PutObserverInServer(this, false, true);
26 }
27 else
29
34}
35
37{
38 if (this.killindicator && !wasfreed(this.killindicator))
39 delete(this.killindicator);
40 this.killindicator = NULL;
41
42 // SetPlayerTeam() kills if team changes, (auto-)selecting the current team shouldn't kill.
43 if (this.killindicator_teamchange == -2 || this.killindicator_teamchange == 0)
44 if (IS_PLAYER(this) && !IS_DEAD(this))
45 Damage(this, this, this, INFINITY, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
46
49
50 // now I am sure the player IS dead
51}
53{
54 if (game_stopped || (this.owner.alpha < 0 && !this.owner.vehicle))
55 {
56 this.owner.killindicator = NULL;
57 delete(this);
58 return;
59 }
60
61 if (this.cnt <= 0)
62 {
64 return;
65 }
66
67 // count == 1 means that it's silent
68 if (this.count != 1)
69 {
70 if (this.cnt <= 10)
71 setmodel(this, MDL_NUM(this.cnt));
72 if (IS_REAL_CLIENT(this.owner))
73 {
74 if (this.cnt <= 10)
75 Send_Notification(NOTIF_ONE, this.owner, MSG_ANNCE, Announcer_PickNumber(CNT_KILL, this.cnt));
76 }
77 }
78 this.nextthink = time + 1;
79 --this.cnt;
80}
81
82.float lip;
84void ClientKill_TeamChange(entity this, float targetteam) // 0 = don't change, -1 = auto, -2 = spec
85{
86 if (game_stopped)
87 return;
88
89 float killtime = autocvar_g_balance_kill_delay;
90
91 if (MUTATOR_CALLHOOK(ClientKill, this, killtime))
92 return;
93 killtime = M_ARGV(1, float);
94
96 killtime = min(killtime, 1);
97
98 if (targetteam == -1)
99 {
100 if (this.team <= 0)
101 {
102 // Defer autoselect to Join(), after any queued players were joined, to avoid 2 players on same team
103 // when the first player(s) chose specific teams and the last player chose autoselect (they skip the queue).
104 this.team_selected = -1; // don't stop at ShowTeamSelection()
105 return;
106 }
107
108 /* Decide the team now because the "best" team could change during g_balance_kill_delay.
109 * This lets balancing code consider this player to be on the team they're about to change to,
110 * so we won't need to cancel the change after informing the player it's happening,
111 * and so we don't need to handle that in other code such as TeamBalance_QueuedPlayersTagIn().
112 * Also so we can notify immediately when already on a best team instead of counting down for nothing.
113 */
115 targetteam = Team_IndexToTeam(TeamBalance_FindBestTeam(balance, this, true));
116 TeamBalance_Destroy(balance);
117 if (targetteam == this.team)
118 {
119 if (this.clientkill_nexttime < time) // don't show conflicting/repeated notifs for legacy selectteam; join
120 {
121 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, APP_TEAM_NUM(this.team, INFO_TEAMCHANGE_ALREADYBEST));
122 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_TEAMCHANGE_ALREADYBEST));
123 }
124 return;
125 }
126 }
127 this.killindicator_teamchange = targetteam;
128
129 // this.killindicator.count == 1 means that the kill indicator was spawned by ClientKill_Silent
130 if(killtime <= 0 && this.killindicator && this.killindicator.count == 1)
131 {
132 ClientKill_Now(this); // allow instant kill in this case
133 return;
134 }
135
136 if (!this.killindicator)
137 {
138 if (!IS_DEAD(this))
139 {
140 killtime = max(killtime, this.clientkill_nexttime - time);
141 float antispam_delay = autocvar_g_balance_kill_antispam;
143 antispam_delay = min(antispam_delay, 2);
144 this.clientkill_nexttime = time + killtime + antispam_delay;
145 }
146
147 if (killtime <= 0 || !IS_PLAYER(this) || IS_DEAD(this))
148 {
149 ClientKill_Now(this);
150 }
151 else
152 {
153 float starttime = max(time, clientkilltime);
154
155 this.killindicator = new(killindicator);
156 this.killindicator.owner = this;
157 this.killindicator.scale = 0.5;
158 setattachment(this.killindicator, this, "");
159 setorigin(this.killindicator, '0 0 52');
161 this.killindicator.nextthink = starttime + (this.lip) * 0.05;
162 clientkilltime = max(clientkilltime, this.killindicator.nextthink + 0.05);
163 this.killindicator.cnt = ceil(killtime);
164 this.killindicator.count = bound(0, ceil(killtime), 10);
165 //sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n"));
166
167 IL_EACH(g_clones, it.enemy == this && !(it.effects & CSQCMODEL_EF_RESPAWNGHOST) && !it.killindicator,
168 {
169 it.killindicator = new(killindicator);
170 it.killindicator.owner = it;
171 it.killindicator.scale = 0.5;
172 setattachment(it.killindicator, it, "");
173 setorigin(it.killindicator, '0 0 52');
174 setthink(it.killindicator, KillIndicator_Think);
175 it.killindicator.nextthink = starttime + (it.lip) * 0.05;
176 //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
177 it.killindicator.cnt = ceil(killtime);
178 });
179 this.lip = 0;
180 }
181 }
182 if (this.killindicator)
183 {
184 Notification notif;
185 if (targetteam == 0) // just die
186 {
187 this.killindicator.colormod = '0 0 0';
188 notif = CENTER_TEAMCHANGE_SUICIDE;
189 }
190 else if (targetteam == -2) // spectate
191 {
192 this.killindicator.colormod = '0.5 0.5 0.5';
193 notif = CENTER_TEAMCHANGE_SPECTATE;
194 }
195 else
196 {
197 this.killindicator.colormod = Team_ColorRGB(targetteam);
198 notif = APP_TEAM_NUM(targetteam, CENTER_TEAMCHANGE);
199 }
200 if (IS_REAL_CLIENT(this) && this.killindicator.cnt > 0)
201 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, notif, this.killindicator.cnt);
202 }
203}
204
205void ClientKill_Silent(entity this, float _delay)
206{
207 // overrides queued silent killindicators
208 if (!this.killindicator || this.killindicator.count != 1)
209 this.killindicator = new(killindicator);
210 this.killindicator.owner = this;
212 this.killindicator.nextthink = time + (this.lip) * 0.05;
213 this.killindicator.cnt = ceil(_delay);
214 this.killindicator.count = 1; // this is used to indicate that it should be silent
215 this.lip = 0;
216}
217
218// Called when a client types 'kill' in the console
220{
221 if (game_stopped || this.player_blocked)
222 return;
223
224 ClientKill_TeamChange(this, 0);
225}
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float cnt
Definition powerups.qc:24
float count
Definition powerups.qc:22
entity owner
Definition main.qh:87
int team
Definition main.qh:188
void KillIndicator_Think(entity this)
Definition clientkill.qc:52
float clientkilltime
Definition clientkill.qc:83
void ClientKill_Now(entity this)
Definition clientkill.qc:36
void ClientKill_Silent(entity this, float _delay)
void ClientKill_TeamChange(entity this, float targetteam)
Definition clientkill.qc:84
void ClientKill_Now_TeamChange(entity this)
Definition clientkill.qc:18
float clientkill_nexttime
Definition clientkill.qh:9
int killindicator_teamchange
Definition clientkill.qh:8
entity killindicator
Definition clientkill.qh:7
float autocvar_g_balance_kill_delay
Definition clientkill.qh:3
float autocvar_g_balance_kill_antispam
Definition clientkill.qh:4
#define setmodel(this, m)
Definition model.qh:26
#define M_ARGV(x, type)
Definition events.qh:17
#define IS_DEAD(s)
Definition player.qh:244
#define IS_PLAYER(s)
Definition player.qh:242
float game_stopped
Definition stats.qh:81
Notification Announcer_PickNumber(int type, int num)
Definition util.qc:1936
const int CNT_KILL
Definition util.qh:256
float time
float nextthink
#define CSQCMODEL_EF_RESPAWNGHOST
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:484
#define DMG_NOWEP
Definition damage.qh:104
#define IL_EACH(this, cond, body)
#define ClientKill
Definition _all.inc:254
#define INFINITY
Definition mathlib.qh:105
float ceil(float f)
float bound(float min, float value, float max)
float min(float f,...)
float max(float f,...)
Model MDL_NUM(int i)
Definition all.inc:229
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1500
entity Notification
always last
Definition all.qh:85
#define APP_TEAM_NUM(num, prefix)
Definition all.qh:88
#define NULL
Definition post.qh:14
#define round_handler_IsActive()
#define round_handler_IsRoundStarted()
#define setthink(e, f)
void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
putting a client as observer in the server
Definition client.qc:261
bool player_blocked
Definition client.qh:332
bool autocvar_sv_spectate
Definition client.qh:57
int team_selected
Definition client.qh:75
float autocvar_g_maxplayers_spectator_blocktime
Definition client.qh:45
IntrusiveList g_clones
Definition player.qh:45
float lip
Definition subs.qh:40
bool TeamBalance_QueuedPlayersTagIn(entity ignore)
Joins queued player(s) to team(s) with a shortage, this should be more robust than only replacing the...
Definition teamplay.qc:694
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:528
void TeamBalance_RemoveExcessPlayers(entity ignore)
Definition teamplay.qc:631
bool SetPlayerTeam(entity player, int team_index, int type)
Sets the team of the player.
Definition teamplay.qc:286
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:424
int TeamBalance_FindBestTeam(entity balance, entity player, bool ignore_player)
Finds the team that will make the game most balanced if the player joins it.
Definition teamplay.qc:892
bool autocvar_g_balance_teams_remove
Definition teamplay.qh:10
@ TEAM_CHANGE_MANUAL
Player has manually selected their team.
Definition teamplay.qh:130
vector Team_ColorRGB(int teamid)
Definition teams.qh:76
int Team_TeamToIndex(int team_num)
Converts team value into team index.
Definition teams.qh:184
int Team_IndexToTeam(int index)
Converts team index into team value.
Definition teams.qh:169
#define IS_REAL_CLIENT(v)
Definition utils.qh:17