]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/gamemode_lms.qc
Kill another gamemode specific check
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / gamemode_lms.qc
1 #include "gamemode_lms.qh"
2
3 #include "gamemode.qh"
4
5 #include "../campaign.qh"
6 #include "../command/cmd.qh"
7
8 int autocvar_g_lms_extra_lives;
9 bool autocvar_g_lms_join_anytime;
10 int autocvar_g_lms_last_join;
11 #define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
12 bool autocvar_g_lms_regenerate;
13
14 // main functions
15 float LMS_NewPlayerLives()
16 {
17         float fl;
18         fl = autocvar_fraglimit;
19         if(fl == 0)
20                 fl = 999;
21
22         // first player has left the game for dying too much? Nobody else can get in.
23         if(lms_lowest_lives < 1)
24                 return 0;
25
26         if(!autocvar_g_lms_join_anytime)
27                 if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
28                         return 0;
29
30         return bound(1, lms_lowest_lives, fl);
31 }
32
33 // mutator hooks
34 MUTATOR_HOOKFUNCTION(lms, reset_map_global)
35 {
36         lms_lowest_lives = 999;
37         lms_next_place = player_count;
38
39         return false;
40 }
41
42 MUTATOR_HOOKFUNCTION(lms, reset_map_players)
43 {SELFPARAM();
44         entity e;
45         if(restart_mapalreadyrestarted || (time < game_starttime))
46         FOR_EACH_CLIENT(e)
47         if(IS_PLAYER(e))
48         {
49                 WITH(entity, self, e, PlayerScore_Add(e, SP_LMS_LIVES, LMS_NewPlayerLives()));
50         }
51
52         return false;
53 }
54
55 MUTATOR_HOOKFUNCTION(lms, PutClientInServer)
56 {SELFPARAM();
57         // player is dead and becomes observer
58         // FIXME fix LMS scoring for new system
59         if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
60         {
61                 self.classname = "observer";
62                 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_NOLIVES);
63         }
64
65         return false;
66 }
67
68 MUTATOR_HOOKFUNCTION(lms, PlayerDies)
69 {SELFPARAM();
70         self.respawn_flags |= RESPAWN_FORCE;
71
72         return false;
73 }
74
75 void lms_RemovePlayer(entity player)
76 {
77         // Only if the player cannot play at all
78         if(PlayerScore_Add(player, SP_LMS_RANK, 0) == 666)
79                 player.frags = FRAGS_SPECTATOR;
80         else
81                 player.frags = FRAGS_LMS_LOSER;
82
83         if(player.killcount != -666)
84                 if(PlayerScore_Add(player, SP_LMS_RANK, 0) > 0 && player.lms_spectate_warning != 2)
85                         Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, player.netname);
86                 else
87                         Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, player.netname);
88 }
89
90 MUTATOR_HOOKFUNCTION(lms, ClientDisconnect)
91 {SELFPARAM();
92         lms_RemovePlayer(self);
93         return false;
94 }
95
96 MUTATOR_HOOKFUNCTION(lms, MakePlayerObserver)
97 {SELFPARAM();
98         lms_RemovePlayer(self);
99         return false;
100 }
101
102 MUTATOR_HOOKFUNCTION(lms, ClientConnect)
103 {SELFPARAM();
104         self.classname = "player";
105         campaign_bots_may_start = 1;
106
107         if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
108         {
109                 PlayerScore_Add(self, SP_LMS_RANK, 666);
110                 self.frags = FRAGS_SPECTATOR;
111         }
112
113         return false;
114 }
115
116 MUTATOR_HOOKFUNCTION(lms, PlayerPreThink)
117 {SELFPARAM();
118         if(self.deadflag == DEAD_DYING)
119                 self.deadflag = DEAD_RESPAWNING;
120
121         return false;
122 }
123
124 MUTATOR_HOOKFUNCTION(lms, PlayerRegen)
125 {
126         if(autocvar_g_lms_regenerate)
127                 return false;
128         return true;
129 }
130
131 MUTATOR_HOOKFUNCTION(lms, ForbidThrowCurrentWeapon)
132 {
133         // forbode!
134         return true;
135 }
136
137 MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill)
138 {
139         // remove a life
140         float tl;
141         tl = PlayerScore_Add(frag_target, SP_LMS_LIVES, -1);
142         if(tl < lms_lowest_lives)
143                 lms_lowest_lives = tl;
144         if(tl <= 0)
145         {
146                 if(!lms_next_place)
147                         lms_next_place = player_count;
148                 else
149                         lms_next_place = min(lms_next_place, player_count);
150                 PlayerScore_Add(frag_target, SP_LMS_RANK, lms_next_place); // won't ever spawn again
151                 --lms_next_place;
152         }
153         frag_score = 0;
154
155         return true;
156 }
157
158 MUTATOR_HOOKFUNCTION(lms, SetStartItems)
159 {
160         start_items &= ~IT_UNLIMITED_AMMO;
161         start_health       = warmup_start_health       = cvar("g_lms_start_health");
162         start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
163         start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
164         start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
165         start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
166         start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
167         start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
168         start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
169
170         return false;
171 }
172
173 MUTATOR_HOOKFUNCTION(lms, ForbidPlayerScore_Clear)
174 {
175         // don't clear player score
176         return true;
177 }
178
179 MUTATOR_HOOKFUNCTION(lms, FilterItem)
180 {SELFPARAM();
181         if(autocvar_g_lms_extra_lives)
182         if(self.itemdef == ITEM_HealthMega)
183         {
184                 self.max_health = 1;
185                 return false;
186         }
187
188         return true;
189 }
190
191 MUTATOR_HOOKFUNCTION(lms, ItemTouch)
192 {SELFPARAM();
193         // give extra lives for mega health
194         if (self.items & ITEM_HealthMega.m_itemid)
195         {
196                 Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
197                 PlayerScore_Add(other, SP_LMS_LIVES, autocvar_g_lms_extra_lives);
198         }
199
200         return MUT_ITEMTOUCH_CONTINUE;
201 }
202
203 MUTATOR_HOOKFUNCTION(lms, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
204 {
205         entity head;
206         FOR_EACH_REALCLIENT(head)
207         {
208                 ++bot_activerealplayers;
209                 ++bot_realplayers;
210         }
211
212         return true;
213 }
214
215 MUTATOR_HOOKFUNCTION(lms, ClientCommand_Spectate)
216 {
217         if(self.lms_spectate_warning)
218         {
219                 // for the forfeit message...
220                 self.lms_spectate_warning = 2;
221                 // mark player as spectator
222                 PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0));
223         }
224         else
225         {
226                 self.lms_spectate_warning = 1;
227                 sprint(self, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");
228                 return MUT_SPECCMD_RETURN;
229         }
230         return MUT_SPECCMD_CONTINUE;
231 }
232
233 MUTATOR_HOOKFUNCTION(lms, CheckRules_World)
234 {
235         ret_float = WinningCondition_LMS();
236         return true;
237 }
238
239 MUTATOR_HOOKFUNCTION(lms, WantWeapon)
240 {
241         want_allguns = true;
242         return false;
243 }
244
245 MUTATOR_HOOKFUNCTION(lms, SetPlayerFullStatus)
246 {
247         return true;
248 }
249
250 MUTATOR_HOOKFUNCTION(lms, SetPlayerStatus)
251 {
252         return true;
253 }
254
255 // scoreboard stuff
256 void lms_ScoreRules()
257 {
258         ScoreRules_basics(0, 0, 0, false);
259         ScoreInfo_SetLabel_PlayerScore(SP_LMS_LIVES,    "lives",     SFL_SORT_PRIO_SECONDARY);
260         ScoreInfo_SetLabel_PlayerScore(SP_LMS_RANK,     "rank",      SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
261         ScoreRules_basics_end();
262 }
263
264 void lms_Initialize()
265 {
266         lms_lowest_lives = 9999;
267         lms_next_place = 0;
268
269         lms_ScoreRules();
270 }
271
272 REGISTER_MUTATOR(lms, g_lms)
273 {
274         SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, -1, -1);
275
276         MUTATOR_ONADD
277         {
278                 if(time > 1) // game loads at time 1
279                         error("This is a game type and it cannot be added at runtime.");
280                 lms_Initialize();
281         }
282
283         MUTATOR_ONROLLBACK_OR_REMOVE
284         {
285                 // we actually cannot roll back lms_Initialize here
286                 // BUT: we don't need to! If this gets called, adding always
287                 // succeeds.
288         }
289
290         MUTATOR_ONREMOVE
291         {
292                 LOG_INFO("This is a game type and it cannot be removed at runtime.");
293                 return -1;
294         }
295
296         return 0;
297 }