1 enum
2 {
3     G_DEMO = 0, G_EDITMODE, G_DEATHMATCH, G_CAPTURE, G_DEFEND, G_BOMBER, G_RACE, G_MAX,
4     G_START = G_EDITMODE, G_PLAY = G_DEATHMATCH,
5     G_RAND = G_BOMBER-G_DEATHMATCH+1, G_COUNT = G_MAX-G_PLAY,
6     G_NEVER = (1<<G_DEMO)|(1<<G_EDITMODE),
7     G_LIMIT = (1<<G_DEATHMATCH)|(1<<G_CAPTURE)|(1<<G_DEFEND)|(1<<G_BOMBER),
8     G_ALL = (1<<G_DEMO)|(1<<G_EDITMODE)|(1<<G_DEATHMATCH)|(1<<G_CAPTURE)|(1<<G_DEFEND)|(1<<G_BOMBER)|(1<<G_RACE),
9     G_SW = (1<<G_RACE),
10 };
11 
12 #define GM(x) (1<<(G_M_##x))
13 enum
14 {
15     G_M_FFA = 0, G_M_COOP, G_M_INSTA, G_M_MEDIEVAL, G_M_KABOOM, G_M_DUEL, G_M_SURVIVOR,
16     G_M_CLASSIC, G_M_ONSLAUGHT, G_M_VAMPIRE, G_M_RESIZE, G_M_HARD, G_M_ARENA,
17     G_M_GSP, G_M_GSP1 = G_M_GSP, G_M_GSP2, G_M_GSP3, G_M_NUM,
18     G_M_GSN = G_M_NUM-G_M_GSP,
19     G_M_ALL = GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
20     G_M_FILTER = GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
21     G_M_ROTATE = GM(FFA),
22     G_M_DUKE = GM(DUEL)|GM(SURVIVOR),
23 };
24 
25 #define GF(x) (1<<(G_F_##x))
26 enum { G_F_GSP = 0, G_F_NUM };
27 
28 enum { G_S_WAITING = 0, G_S_GETMAP, G_S_SENDMAP, G_S_READYING, G_S_GAMEINFO, G_S_PLAYING, G_S_OVERTIME, G_S_INTERMISSION, G_S_VOTING, G_S_MAX };
29 
30 #ifdef CPP_GAME_SERVER
31 const char *gamestates[4][G_S_MAX] = {
32     { "waiting", "getmap", "sendmap", "readying", "syncing", "playing", "overtime", "intermission", "voting" },
33     { "Waiting", "Getmap", "Sendmap", "Readying", "Syncing", "Playing", "Overtime", "Intermission", "Voting" },
34     { "waiting to play", "server getting map", "server sending map", "readying", "syncing info", "playing", "overtime", "intermission", "voting" },
35     { "Waiting to Play", "Getting Map", "Sending Maps", "Readying", "Syncing Info", "Playing", "Overtime", "Intermission", "Voting" }
36 };
37 #else
38 extern const char *gamestates[4][G_S_MAX];
39 #endif
40 
41 #define gs_waiting(a) (a >= G_S_WAITING && a <= G_S_GAMEINFO)
42 #define gs_playing(a) (a >= G_S_PLAYING && a <= G_S_OVERTIME)
43 #define gs_intermission(a) (a >= G_S_INTERMISSION && a <= G_S_VOTING)
44 
45 struct gametypes
46 {
47     int type, flags, implied, mutators[1+G_M_GSN];
48     const char *name, *sname, *gsp[G_M_GSN], *desc, *gsd[G_M_GSN];
49 };
50 struct mutstypes
51 {
52     int type, implied, mutators;
53     const char *name, *desc;
54 };
55 #ifdef CPP_GAME_SERVER
56 gametypes gametype[] = {
57     {
58         G_DEMO, 0, 0, { 0, 0, 0, 0 },
59         "Demo", "Demo", { "", "", "" },
60         "Play back previously recorded games", { "", "", "" },
61     },
62     {
63         G_EDITMODE, 0, GM(FFA),
64         {
65             GM(FFA)|GM(CLASSIC)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA),
66             0, 0, 0
67         },
68         "Editing", "Editing", { "", "", "" },
69         "Create and edit existing maps", { "", "", "" },
70     },
71     {
72         G_DEATHMATCH, 0, 0,
73         {
74             GM(FFA)|GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2),
75             GM(FFA)|GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(GSP1),
76             GM(FFA)|GM(COOP)|GM(INSTA)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP2),
77             0
78         },
79         "Deathmatch", "DM", { "Gladiator", "Old School", "" },
80         "Shoot to kill and increase score by fragging", { "Fight in a confined area with increased pushback from damage", "Every frag only gives you a single point, like the old days", "" },
81     },
82     {
83         G_CAPTURE, 0, 0,
84         {
85             GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
86             GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1),
87             GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP2),
88             GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP3)
89         },
90         "Capture the Flag", "Capture", { "Quick", "Defend", "Protect" },
91         "Take the enemy flag and return it to the base to score", { "Dropped flags instantly return to base", "Dropped flags must be defended until they reset", "Protect the flag and hold the enemy flag to score" },
92     },
93     {
94         G_DEFEND, 0, 0,
95         {
96             GM(COOP)|GM(INSTA)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2),
97             GM(COOP)|GM(INSTA)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2),
98             GM(COOP)|GM(INSTA)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2),
99             0
100         },
101         "Defend and Control", "Defend", { "Quick", "King", "" },
102         "Defend control points to score", { "Control points secure quicker than normal", "Remain king of the hill to score", ""},
103     },
104     {
105         G_BOMBER, GF(GSP), 0,
106         {
107             GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
108             GM(FFA)|GM(COOP)|GM(INSTA)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1),
109             GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP2)|GM(GSP3),
110             GM(COOP)|GM(INSTA)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP2)|GM(GSP3)
111         },
112         "Bomber Ball", "Bomber", { "Hold", "Basket", "Assault" },
113         "Carry the bomb into the enemy goal to score", { "Hold the bomb as long as possible to score", "Throw the bomb into the enemy goal to score", "Teams take turns attacking and defending" },
114     },
115     {
116         G_RACE, GF(GSP), 0,
117         {
118             GM(FFA)|GM(ONSLAUGHT)|GM(GSP1)|GM(GSP2)|GM(GSP3),
119             GM(FFA)|GM(ONSLAUGHT)|GM(GSP1)|GM(GSP2)|GM(GSP3),
120             GM(FFA)|GM(ONSLAUGHT)|GM(GSP1)|GM(GSP2)|GM(GSP3),
121             GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3)
122         },
123         "Race", "Race", { "Lapped", "Endurance", "Gauntlet" },
124         "Compete for the fastest time completing a lap", { "Compete for the most number of laps", "Laps must be completed without dying at all", "Teams take turns running the gauntlet" },
125     }
126 };
127 mutstypes mutstype[] = {
128     {
129         G_M_FFA, GM(FFA),
130         GM(FFA)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
131         "FFA", "Every player for themselves"
132     },
133     {
134         G_M_COOP, GM(COOP),
135         GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
136         "Coop", "Players versus drones"
137     },
138     {
139         G_M_INSTA, GM(INSTA),
140         GM(FFA)|GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(HARD)|GM(RESIZE)|GM(GSP1)|GM(GSP2)|GM(GSP3),
141         "Instagib", "One hit kills instantly"
142     },
143     {
144         G_M_MEDIEVAL, GM(MEDIEVAL),
145         GM(FFA)|GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(MEDIEVAL)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(GSP1)|GM(GSP2)|GM(GSP3),
146         "Medieval", "Players spawn only with swords"
147     },
148     {
149         G_M_KABOOM,  GM(KABOOM),
150         GM(FFA)|GM(COOP)|GM(INSTA)|GM(DUEL)|GM(SURVIVOR)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(GSP1)|GM(GSP2)|GM(GSP3),
151         "Kaboom", "Players spawn with explosives only"
152     },
153     {
154         G_M_DUEL, GM(DUEL),
155         GM(FFA)|GM(COOP)|GM(INSTA)|GM(DUEL)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
156         "Duel", "One on one battles to determine the winner"
157     },
158     {
159         G_M_SURVIVOR, GM(SURVIVOR),
160         GM(FFA)|GM(COOP)|GM(INSTA)|GM(SURVIVOR)|GM(CLASSIC)|GM(MEDIEVAL)|GM(KABOOM)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
161         "Survivor", "Players battle to determine the winner"
162     },
163     {
164         G_M_CLASSIC,    GM(CLASSIC),
165         GM(FFA)|GM(COOP)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
166         "Classic", "Weapons must be collected from spawns in the arena"
167     },
168     {
169         G_M_ONSLAUGHT, GM(ONSLAUGHT),
170         GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
171         "Onslaught", "Waves of enemies fill the battle arena"
172     },
173     {
174         G_M_VAMPIRE, GM(VAMPIRE),
175         GM(FFA)|GM(COOP)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
176         "Vampire", "Deal damage to regenerate health"
177     },
178     {
179         G_M_RESIZE, GM(RESIZE),
180         GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
181         "Resize", "Players change size depending on their health"
182     },
183     {
184         G_M_HARD, GM(HARD),
185         GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
186         "Hard", "Radar and health regeneration is disabled"
187     },
188     {
189         G_M_ARENA, GM(ARENA),
190         GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
191         "Arena", "Players are able to carry all weapons at once"
192     },
193     {
194         G_M_GSP1, GM(GSP1),
195         GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
196         "Game Specific 1", ""
197     },
198     {
199         G_M_GSP2, GM(GSP2),
200         GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
201         "Game Specific 2", ""
202     },
203     {
204         G_M_GSP3, GM(GSP3),
205         GM(FFA)|GM(COOP)|GM(INSTA)|GM(MEDIEVAL)|GM(KABOOM)|GM(DUEL)|GM(SURVIVOR)|GM(CLASSIC)|GM(ONSLAUGHT)|GM(VAMPIRE)|GM(RESIZE)|GM(HARD)|GM(ARENA)|GM(GSP1)|GM(GSP2)|GM(GSP3),
206         "Game Specific 3", ""
207     },
208 };
209 #else
210 extern gametypes gametype[];
211 extern mutstypes mutstype[];
212 #endif
213 
214 #define m_game(a)           (a > -1 && a < G_MAX)
215 #define m_check(a,b,c,d)    ((!a || (a < 0 ? !((0-a)&(1<<(c-G_PLAY))) : a&(1<<(c-G_PLAY)))) && (!b || (b < 0 ? !((0-b)&d) : b&d)))
216 #define m_local(a)          (a == G_DEMO)
217 
218 #define m_demo(a)           (a == G_DEMO)
219 #define m_edit(a)           (a == G_EDITMODE)
220 #define m_dm(a)             (a == G_DEATHMATCH)
221 #define m_capture(a)        (a == G_CAPTURE)
222 #define m_defend(a)         (a == G_DEFEND)
223 #define m_bomber(a)         (a == G_BOMBER)
224 #define m_race(a)           (a == G_RACE)
225 
226 #define m_play(a)           (a >= G_PLAY)
227 #define m_affinity(a)       (m_capture(a) || m_defend(a) || m_bomber(a))
228 
229 #define m_ffa(a,b)          ((b&GM(FFA)) || (gametype[a].implied&GM(FFA)))
230 #define m_coop(a,b)         ((b&GM(COOP)) || (gametype[a].implied&GM(COOP)))
231 #define m_insta(a,b)        ((b&GM(INSTA)) || (gametype[a].implied&GM(INSTA)))
232 #define m_medieval(a,b)     ((b&GM(MEDIEVAL)) || (gametype[a].implied&GM(MEDIEVAL)))
233 #define m_kaboom(a,b)       ((b&GM(KABOOM)) || (gametype[a].implied&GM(KABOOM)))
234 #define m_duel(a,b)         ((b&GM(DUEL)) || (gametype[a].implied&GM(DUEL)))
235 #define m_survivor(a,b)     ((b&GM(SURVIVOR)) || (gametype[a].implied&GM(SURVIVOR)))
236 #define m_classic(a,b)      ((b&GM(CLASSIC)) || (gametype[a].implied&GM(CLASSIC)))
237 #define m_onslaught(a,b)    ((b&GM(ONSLAUGHT)) || (gametype[a].implied&GM(ONSLAUGHT)))
238 #define m_vampire(a,b)      ((b&GM(VAMPIRE)) || (gametype[a].implied&GM(VAMPIRE)))
239 #define m_resize(a,b)       ((b&GM(RESIZE)) || (gametype[a].implied&GM(RESIZE)))
240 #define m_hard(a,b)         ((b&GM(HARD)) || (gametype[a].implied&GM(HARD)))
241 #define m_arena(a,b)        ((b&GM(ARENA)) || (gametype[a].implied&GM(ARENA)))
242 
243 #define m_gsp1(a,b)         ((b&GM(GSP1)) || (gametype[a].implied&GM(GSP1)))
244 #define m_gsp2(a,b)         ((b&GM(GSP2)) || (gametype[a].implied&GM(GSP2)))
245 #define m_gsp3(a,b)         ((b&GM(GSP3)) || (gametype[a].implied&GM(GSP3)))
246 #define m_gsp(a,b)          (m_gsp1(a,b) || m_gsp2(a,b) || m_gsp3(a,b))
247 
248 #define m_dm_gladiator(a,b) (m_dm(a) && m_gsp1(a, b))
249 #define m_dm_oldschool(a,b) (m_dm(a) && m_gsp2(a, b))
250 
251 #define m_ctf_quick(a,b)    (m_capture(a) && m_gsp1(a, b))
252 #define m_ctf_defend(a,b)   (m_capture(a) && m_gsp2(a, b))
253 #define m_ctf_protect(a,b)  (m_capture(a) && m_gsp3(a, b))
254 
255 #define m_dac_quick(a,b)    (m_defend(a) && m_gsp1(a, b))
256 #define m_dac_king(a,b)     (m_defend(a) && m_gsp2(a, b))
257 
258 #define m_bb_hold(a,b)      (m_bomber(a) && m_gsp1(a, b))
259 #define m_bb_basket(a,b)    (m_bomber(a) && m_gsp2(a, b))
260 #define m_bb_assault(a,b)   (m_bomber(a) && m_gsp3(a, b))
261 
262 #define m_ra_lapped(a,b)    (m_race(a) && m_gsp1(a, b))
263 #define m_ra_timed(a,b)     (m_race(a) && !m_gsp1(a, b))
264 #define m_ra_endurance(a,b) (m_race(a) && m_gsp2(a, b))
265 #define m_ra_gauntlet(a,b)  (m_race(a) && m_gsp3(a, b))
266 
267 #define m_team(a,b)         (!m_ffa(a, b))
268 #define m_single(a,b)       (m_dm_gladiator(a, b) || (m_race(a) && !m_ra_gauntlet(a, b)) || m_insta(a, b) || m_medieval(a, b)) // games that give you only a single weapon (for *extra values)
269 #define m_sweaps(a,b)       (m_dm_gladiator(a, b) || (m_race(a) && !m_ra_gauntlet(a, b)) || m_insta(a, b) || m_medieval(a, b) || m_kaboom(a, b)) // games that do not require selecing a spawn loadout but also don't have you pick one up
270 #define m_rotweaps(a,b)     (m_dm_gladiator(a, b) || (m_race(a) && !m_ra_gauntlet(a, b)) || m_medieval(a, b) || m_kaboom(a, b)) // games that require picking up rotation weapons
271 #define m_loadout(a,b)      (!m_classic(a, b) && !m_sweaps(a, b)) // games that require selecting a spawn loadout: non-classic, non-([non-gladiator race],gauntlet,insta,medieval,kaboom)
272 #define m_duke(a,b)         (m_duel(a, b) || m_survivor(a, b))
273 #define m_regen(a,b)        (!m_hard(a,b) && (!m_duke(a, b) || DSG(a, b, regen)) && !m_insta(a, b))
274 #define m_ghost(a,b)        (m_race(a) && !m_ra_gauntlet(a, b))
275 #define m_bots(a)           (m_play(a) && !m_race(a))
276 #define m_botbal(a,b)       (m_duel(a, b) ? G(botbalanceduel) : (m_survivor(a, b) ? G(botbalancesurvivor) : G(botbalance)))
277 #define m_nopoints(a,b)     (m_duke(a, b) || m_bb_hold(a, b) || m_race(a))
278 #define m_points(a,b)       (!m_nopoints(a, b))
279 #define m_normweaps(a,b)    (!m_race(a) && !m_insta(a,b) && !m_medieval(a,b) && !m_kaboom(a,b) && !m_dm_gladiator(a,b))
280 #define m_lasthit(a,b)      (m_dm_gladiator(a,b) && m_points(a,b))
281 
282 #define m_weapon(at,a,b)    (m_medieval(a, b) ? AA(at, weaponmedieval) : (m_kaboom(a, b) ? AA(at, weaponkaboom) : (m_insta(a, b) ? AA(at, weaponinsta) : (m_race(a) && !m_ra_gauntlet(a, b) ? AA(at, weaponrace) : (m_dm_gladiator(a, b) ? AA(at, weapongladiator) : AA(at, weaponspawn))))))
283 #define m_maxcarry(at,a,b)  (at < A_ENEMY && m_arena(a, b) ? W_LOADOUT : AA(at, maxcarry))
284 #define m_delay(at,a,b,c)   (!m_duke(a,b) ? int((m_edit(a) ? AA(at, spawndelayedit) : (m_race(a) ? (!m_ra_gauntlet(a, b) || c == T_ALPHA ? AA(at, spawndelayrace) : AA(at, spawndelaygauntlet)) : (m_bomber(a) ? AA(at, spawndelaybomber) : (m_defend(a) ? AA(at, spawndelaydefend) : (m_capture(a) ? AA(at, spawndelaycapture) : AA(at, spawndelay))))))*(m_insta(a, b) ? AA(at, spawndelayinstascale) : 1.f)) : 0)
285 #define m_protect(a,b)      (m_duke(a,b) ? DSG(a, b, protect) : (m_insta(a, b) ? G(instaprotect) : G(spawnprotect)))
286 #define m_teamspawn(a,b)    (m_team(a, b) && (!m_race(a) || m_ra_gauntlet(a, b)))
287 #define m_swapteam(a,b)     (m_play(a) && m_teamspawn(a, b) && (G(teambalanceduel) || !m_duel(a, b)) && !m_coop(gamemode, mutators) && G(teambalance) >= 3 && G(teambalanceswap))
288 #define m_balteam(a,b,c)    (m_play(a) && m_teamspawn(a, b) && (G(teambalanceduel) || !m_duel(a, b)) && !m_coop(gamemode, mutators) && G(teambalance) >= c)
289 #define m_forcebal(a,b)     (m_bb_assault(a, b) || m_ra_gauntlet(a, b))
290 #define m_balance(a,b,c)    (m_play(a) && m_teamspawn(a, b) && (m_forcebal(a, b) || ((G(balanceduke) || !m_duke(a, b)) && ((G(balancemaps) >= 0 ? G(balancemaps) : G(mapbalance)) >= (m_affinity(a) ? 1 : (c ? 2 : 3))))))
291 #define m_balreset(a,b)     (G(balancereset) && (G(balancereset) == 2 || m_capture(a) || m_bomber(a) || m_race(a) || m_duke(a, b)))
292 
293 #ifdef CPP_GAME_SERVER
294 #define m_attr(a,b)         (a == WEAPON ? attrmap[isweap(b) ? b : W_GRENADE] : b)
295 #else
296 #define m_attr(a,b)         (a == WEAPON ? game::attrmap[isweap(b) ? b : W_GRENADE] : b)
297 #endif
298 
299 #define m_mmvar(a,b,c)      (m_dm(a) ? \
300                                 (m_duel(a, b) ? G(c##duel) : \
301                                     (m_survivor(a, b) ? G(c##survivor) : \
302                                         (m_dm_gladiator(a, b) ? G(c##gladiator) : G(c)) \
303                                     ) \
304                                 ) : \
305                                 (m_capture(a) ? G(c##capture) : \
306                                     (m_defend(a) ? \
307                                         (m_dac_king(a, b) ? G(c##defendking) : G(c##defend)) : \
308                                         (m_bomber(a) ? (m_bb_hold(a, b) ? G(c##bomberhold) : G(c##bomber)) : \
309                                             (m_race(a) ? \
310                                                 (m_ra_lapped(a, b) ? G(c##racelapped) : \
311                                                     (m_ra_gauntlet(a, b) ? G(c##racegauntlet) : G(c##race)) \
312                                                 ) : 0 \
313                                             ) \
314                                         ) \
315                                     ) \
316                                 ) \
317                             )
318 
319 #define MMVAR(f,l,a,b,c,w01,w02,w03,w04,w05,w06,w07,w08,w09,w10,w11,w12) \
320     GVAR(f, l, a, b, w01, c); \
321     GVAR(f, l, a##duel, b, w02, c); \
322     GVAR(f, l, a##survivor, b, w03, c); \
323     GVAR(f, l, a##gladiator, b, w04, c); \
324     GVAR(f, l, a##capture, b, w05, c); \
325     GVAR(f, l, a##defend, b, w06, c); \
326     GVAR(f, l, a##defendking, b, w07, c); \
327     GVAR(f, l, a##bomber, b, w08, c); \
328     GVAR(f, l, a##bomberhold, b, w09, c); \
329     GVAR(f, l, a##race, b, w10, c); \
330     GVAR(f, l, a##racelapped, b, w11, c); \
331     GVAR(f, l, a##racegauntlet, b, w12, c);
332 
333 #define DSG(a,b,x)          (m_duel(a, b) ? G(duel##x) : G(survivor##x))
334 
335 #define mapshrink(a,b,c,d) if((a) && (b) && (c) && *(c)) \
336 { \
337     char *p = shrinklist(b, c, 1, d); \
338     if(p) \
339     { \
340         DELETEA(b); \
341         b = p; \
342     } \
343 }
344 #define mapcull(a,b,c,d,e,f) \
345 { \
346     mapshrink(m_duel(b, c), a, G(duelmaps), false) \
347     if((d) > 0 && (e) >= 2 && m_play(b) && !m_duel(b, c)) \
348     { \
349         mapshrink(G(smallmapmax) && (d) <= G(smallmapmax), a, G(smallmaps), false) \
350         else mapshrink(G(mediummapmax) && (d) <= G(mediummapmax), a, G(mediummaps), false) \
351         else mapshrink(G(mediummapmax) && (d) > G(mediummapmax), a, G(largemaps), false) \
352     } \
353     mapshrink(!(f), a, G(previousmaps), true) \
354 }
355 //note that maplist removes entries in previousmaps
356 #define maplist(a,b,c,d,e,f) \
357 { \
358     if(m_capture(b)) a = newstring(G(capturemaps)); \
359     else if(m_defend(b)) a = newstring(m_dac_king(b, c) ? G(kingmaps) : G(defendmaps)); \
360     else if(m_bomber(b)) a = newstring(m_bb_hold(b, c) ? G(holdmaps) : G(bombermaps)); \
361     else if(m_race(b)) a = newstring(G(racemaps)); \
362     else if(m_dm(b)) a = newstring(m_dm_gladiator(b, c) ? G(gladiatormaps) : G(mainmaps)); \
363     else a = newstring(G(allowmaps)); \
364     if(e) mapcull(a, b, c, d, e, f) \
365     else mapshrink(!(f), a, G(previousmaps), true) \
366 }
367 //allowmaplist doesn't cut previous maps
368 #define allowmaplist(a,b,c) \
369 { \
370     if(m_capture(b)) a = newstring(G(capturemaps)); \
371     else if(m_defend(b)) a = newstring(m_dac_king(b, c) ? G(kingmaps) : G(defendmaps)); \
372     else if(m_bomber(b)) a = newstring(m_bb_hold(b, c) ? G(holdmaps) : G(bombermaps)); \
373     else if(m_race(b)) a = newstring(G(racemaps)); \
374     else if(m_dm(b)) a = newstring(m_dm_gladiator(b, c) ? G(gladiatormaps) : G(mainmaps)); \
375     else a = newstring(G(allowmaps)); \
376 }
377 
378 #ifdef CPP_GAME_SERVER
379 SVAR(IDF_READONLY, gamestateidxname, "waiting getmap sendmap readying gameinfo playing overtime intermission voting");
380 VAR(IDF_READONLY, gamestatewaiting, 1, G_S_WAITING, -1);
381 VAR(IDF_READONLY, gamestategetmap, 1, G_S_GETMAP, -1);
382 VAR(IDF_READONLY, gamestatesendmap, 1, G_S_SENDMAP, -1);
383 VAR(IDF_READONLY, gamestatereadying, 1, G_S_READYING, -1);
384 VAR(IDF_READONLY, gamestategameinfo, 1, G_S_GAMEINFO, -1);
385 VAR(IDF_READONLY, gamestateplaying, 1, G_S_PLAYING, -1);
386 VAR(IDF_READONLY, gamestateovertime, 1, G_S_OVERTIME, -1);
387 VAR(IDF_READONLY, gamestateintermission, 1, G_S_INTERMISSION, -1);
388 VAR(IDF_READONLY, gamestatevoting, 1, G_S_VOTING, -1);
389 VAR(IDF_READONLY, gamestatenum, 1, G_S_MAX, -1);
390 SVAR(IDF_READONLY, modename, "Demo Editing Deathmatch [Capture the Flag] [Defend and Control] [Bomber Ball] [Race]");
391 SVAR(IDF_READONLY, modeidxname, "demo editing deathmatch capture defend bomber race");
392 VAR(IDF_READONLY, modeidxdemo, 1, G_DEMO, -1);
393 VAR(IDF_READONLY, modeidxediting, 1, G_EDITMODE, -1);
394 VAR(IDF_READONLY, modeidxdeathmatch, 1, G_DEATHMATCH, -1);
395 VAR(IDF_READONLY, modeidxcapture, 1, G_CAPTURE, -1);
396 VAR(IDF_READONLY, modeidxdefend, 1, G_DEFEND, -1);
397 VAR(IDF_READONLY, modeidxbomber, 1, G_BOMBER, -1);
398 VAR(IDF_READONLY, modeidxrace, 1, G_RACE, -1);
399 VAR(IDF_READONLY, modeidxstart, 1, G_START, -1);
400 VAR(IDF_READONLY, modeidxplay, 1, G_PLAY, -1);
401 VAR(IDF_READONLY, modeidxrand, 1, G_RAND, -1);
402 VAR(IDF_READONLY, modeidxnever, 1, G_NEVER, -1);
403 VAR(IDF_READONLY, modeidxlimit, 1, G_LIMIT, -1);
404 VAR(IDF_READONLY, modeidxnum, 1, G_MAX, -1);
405 VAR(IDF_READONLY, modebitdemo, 1, (1<<G_DEMO), -1);
406 VAR(IDF_READONLY, modebitediting, 1, (1<<G_EDITMODE), -1);
407 VAR(IDF_READONLY, modebitdeathmatch, 1, (1<<G_DEATHMATCH), -1);
408 VAR(IDF_READONLY, modebitcapture, 1, (1<<G_CAPTURE), -1);
409 VAR(IDF_READONLY, modebitdefend, 1, (1<<G_DEFEND), -1);
410 VAR(IDF_READONLY, modebitbomber, 1, (1<<G_BOMBER), -1);
411 VAR(IDF_READONLY, modebitrace, 1, (1<<G_RACE), -1);
412 VAR(IDF_READONLY, modebitall, 1, G_ALL, -1);
413 SVAR(IDF_READONLY, mutsname, "FFA Coop Instagib Medieval Kaboom Duel Survivor Classic Onslaught Vampire Resize Hard Arena");
414 SVAR(IDF_READONLY, mutsidxname, "ffa coop instagib medieval kaboom duel survivor classic onslaught vampire resize hard arena");
415 VAR(IDF_READONLY, mutsidxffa, 1, G_M_FFA, -1);
416 VAR(IDF_READONLY, mutsidxcoop, 1, G_M_COOP, -1);
417 VAR(IDF_READONLY, mutsidxinstagib, 1, G_M_INSTA, -1);
418 VAR(IDF_READONLY, mutsidxmedieval, 1, G_M_MEDIEVAL, -1);
419 VAR(IDF_READONLY, mutsidxkaboom, 1, G_M_KABOOM, -1);
420 VAR(IDF_READONLY, mutsidxduel, 1, G_M_DUEL, -1);
421 VAR(IDF_READONLY, mutsidxsurvivor, 1, G_M_SURVIVOR, -1);
422 VAR(IDF_READONLY, mutsidxclassic, 1, G_M_CLASSIC, -1);
423 VAR(IDF_READONLY, mutsidxonslaught, 1, G_M_ONSLAUGHT, -1);
424 VAR(IDF_READONLY, mutsidxvampire, 1, G_M_VAMPIRE, -1);
425 VAR(IDF_READONLY, mutsidxresize, 1, G_M_RESIZE, -1);
426 VAR(IDF_READONLY, mutsidxhard, 1, G_M_HARD, -1);
427 VAR(IDF_READONLY, mutsidxarena, 1, G_M_ARENA, -1);
428 VAR(IDF_READONLY, mutsidxgsp1, 1, G_M_GSP1, -1);
429 VAR(IDF_READONLY, mutsidxgsp2, 1, G_M_GSP2, -1);
430 VAR(IDF_READONLY, mutsidxgsp3, 1, G_M_GSP3, -1);
431 VAR(IDF_READONLY, mutsidxgsn, 1, G_M_GSN, -1);
432 VAR(IDF_READONLY, mutsidxgsp, 1, G_M_GSP, -1);
433 VAR(IDF_READONLY, mutsidxnum, 1, G_M_NUM, -1);
434 VAR(IDF_READONLY, mutsidxnormal, 1, G_M_NUM-G_M_GSN, -1);
435 VAR(IDF_READONLY, mutsbitffa, 1, GM(FFA), -1);
436 VAR(IDF_READONLY, mutsbitcoop, 1, GM(COOP), -1);
437 VAR(IDF_READONLY, mutsbitinstagib, 1, GM(INSTA), -1);
438 VAR(IDF_READONLY, mutsbitmedieval, 1, GM(MEDIEVAL), -1);
439 VAR(IDF_READONLY, mutsbitkaboom, 1, GM(KABOOM), -1);
440 VAR(IDF_READONLY, mutsbitduel, 1, GM(DUEL), -1);
441 VAR(IDF_READONLY, mutsbitsurvivor, 1, GM(SURVIVOR), -1);
442 VAR(IDF_READONLY, mutsbitclassic, 1, GM(CLASSIC), -1);
443 VAR(IDF_READONLY, mutsbitonslaught, 1, GM(ONSLAUGHT), -1);
444 VAR(IDF_READONLY, mutsbitvampire, 1, GM(VAMPIRE), -1);
445 VAR(IDF_READONLY, mutsbitresize, 1, GM(RESIZE), -1);
446 VAR(IDF_READONLY, mutsbithard, 1, GM(HARD), -1);
447 VAR(IDF_READONLY, mutsbitarena, 1, GM(ARENA), -1);
448 VAR(IDF_READONLY, mutsbitgsp1, 1, GM(GSP1), -1);
449 VAR(IDF_READONLY, mutsbitgsp2, 1, GM(GSP2), -1);
450 VAR(IDF_READONLY, mutsbitgsp3, 1, GM(GSP3), -1);
451 VAR(IDF_READONLY, mutsbitall, 1, G_M_ALL, -1);
452 #endif
453