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