1 /*
2 ** gi.cpp
3 ** Holds same game-dependant info
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 #include <stdlib.h>
36 #include "info.h"
37 #include "gi.h"
38 #include "m_fixed.h"
39 #include "v_palette.h"
40 #include "sc_man.h"
41 #include "w_wad.h"
42 #include "i_system.h"
43 #include "v_video.h"
44 #include "g_level.h"
45
46 gameinfo_t gameinfo;
47
48 const char *GameNames[17] =
49 {
50 NULL, "Doom", "Heretic", NULL, "Hexen", NULL, NULL, NULL, "Strife", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Chex"
51 };
52
53
54 static staticgameborder_t DoomBorder =
55 {
56 8, 8,
57 "brdr_tl", "brdr_t", "brdr_tr",
58 "brdr_l", "brdr_r",
59 "brdr_bl", "brdr_b", "brdr_br"
60 };
61
62 static staticgameborder_t HereticBorder =
63 {
64 4, 16,
65 "bordtl", "bordt", "bordtr",
66 "bordl", "bordr",
67 "bordbl", "bordb", "bordbr"
68 };
69
70 static staticgameborder_t StrifeBorder =
71 {
72 8, 8,
73 "brdr_tl", "brdr_t", "brdr_tr",
74 "brdr_l", "brdr_r",
75 "brdr_bl", "brdr_b", "brdr_br"
76 };
77
78 // Custom GAMEINFO ------------------------------------------------------------
79
80 const char* GameInfoBorders[] =
81 {
82 "DoomBorder",
83 "HereticBorder",
84 "StrifeBorder",
85 NULL
86 };
87
88 #define GAMEINFOKEY_CSTRING(key, variable, length) \
89 else if(nextKey.CompareNoCase(variable) == 0) \
90 { \
91 sc.MustGetToken(TK_StringConst); \
92 if(strlen(sc.String) > length) \
93 { \
94 sc.ScriptError("Value for '%s' can not be longer than %d characters.", #key, length); \
95 } \
96 strcpy(gameinfo.key, sc.String); \
97 }
98
99 #define GAMEINFOKEY_STRINGARRAY(key, variable, length, clear) \
100 else if(nextKey.CompareNoCase(variable) == 0) \
101 { \
102 if (clear) gameinfo.key.Clear(); \
103 do \
104 { \
105 sc.MustGetToken(TK_StringConst); \
106 if(length > 0 && strlen(sc.String) > length) \
107 { \
108 sc.ScriptError("Value for '%s' can not be longer than %d characters.", #key, length); \
109 } \
110 gameinfo.key[gameinfo.key.Reserve(1)] = sc.String; \
111 } \
112 while (sc.CheckToken(',')); \
113 }
114
115 #define GAMEINFOKEY_STRING(key, variable) \
116 else if(nextKey.CompareNoCase(variable) == 0) \
117 { \
118 sc.MustGetToken(TK_StringConst); \
119 gameinfo.key = sc.String; \
120 }
121
122 #define GAMEINFOKEY_INT(key, variable) \
123 else if(nextKey.CompareNoCase(variable) == 0) \
124 { \
125 sc.MustGetNumber(); \
126 gameinfo.key = sc.Number; \
127 }
128
129 #define GAMEINFOKEY_FLOAT(key, variable) \
130 else if(nextKey.CompareNoCase(variable) == 0) \
131 { \
132 sc.MustGetFloat(); \
133 gameinfo.key = static_cast<float> (sc.Float); \
134 }
135
136 #define GAMEINFOKEY_FIXED(key, variable) \
137 else if(nextKey.CompareNoCase(variable) == 0) \
138 { \
139 sc.MustGetFloat(); \
140 gameinfo.key = static_cast<int> (sc.Float*FRACUNIT); \
141 }
142
143 #define GAMEINFOKEY_COLOR(key, variable) \
144 else if(nextKey.CompareNoCase(variable) == 0) \
145 { \
146 sc.MustGetToken(TK_StringConst); \
147 FString color = sc.String; \
148 FString colorName = V_GetColorStringByName(color); \
149 if(!colorName.IsEmpty()) \
150 color = colorName; \
151 gameinfo.key = V_GetColorFromString(NULL, color); \
152 }
153
154 #define GAMEINFOKEY_BOOL(key, variable) \
155 else if(nextKey.CompareNoCase(variable) == 0) \
156 { \
157 if(sc.CheckToken(TK_False)) \
158 gameinfo.key = false; \
159 else \
160 { \
161 sc.MustGetToken(TK_True); \
162 gameinfo.key = true; \
163 } \
164 }
165
166 #define GAMEINFOKEY_FONT(key, variable) \
167 else if(nextKey.CompareNoCase(variable) == 0) \
168 { \
169 sc.MustGetToken(TK_StringConst); \
170 gameinfo.key.fontname = sc.String; \
171 if (sc.CheckToken(',')) { \
172 sc.MustGetToken(TK_StringConst); \
173 gameinfo.key.color = sc.String; \
174 } else { \
175 gameinfo.key.color = NAME_None; \
176 } \
177 }
178
179 #define GAMEINFOKEY_PATCH(key, variable) \
180 else if(nextKey.CompareNoCase(variable) == 0) \
181 { \
182 sc.MustGetToken(TK_StringConst); \
183 gameinfo.key.fontname = sc.String; \
184 gameinfo.key.color = NAME_Null; \
185 }
186
187 #define GAMEINFOKEY_MUSIC(key, order, variable) \
188 else if(nextKey.CompareNoCase(variable) == 0) \
189 { \
190 sc.MustGetToken(TK_StringConst); \
191 gameinfo.order = 0; \
192 char *colon = strchr (sc.String, ':'); \
193 if (colon) \
194 { \
195 gameinfo.order = atoi(colon+1); \
196 *colon = 0; \
197 } \
198 gameinfo.key = sc.String; \
199 }
200
201
ParseGameInfo()202 void FMapInfoParser::ParseGameInfo()
203 {
204 sc.MustGetToken('{');
205 while(sc.GetToken())
206 {
207 if (sc.TokenType == '}') return;
208
209 sc.TokenMustBe(TK_Identifier);
210 FString nextKey = sc.String;
211 sc.MustGetToken('=');
212
213 if (nextKey.CompareNoCase("weaponslot") == 0)
214 {
215 sc.MustGetToken(TK_IntConst);
216 if (sc.Number < 0 || sc.Number >= 10)
217 {
218 sc.ScriptError("Weapon slot index must be in range [0..9].\n");
219 }
220 int i = sc.Number;
221 gameinfo.DefaultWeaponSlots[i].Clear();
222 sc.MustGetToken(',');
223 do
224 {
225 sc.MustGetString();
226 FName val = sc.String;
227 gameinfo.DefaultWeaponSlots[i].Push(val);
228
229 }
230 while (sc.CheckToken(','));
231 }
232 else if(nextKey.CompareNoCase("border") == 0)
233 {
234 staticgameborder_t *b;
235 if (sc.CheckToken(TK_Identifier))
236 {
237 switch(sc.MustMatchString(GameInfoBorders))
238 {
239 default:
240 b = &DoomBorder;
241 break;
242 case 1:
243 b = &HereticBorder;
244 break;
245 case 2:
246 b = &StrifeBorder;
247 break;
248 }
249 gameinfo.Border = *b;
250 }
251 else
252 {
253 // border = {size, offset, tr, t, tl, r, l ,br, b, bl};
254 FString *graphics[8] = { &gameinfo.Border.tr, &gameinfo.Border.t, &gameinfo.Border.tl, &gameinfo.Border.r, &gameinfo.Border.l, &gameinfo.Border.br, &gameinfo.Border.b, &gameinfo.Border.bl };
255 sc.MustGetToken(TK_IntConst);
256 gameinfo.Border.offset = sc.Number;
257 sc.MustGetToken(',');
258 sc.MustGetToken(TK_IntConst);
259 gameinfo.Border.size = sc.Number;
260 for(int i = 0;i < 8;i++)
261 {
262 sc.MustGetToken(',');
263 sc.MustGetToken(TK_StringConst);
264 (*graphics[i]) = sc.String;
265 }
266 }
267 }
268 else if(nextKey.CompareNoCase("armoricons") == 0)
269 {
270 sc.MustGetToken(TK_StringConst);
271 gameinfo.ArmorIcon1 = sc.String;
272 if (sc.CheckToken(','))
273 {
274 sc.MustGetToken(TK_FloatConst);
275 gameinfo.Armor2Percent = FLOAT2FIXED(sc.Float);
276 sc.MustGetToken(',');
277 sc.MustGetToken(TK_StringConst);
278 gameinfo.ArmorIcon2 = sc.String;
279 }
280 }
281 else if(nextKey.CompareNoCase("maparrow") == 0)
282 {
283 sc.MustGetToken(TK_StringConst);
284 gameinfo.mMapArrow = sc.String;
285 if (sc.CheckToken(','))
286 {
287 sc.MustGetToken(TK_StringConst);
288 gameinfo.mCheatMapArrow = sc.String;
289 }
290 else gameinfo.mCheatMapArrow = "";
291 }
292 // Insert valid keys here.
293 GAMEINFOKEY_STRING(mCheatKey, "cheatKey")
294 GAMEINFOKEY_STRING(mEasyKey, "easyKey")
295 GAMEINFOKEY_STRING(TitlePage, "titlePage")
296 GAMEINFOKEY_STRINGARRAY(creditPages, "addcreditPage", 8, false)
297 GAMEINFOKEY_STRINGARRAY(creditPages, "CreditPage", 8, true)
298 GAMEINFOKEY_STRINGARRAY(PlayerClasses, "addplayerclasses", 0, false)
299 GAMEINFOKEY_STRINGARRAY(PlayerClasses, "playerclasses", 0, true)
300 GAMEINFOKEY_MUSIC(titleMusic, titleOrder, "titleMusic")
301 GAMEINFOKEY_FLOAT(titleTime, "titleTime")
302 GAMEINFOKEY_FLOAT(advisoryTime, "advisoryTime")
303 GAMEINFOKEY_FLOAT(pageTime, "pageTime")
304 GAMEINFOKEY_STRING(chatSound, "chatSound")
305 GAMEINFOKEY_MUSIC(finaleMusic, finaleOrder, "finaleMusic")
306 GAMEINFOKEY_STRING(FinaleFlat, "finaleFlat")
307 GAMEINFOKEY_STRINGARRAY(finalePages, "finalePage", 8, true)
308 GAMEINFOKEY_STRINGARRAY(infoPages, "addinfoPage", 8, false)
309 GAMEINFOKEY_STRINGARRAY(infoPages, "infoPage", 8, true)
310 GAMEINFOKEY_STRING(PauseSign, "pausesign")
311 GAMEINFOKEY_STRING(quitSound, "quitSound")
312 GAMEINFOKEY_STRING(BorderFlat, "borderFlat")
313 GAMEINFOKEY_FIXED(telefogheight, "telefogheight")
314 GAMEINFOKEY_FIXED(gibfactor, "gibfactor")
315 GAMEINFOKEY_INT(defKickback, "defKickback")
316 GAMEINFOKEY_STRING(SkyFlatName, "SkyFlatName")
317 GAMEINFOKEY_STRING(translator, "translator")
318 GAMEINFOKEY_COLOR(pickupcolor, "pickupcolor")
319 GAMEINFOKEY_COLOR(defaultbloodcolor, "defaultbloodcolor")
320 GAMEINFOKEY_COLOR(defaultbloodparticlecolor, "defaultbloodparticlecolor")
321 GAMEINFOKEY_STRING(backpacktype, "backpacktype")
322 GAMEINFOKEY_STRING(statusbar, "statusbar")
323 GAMEINFOKEY_MUSIC(intermissionMusic, intermissionOrder, "intermissionMusic")
324 GAMEINFOKEY_STRING(CursorPic, "CursorPic")
325 GAMEINFOKEY_BOOL(noloopfinalemusic, "noloopfinalemusic")
326 GAMEINFOKEY_BOOL(drawreadthis, "drawreadthis")
327 GAMEINFOKEY_BOOL(swapmenu, "swapmenu")
328 GAMEINFOKEY_BOOL(dontcrunchcorpses, "dontcrunchcorpses")
329 GAMEINFOKEY_BOOL(intermissioncounter, "intermissioncounter")
330 GAMEINFOKEY_BOOL(nightmarefast, "nightmarefast")
331 GAMEINFOKEY_COLOR(dimcolor, "dimcolor")
332 GAMEINFOKEY_FLOAT(dimamount, "dimamount")
333 GAMEINFOKEY_INT(definventorymaxamount, "definventorymaxamount")
334 GAMEINFOKEY_INT(defaultrespawntime, "defaultrespawntime")
335 GAMEINFOKEY_INT(defaultrespawntime, "defaultrespawntime")
336 GAMEINFOKEY_INT(defaultdropstyle, "defaultdropstyle")
337 GAMEINFOKEY_STRING(Endoom, "endoom")
338 GAMEINFOKEY_STRINGARRAY(quitmessages, "addquitmessages", 0, false)
339 GAMEINFOKEY_STRINGARRAY(quitmessages, "quitmessages", 0, true)
340 GAMEINFOKEY_STRING(mTitleColor, "menufontcolor_title")
341 GAMEINFOKEY_STRING(mFontColor, "menufontcolor_label")
342 GAMEINFOKEY_STRING(mFontColorValue, "menufontcolor_value")
343 GAMEINFOKEY_STRING(mFontColorMore, "menufontcolor_action")
344 GAMEINFOKEY_STRING(mFontColorHeader, "menufontcolor_header")
345 GAMEINFOKEY_STRING(mFontColorHighlight, "menufontcolor_highlight")
346 GAMEINFOKEY_STRING(mFontColorSelection, "menufontcolor_selection")
347 GAMEINFOKEY_STRING(mBackButton, "menubackbutton")
348 GAMEINFOKEY_INT(TextScreenX, "textscreenx")
349 GAMEINFOKEY_INT(TextScreenY, "textscreeny")
350 GAMEINFOKEY_STRING(DefaultEndSequence, "defaultendsequence")
351 GAMEINFOKEY_FONT(mStatscreenMapNameFont, "statscreen_mapnamefont")
352 GAMEINFOKEY_FONT(mStatscreenFinishedFont, "statscreen_finishedfont")
353 GAMEINFOKEY_FONT(mStatscreenEnteringFont, "statscreen_enteringfont")
354 GAMEINFOKEY_PATCH(mStatscreenFinishedFont, "statscreen_finishedpatch")
355 GAMEINFOKEY_PATCH(mStatscreenEnteringFont, "statscreen_enteringpatch")
356 GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass")
357
358 else
359 {
360 // ignore unkown keys.
361 sc.UnGet();
362 SkipToNext();
363 }
364 }
365 }
366
GetFinalePage(unsigned int num) const367 const char *gameinfo_t::GetFinalePage(unsigned int num) const
368 {
369 if (finalePages.Size() == 0) return "-NOFLAT-";
370 else if (num < 1 || num > finalePages.Size()) return finalePages[0];
371 else return finalePages[num-1];
372 }
373