]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/gamemode_lms.qc
#includes: cleanup server
[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 // main functions
9 float LMS_NewPlayerLives()
10 {
11         float fl;
12         fl = autocvar_fraglimit;
13         if(fl == 0)
14                 fl = 999;
15
16         // first player has left the game for dying too much? Nobody else can get in.
17         if(lms_lowest_lives < 1)
18                 return 0;
19
20         if(!autocvar_g_lms_join_anytime)
21                 if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
22                         return 0;
23
24         return bound(1, lms_lowest_lives, fl);
25 }
26
27 // mutator hooks
28 MUTATOR_HOOKFUNCTION(lms_ResetMap)
29 {
30         lms_lowest_lives = 999;
31         lms_next_place = player_count;
32
33         return false;
34 }
35
36 MUTATOR_HOOKFUNCTION(lms_ResetPlayers)
37 {SELFPARAM();
38         entity e;
39         if(restart_mapalreadyrestarted || (time < game_starttime))
40         FOR_EACH_CLIENT(e)
41         if(IS_PLAYER(e))
42         {
43                 WITH(entity, self, e, PlayerScore_Add(e, SP_LMS_LIVES, LMS_NewPlayerLives()));
44         }
45
46         return false;
47 }
48
49 MUTATOR_HOOKFUNCTION(lms_PlayerPreSpawn)
50 {SELFPARAM();
51         // player is dead and becomes observer
52         // FIXME fix LMS scoring for new system
53         if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
54         {
55                 self.classname = "observer";
56                 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_NOLIVES);
57         }
58
59         return false;
60 }
61
62 MUTATOR_HOOKFUNCTION(lms_PlayerDies)
63 {SELFPARAM();
64         self.respawn_flags |= RESPAWN_FORCE;
65
66         return false;
67 }
68
69 MUTATOR_HOOKFUNCTION(lms_RemovePlayer)
70 {SELFPARAM();
71         // Only if the player cannot play at all
72         if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
73                 self.frags = FRAGS_SPECTATOR;
74         else
75                 self.frags = FRAGS_LMS_LOSER;
76
77         if(self.killcount != -666)
78                 if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
79                         Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname);
80                 else
81                         Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname);
82
83         return false;
84 }
85
86 MUTATOR_HOOKFUNCTION(lms_ClientConnect)
87 {SELFPARAM();
88         self.classname = "player";
89         campaign_bots_may_start = 1;
90
91         if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
92         {
93                 PlayerScore_Add(self, SP_LMS_RANK, 666);
94                 self.frags = FRAGS_SPECTATOR;
95         }
96
97         return false;
98 }
99
100 MUTATOR_HOOKFUNCTION(lms_PlayerThink)
101 {SELFPARAM();
102         if(self.deadflag == DEAD_DYING)
103                 self.deadflag = DEAD_RESPAWNING;
104
105         return false;
106 }
107
108 MUTATOR_HOOKFUNCTION(lms_PlayerRegen)
109 {
110         if(autocvar_g_lms_regenerate)
111                 return false;
112         return true;
113 }
114
115 MUTATOR_HOOKFUNCTION(lms_ForbidThrowing)
116 {
117         // forbode!
118         return true;
119 }
120
121 MUTATOR_HOOKFUNCTION(lms_GiveFragsForKill)
122 {
123         // remove a life
124         float tl;
125         tl = PlayerScore_Add(frag_target, SP_LMS_LIVES, -1);
126         if(tl < lms_lowest_lives)
127                 lms_lowest_lives = tl;
128         if(tl <= 0)
129         {
130                 if(!lms_next_place)
131                         lms_next_place = player_count;
132                 else
133                         lms_next_place = min(lms_next_place, player_count);
134                 PlayerScore_Add(frag_target, SP_LMS_RANK, lms_next_place); // won't ever spawn again
135                 --lms_next_place;
136         }
137         frag_score = 0;
138
139         return true;
140 }
141
142 MUTATOR_HOOKFUNCTION(lms_SetStartItems)
143 {
144         start_items &= ~IT_UNLIMITED_AMMO;
145         start_health       = warmup_start_health       = cvar("g_lms_start_health");
146         start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
147         start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
148         start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
149         start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
150         start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
151         start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
152         start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
153
154         return false;
155 }
156
157 MUTATOR_HOOKFUNCTION(lms_KeepScore)
158 {
159         // don't clear player score
160         return true;
161 }
162
163 MUTATOR_HOOKFUNCTION(lms_FilterItem)
164 {SELFPARAM();
165         if(autocvar_g_lms_extra_lives)
166         if(self.itemdef == ITEM_HealthMega)
167         {
168                 self.max_health = 1;
169                 return false;
170         }
171
172         return true;
173 }
174
175 MUTATOR_HOOKFUNCTION(lms_ItemTouch)
176 {SELFPARAM();
177         // give extra lives for mega health
178         if (self.items & ITEM_HealthMega.m_itemid)
179         {
180                 Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
181                 PlayerScore_Add(other, SP_LMS_LIVES, autocvar_g_lms_extra_lives);
182         }
183
184         return MUT_ITEMTOUCH_CONTINUE;
185 }
186
187 // scoreboard stuff
188 void lms_ScoreRules()
189 {
190         ScoreRules_basics(0, 0, 0, false);
191         ScoreInfo_SetLabel_PlayerScore(SP_LMS_LIVES,    "lives",     SFL_SORT_PRIO_SECONDARY);
192         ScoreInfo_SetLabel_PlayerScore(SP_LMS_RANK,     "rank",      SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
193         ScoreRules_basics_end();
194 }
195
196 void lms_Initialize()
197 {
198         lms_lowest_lives = 9999;
199         lms_next_place = 0;
200
201         lms_ScoreRules();
202 }
203
204 MUTATOR_DEFINITION(gamemode_lms)
205 {
206         MUTATOR_HOOK(reset_map_global, lms_ResetMap, CBC_ORDER_ANY);
207         MUTATOR_HOOK(reset_map_players, lms_ResetPlayers, CBC_ORDER_ANY);
208         MUTATOR_HOOK(PutClientInServer, lms_PlayerPreSpawn, CBC_ORDER_ANY);
209         MUTATOR_HOOK(PlayerDies, lms_PlayerDies, CBC_ORDER_ANY);
210         MUTATOR_HOOK(MakePlayerObserver, lms_RemovePlayer, CBC_ORDER_ANY);
211         MUTATOR_HOOK(ClientConnect, lms_ClientConnect, CBC_ORDER_ANY);
212         MUTATOR_HOOK(PlayerPreThink, lms_PlayerThink, CBC_ORDER_ANY);
213         MUTATOR_HOOK(PlayerRegen, lms_PlayerRegen, CBC_ORDER_ANY);
214         MUTATOR_HOOK(ForbidThrowCurrentWeapon, lms_ForbidThrowing, CBC_ORDER_ANY);
215         MUTATOR_HOOK(GiveFragsForKill, lms_GiveFragsForKill, CBC_ORDER_ANY);
216         MUTATOR_HOOK(SetStartItems, lms_SetStartItems, CBC_ORDER_ANY);
217         MUTATOR_HOOK(ForbidPlayerScore_Clear, lms_KeepScore, CBC_ORDER_ANY);
218         MUTATOR_HOOK(FilterItem, lms_FilterItem, CBC_ORDER_ANY);
219         MUTATOR_HOOK(ItemTouch, lms_ItemTouch, CBC_ORDER_ANY);
220
221         MUTATOR_ONADD
222         {
223                 if(time > 1) // game loads at time 1
224                         error("This is a game type and it cannot be added at runtime.");
225                 lms_Initialize();
226         }
227
228         MUTATOR_ONROLLBACK_OR_REMOVE
229         {
230                 // we actually cannot roll back lms_Initialize here
231                 // BUT: we don't need to! If this gets called, adding always
232                 // succeeds.
233         }
234
235         MUTATOR_ONREMOVE
236         {
237                 LOG_INFO("This is a game type and it cannot be removed at runtime.");
238                 return -1;
239         }
240
241         return 0;
242 }