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