]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/clientkill.qc
Transifex autosync
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / clientkill.qc
1 #include "clientkill.qh"
2
3 #include <common/csqcmodel_settings.qh>
4 #include <common/deathtypes/all.qh>
5 #include <common/mapobjects/triggers.qh>
6 #include <common/notifications/all.qh>
7 #include <common/stats.qh>
8 #include <common/stats.qh>
9 #include <common/vehicles/sv_vehicles.qh>
10 #include <common/weapons/_all.qh>
11 #include <server/client.qh>
12 #include <server/damage.qh>
13 #include <server/mutators/_mod.qh>
14 #include <server/player.qh>
15 #include <server/round_handler.qh>
16 #include <server/teamplay.qh>
17
18 void ClientKill_Now_TeamChange(entity this)
19 {
20         if (this.killindicator_teamchange == -1)
21         {
22                 TeamBalance_JoinBestTeam(this);
23         }
24         else if (this.killindicator_teamchange == -2)
25         {
26                 if (blockSpectators)
27                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
28
29                 if (this.wants_join)
30                 {
31                         this.wants_join = 0;
32                         this.team_selected = false;
33                         Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_QUEUE, this.netname);
34                         SetPlayerTeam(this, -1, TEAM_CHANGE_SPECTATOR);
35                 }
36                 else
37                 {
38                         PutObserverInServer(this, false, true);
39                         if (!TeamBalance_QueuedPlayersTagIn(this))
40                         if (autocvar_g_balance_teams_remove)
41                                 TeamBalance_RemoveExcessPlayers(this);
42                 }
43         }
44         else
45         {
46                 Player_SetTeamIndexChecked(this, Team_TeamToIndex(
47                         this.killindicator_teamchange));
48         }
49         this.killindicator_teamchange = 0;
50 }
51
52 void ClientKill_Now(entity this)
53 {
54         if (this.vehicle)
55         {
56                 vehicles_exit(this.vehicle, VHEF_RELEASE);
57                 if (!this.killindicator_teamchange)
58                 {
59                         this.vehicle_health = -1;
60                         Damage(this, this, this, 1 , DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
61                 }
62         }
63
64         if (this.killindicator && !wasfreed(this.killindicator))
65                 delete(this.killindicator);
66
67         this.killindicator = NULL;
68
69         if (this.killindicator_teamchange)
70                 ClientKill_Now_TeamChange(this);
71
72         if (!IS_SPEC(this) && !IS_OBSERVER(this) && MUTATOR_CALLHOOK(ClientKill_Now, this) == false)
73         {
74                 Damage(this, this, this, 100000, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
75         }
76
77         // now I am sure the player IS dead
78 }
79 void KillIndicator_Think(entity this)
80 {
81         if (game_stopped || (this.owner.alpha < 0 && !this.owner.vehicle))
82         {
83                 this.owner.killindicator = NULL;
84                 delete(this);
85                 return;
86         }
87
88         if (this.cnt <= 0)
89         {
90                 ClientKill_Now(this.owner);
91                 return;
92         }
93
94         // count == 1 means that it's silent
95         if (this.count != 1)
96         {
97                 if (this.cnt <= 10)
98                         setmodel(this, MDL_NUM(this.cnt));
99                 if (IS_REAL_CLIENT(this.owner))
100                 {
101                         if (this.cnt <= 10)
102                                 Send_Notification(NOTIF_ONE, this.owner, MSG_ANNCE, Announcer_PickNumber(CNT_KILL, this.cnt));
103                 }
104         }
105         this.nextthink = time + 1;
106         this.cnt -= 1;
107 }
108
109 .float lip;
110 float clientkilltime;
111 .float clientkill_nexttime;
112 void ClientKill_TeamChange(entity this, float targetteam) // 0 = don't change, -1 = auto, -2 = spec
113 {
114         if (game_stopped)
115                 return;
116
117         float killtime = autocvar_g_balance_kill_delay;
118
119         if (MUTATOR_CALLHOOK(ClientKill, this, killtime))
120                 return;
121         killtime = M_ARGV(1, float);
122
123         if(round_handler_IsActive() && !round_handler_IsRoundStarted())
124                 killtime = min(killtime, 1);
125
126         this.killindicator_teamchange = targetteam;
127
128         // this.killindicator.count == 1 means that the kill indicator was spawned by ClientKill_Silent
129         if(killtime <= 0 && this.killindicator && this.killindicator.count == 1)
130         {
131                 ClientKill_Now(this); // allow instant kill in this case
132                 return;
133         }
134
135         if (!this.killindicator)
136         {
137                 if (!IS_DEAD(this))
138                 {
139                         killtime = max(killtime, this.clientkill_nexttime - time);
140                         float antispam_delay = autocvar_g_balance_kill_antispam;
141                         if(round_handler_IsActive() && !round_handler_IsRoundStarted())
142                                 antispam_delay = min(antispam_delay, 2);
143                         this.clientkill_nexttime = time + killtime + antispam_delay;
144                 }
145
146                 if (killtime <= 0 || !IS_PLAYER(this) || IS_DEAD(this))
147                 {
148                         ClientKill_Now(this);
149                 }
150                 else
151                 {
152                         float starttime = max(time, clientkilltime);
153
154                         this.killindicator = new(killindicator);
155                         this.killindicator.owner = this;
156                         this.killindicator.scale = 0.5;
157                         setattachment(this.killindicator, this, "");
158                         setorigin(this.killindicator, '0 0 52');
159                         setthink(this.killindicator, KillIndicator_Think);
160                         this.killindicator.nextthink = starttime + (this.lip) * 0.05;
161                         clientkilltime = max(clientkilltime, this.killindicator.nextthink + 0.05);
162                         this.killindicator.cnt = ceil(killtime);
163                         this.killindicator.count = bound(0, ceil(killtime), 10);
164                         //sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n"));
165
166                         IL_EACH(g_clones, it.enemy == this && !(it.effects & CSQCMODEL_EF_RESPAWNGHOST) && !it.killindicator,
167                         {
168                                 it.killindicator = new(killindicator);
169                                 it.killindicator.owner = it;
170                                 it.killindicator.scale = 0.5;
171                                 setattachment(it.killindicator, it, "");
172                                 setorigin(it.killindicator, '0 0 52');
173                                 setthink(it.killindicator, KillIndicator_Think);
174                                 it.killindicator.nextthink = starttime + (it.lip) * 0.05;
175                                 //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
176                                 it.killindicator.cnt = ceil(killtime);
177                         });
178                         this.lip = 0;
179                 }
180         }
181         if (this.killindicator)
182         {
183                 Notification notif;
184                 if (targetteam == 0) // just die
185                 {
186                         this.killindicator.colormod = '0 0 0';
187                         notif = CENTER_TEAMCHANGE_SUICIDE;
188                 }
189                 else if (targetteam == -1) // auto
190                 {
191                         this.killindicator.colormod = '0 1 0';
192                         notif = CENTER_TEAMCHANGE_AUTO;
193                 }
194                 else if (targetteam == -2) // spectate
195                 {
196                         this.killindicator.colormod = '0.5 0.5 0.5';
197                         notif = CENTER_TEAMCHANGE_SPECTATE;
198                 }
199                 else
200                 {
201                         this.killindicator.colormod = Team_ColorRGB(targetteam);
202                         notif = APP_TEAM_NUM(targetteam, CENTER_TEAMCHANGE);
203                 }
204                 if (IS_REAL_CLIENT(this) && this.killindicator.cnt > 0)
205                         Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, notif, this.killindicator.cnt);
206         }
207
208 }
209
210 void ClientKill_Silent(entity this, float _delay)
211 {
212         this.killindicator = new(killindicator);
213         this.killindicator.owner = this;
214         setthink(this.killindicator, KillIndicator_Think);
215         this.killindicator.nextthink = time + (this.lip) * 0.05;
216         this.killindicator.cnt = ceil(_delay);
217         this.killindicator.count = 1; // this is used to indicate that it should be silent
218         this.lip = 0;
219 }
220
221 // Called when a client types 'kill' in the console
222 void ClientKill(entity this)
223 {
224         if (game_stopped || this.player_blocked || STAT(FROZEN, this))
225                 return;
226
227         ClientKill_TeamChange(this, 0);
228 }