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.vehicle)
39 {
42 {
43 this.vehicle_health = -1;
44 Damage(this, this, this, 1 , DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
45 }
46 }
47
48 if (this.killindicator && !wasfreed(this.killindicator))
49 delete(this.killindicator);
50
51 this.killindicator = NULL;
52
55 // SetPlayerTeam() already killed if team changed, auto-selecting the current team shouldn't kill.
56 else if (!IS_SPEC(this) && !IS_OBSERVER(this) && MUTATOR_CALLHOOK(ClientKill_Now, this) == false)
57 Damage(this, this, this, 100000, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
58
59 // now I am sure the player IS dead
60}
62{
63 if (game_stopped || (this.owner.alpha < 0 && !this.owner.vehicle))
64 {
65 this.owner.killindicator = NULL;
66 delete(this);
67 return;
68 }
69
70 if (this.cnt <= 0)
71 {
73 return;
74 }
75
76 // count == 1 means that it's silent
77 if (this.count != 1)
78 {
79 if (this.cnt <= 10)
80 setmodel(this, MDL_NUM(this.cnt));
81 if (IS_REAL_CLIENT(this.owner))
82 {
83 if (this.cnt <= 10)
84 Send_Notification(NOTIF_ONE, this.owner, MSG_ANNCE, Announcer_PickNumber(CNT_KILL, this.cnt));
85 }
86 }
87 this.nextthink = time + 1;
88 --this.cnt;
89}
90
91.float lip;
94void ClientKill_TeamChange(entity this, float targetteam) // 0 = don't change, -1 = auto, -2 = spec
95{
96 if (game_stopped)
97 return;
98
99 float killtime = autocvar_g_balance_kill_delay;
100
101 if (MUTATOR_CALLHOOK(ClientKill, this, killtime))
102 return;
103 killtime = M_ARGV(1, float);
104
106 killtime = min(killtime, 1);
107
108 if (targetteam == -1)
109 {
110 if (this.team <= 0)
111 {
112 // Defer autoselect to Join(), after any queued players were joined, to avoid 2 players on same team
113 // when the first player(s) chose specific teams and the last player chose autoselect (they skip the queue).
114 this.team_selected = -1; // don't stop at ShowTeamSelection()
115 return;
116 }
117
118 /* Decide the team now because the "best" team could change during g_balance_kill_delay.
119 * This lets balancing code consider this player to be on the team they're about to change to,
120 * so we won't need to cancel the change after informing the player it's happening,
121 * and so we don't need to handle that in other code such as TeamBalance_QueuedPlayersTagIn().
122 * Also so we can notify immediately when already on a best team instead of counting down for nothing.
123 */
125 targetteam = Team_IndexToTeam(TeamBalance_FindBestTeam(balance, this, true));
126 TeamBalance_Destroy(balance);
127 if (targetteam == this.team)
128 {
129 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_ALREADYBEST);
130 return;
131 }
132 }
133 this.killindicator_teamchange = targetteam;
134
135 // this.killindicator.count == 1 means that the kill indicator was spawned by ClientKill_Silent
136 if(killtime <= 0 && this.killindicator && this.killindicator.count == 1)
137 {
138 ClientKill_Now(this); // allow instant kill in this case
139 return;
140 }
141
142 if (!this.killindicator)
143 {
144 if (!IS_DEAD(this))
145 {
146 killtime = max(killtime, this.clientkill_nexttime - time);
147 float antispam_delay = autocvar_g_balance_kill_antispam;
149 antispam_delay = min(antispam_delay, 2);
150 this.clientkill_nexttime = time + killtime + antispam_delay;
151 }
152
153 if (killtime <= 0 || !IS_PLAYER(this) || IS_DEAD(this))
154 {
155 ClientKill_Now(this);
156 }
157 else
158 {
159 float starttime = max(time, clientkilltime);
160
161 this.killindicator = new(killindicator);
162 this.killindicator.owner = this;
163 this.killindicator.scale = 0.5;
164 setattachment(this.killindicator, this, "");
165 setorigin(this.killindicator, '0 0 52');
167 this.killindicator.nextthink = starttime + (this.lip) * 0.05;
168 clientkilltime = max(clientkilltime, this.killindicator.nextthink + 0.05);
169 this.killindicator.cnt = ceil(killtime);
170 this.killindicator.count = bound(0, ceil(killtime), 10);
171 //sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n"));
172
173 IL_EACH(g_clones, it.enemy == this && !(it.effects & CSQCMODEL_EF_RESPAWNGHOST) && !it.killindicator,
174 {
175 it.killindicator = new(killindicator);
176 it.killindicator.owner = it;
177 it.killindicator.scale = 0.5;
178 setattachment(it.killindicator, it, "");
179 setorigin(it.killindicator, '0 0 52');
180 setthink(it.killindicator, KillIndicator_Think);
181 it.killindicator.nextthink = starttime + (it.lip) * 0.05;
182 //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
183 it.killindicator.cnt = ceil(killtime);
184 });
185 this.lip = 0;
186 }
187 }
188 if (this.killindicator)
189 {
190 Notification notif;
191 if (targetteam == 0) // just die
192 {
193 this.killindicator.colormod = '0 0 0';
194 notif = CENTER_TEAMCHANGE_SUICIDE;
195 }
196 else if (targetteam == -2) // spectate
197 {
198 this.killindicator.colormod = '0.5 0.5 0.5';
199 notif = CENTER_TEAMCHANGE_SPECTATE;
200 }
201 else
202 {
203 this.killindicator.colormod = Team_ColorRGB(targetteam);
204 notif = APP_TEAM_NUM(targetteam, CENTER_TEAMCHANGE);
205 }
206 if (IS_REAL_CLIENT(this) && this.killindicator.cnt > 0)
207 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, notif, this.killindicator.cnt);
208 }
209
210}
211
212void ClientKill_Silent(entity this, float _delay)
213{
214 // overrides queued silent killindicators
215 if (!this.killindicator || this.killindicator.count != 1)
216 this.killindicator = new(killindicator);
217 this.killindicator.owner = this;
219 this.killindicator.nextthink = time + (this.lip) * 0.05;
220 this.killindicator.cnt = ceil(_delay);
221 this.killindicator.count = 1; // this is used to indicate that it should be silent
222 this.lip = 0;
223}
224
225// Called when a client types 'kill' in the console
227{
228 if (game_stopped || this.player_blocked)
229 return;
230
231 ClientKill_TeamChange(this, 0);
232}
#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:61
float clientkill_nexttime
Definition clientkill.qc:93
float clientkilltime
Definition clientkill.qc:92
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:94
void ClientKill_Now_TeamChange(entity this)
Definition clientkill.qc:18
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:1924
const int CNT_KILL
Definition util.qh:254
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:493
#define DMG_NOWEP
Definition damage.qh:104
#define IL_EACH(this, cond, body)
#define ClientKill
Definition _all.inc:254
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
void vehicles_exit(entity vehic, bool eject)
const float vehicle_health
If ent is player this is 0..100 indicating precentage of health left on vehicle. Vehicle's value is t...
const int VHEF_RELEASE
Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (n...
entity vehicle
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:763
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:597
void TeamBalance_RemoveExcessPlayers(entity ignore)
Definition teamplay.qc:700
bool SetPlayerTeam(entity player, int team_index, int type)
Sets the team of the player.
Definition teamplay.qc:284
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:488
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:962
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_OBSERVER(v)
Definition utils.qh:11
#define IS_SPEC(v)
Definition utils.qh:10
#define IS_REAL_CLIENT(v)
Definition utils.qh:17