1 /*
2  * OpenTyrian: A modern cross-platform port of Tyrian
3  * Copyright (C) 2007-2009  The OpenTyrian Development Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19 #include "config.h"
20 #include "episodes.h"
21 #include "file.h"
22 #include "fonthand.h"
23 #include "helptext.h"
24 #include "menus.h"
25 #include "opentyr.h"
26 #include "video.h"
27 
28 #include <assert.h>
29 #include <string.h>
30 
31 
32 const JE_byte menuHelp[MENU_MAX][11] = /* [1..maxmenu, 1..11] */
33 {
34 	{  1, 34,  2,  3,  4,  5,                  0, 0, 0, 0, 0 },
35 	{  6,  7,  8,  9, 10, 11, 11, 12,                0, 0, 0 },
36 	{ 13, 14, 15, 15, 16, 17, 12,                 0, 0, 0, 0 },
37 	{                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
38 	{                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
39 	{                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
40 	{                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
41 	{                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
42 	{                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
43 	{  4, 30, 30,  3,  5,                   0, 0, 0, 0, 0, 0 },
44 	{                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
45 	{ 16, 17, 15, 15, 12,                   0, 0, 0, 0, 0, 0 },
46 	{ 31, 31, 31, 31, 32, 12,                  0, 0, 0, 0, 0 },
47 	{  4, 34,  3,  5,                    0, 0, 0, 0, 0, 0, 0 }
48 };
49 
50 JE_byte verticalHeight = 7;
51 JE_byte helpBoxColor = 12;
52 JE_byte helpBoxBrightness = 1;
53 JE_byte helpBoxShadeType = FULL_SHADE;
54 
55 char helpTxt[39][231];                                                   /* [1..39] of string [230] */
56 char pName[21][16];                                                      /* [1..21] of string [15] */
57 char miscText[HELPTEXT_MISCTEXT_COUNT][42];                              /* [1..68] of string [41] */
58 char miscTextB[HELPTEXT_MISCTEXTB_COUNT][HELPTEXT_MISCTEXTB_SIZE];       /* [1..5] of string [10] */
59 char keyName[8][18];                                                     /* [1..8] of string [17] */
60 char menuText[7][HELPTEXT_MENUTEXT_SIZE];                                /* [1..7] of string [20] */
61 char outputs[9][31];                                                     /* [1..9] of string [30] */
62 char topicName[6][21];                                                   /* [1..6] of string [20] */
63 char mainMenuHelp[HELPTEXT_MAINMENUHELP_COUNT][66];                      /* [1..34] of string [65] */
64 char inGameText[6][21];                                                  /* [1..6] of string [20] */
65 char detailLevel[6][13];                                                 /* [1..6] of string [12] */
66 char gameSpeedText[5][13];                                               /* [1..5] of string [12] */
67 char inputDevices[3][13];                                                /* [1..3] of string [12] */
68 char networkText[HELPTEXT_NETWORKTEXT_COUNT][HELPTEXT_NETWORKTEXT_SIZE]; /* [1..4] of string [20] */
69 char difficultyNameB[11][21];                                            /* [0..9] of string [20] */
70 char joyButtonNames[5][21];                                              /* [1..5] of string [20] */
71 char superShips[HELPTEXT_SUPERSHIPS_COUNT][26];                          /* [0..10] of string [25] */
72 char specialName[HELPTEXT_SPECIALNAME_COUNT][10];                        /* [1..9] of string [9] */
73 char destructHelp[25][22];                                               /* [1..25] of string [21] */
74 char weaponNames[17][17];                                                /* [1..17] of string [16] */
75 char destructModeName[DESTRUCT_MODES][13];                               /* [1..destructmodes] of string [12] */
76 char shipInfo[HELPTEXT_SHIPINFO_COUNT][2][256];                          /* [1..13, 1..2] of string */
77 char menuInt[MENU_MAX+1][11][18];                                        /* [0..14, 1..11] of string [17] */
78 
79 
decrypt_pascal_string(char * s,int len)80 void decrypt_pascal_string( char *s, int len )
81 {
82 	static const unsigned char crypt_key[] = { 204, 129, 63, 255, 71, 19, 25, 62, 1, 99 };
83 
84 	for (int i = len - 1; i >= 0; --i)
85 	{
86 		s[i] ^= crypt_key[i % sizeof(crypt_key)];
87 		if (i > 0)
88 			s[i] ^= s[i - 1];
89 	}
90 }
91 
read_encrypted_pascal_string(char * s,int size,FILE * f)92 void read_encrypted_pascal_string( char *s, int size, FILE *f )
93 {
94 	int len = getc(f);
95 	if (len != EOF)
96 	{
97 		int skip = MAX((len + 1) - size, 0);
98 		assert(skip == 0);
99 
100 		len -= skip;
101 		efread(s, 1, len, f);
102 		if (size > 0)
103 			s[len] = '\0';
104 		fseek(f, skip, SEEK_CUR);
105 
106 		decrypt_pascal_string(s, len);
107 	}
108 }
109 
skip_pascal_string(FILE * f)110 void skip_pascal_string( FILE *f )
111 {
112 	int len = getc(f);
113 	fseek(f, len, SEEK_CUR);
114 }
115 
JE_helpBox(SDL_Surface * screen,int x,int y,const char * message,unsigned int boxwidth)116 void JE_helpBox( SDL_Surface *screen,  int x, int y, const char *message, unsigned int boxwidth )
117 {
118 	JE_byte startpos, endpos, pos;
119 	JE_boolean endstring;
120 
121 	char substring[256];
122 
123 	if (strlen(message) == 0)
124 	{
125 		return;
126 	}
127 
128 	pos = 1;
129 	endpos = 0;
130 	endstring = false;
131 
132 	do
133 	{
134 		startpos = endpos + 1;
135 
136 		do
137 		{
138 			endpos = pos;
139 			do
140 			{
141 				pos++;
142 				if (pos == strlen(message))
143 				{
144 					endstring = true;
145 					if ((unsigned)(pos - startpos) < boxwidth)
146 					{
147 						endpos = pos + 1;
148 					}
149 				}
150 
151 			} while (!(message[pos-1] == ' ' || endstring));
152 
153 		} while (!((unsigned)(pos - startpos) > boxwidth || endstring));
154 
155 		JE_textShade(screen, x, y, strnztcpy(substring, message + startpos - 1, endpos - startpos), helpBoxColor, helpBoxBrightness, helpBoxShadeType);
156 
157 		y += verticalHeight;
158 
159 	} while (!endstring);
160 
161 	if (endpos != pos + 1)
162 	{
163 		JE_textShade(screen, x, y, message + endpos, helpBoxColor, helpBoxBrightness, helpBoxShadeType);
164 	}
165 
166 	helpBoxColor = 12;
167 	helpBoxShadeType = FULL_SHADE;
168 }
169 
JE_HBox(SDL_Surface * screen,int x,int y,unsigned int messagenum,unsigned int boxwidth)170 void JE_HBox( SDL_Surface *screen, int x, int y, unsigned int  messagenum, unsigned int boxwidth )
171 {
172 	JE_helpBox(screen, x, y, helpTxt[messagenum-1], boxwidth);
173 }
174 
JE_loadHelpText(void)175 void JE_loadHelpText( void )
176 {
177 #ifdef TYRIAN2000
178 	const unsigned int menuInt_entries[MENU_MAX + 1] = { -1, 7, 9, 9, -1, -1, 11, -1, -1, -1, 7, 4, 6, 7, 5 };
179 #else
180 	const unsigned int menuInt_entries[MENU_MAX + 1] = { -1, 7, 9, 8, -1, -1, 11, -1, -1, -1, 6, 4, 6, 7, 5 };
181 #endif
182 
183 	FILE *f = dir_fopen_die(data_dir(), "tyrian.hdt", "rb");
184 	efread(&episode1DataLoc, sizeof(JE_longint), 1, f);
185 
186 	/*Online Help*/
187 	skip_pascal_string(f);
188 	for (unsigned int i = 0; i < COUNTOF(helpTxt); ++i)
189 		read_encrypted_pascal_string(helpTxt[i], sizeof(helpTxt[i]), f);
190 	skip_pascal_string(f);
191 
192 	/*Planet names*/
193 	skip_pascal_string(f);
194 	for (unsigned int i = 0; i < COUNTOF(pName); ++i)
195 		read_encrypted_pascal_string(pName[i], sizeof(pName[i]), f);
196 	skip_pascal_string(f);
197 
198 	/*Miscellaneous text*/
199 	skip_pascal_string(f);
200 	for (unsigned int i = 0; i < COUNTOF(miscText); ++i)
201 		read_encrypted_pascal_string(miscText[i], sizeof(miscText[i]), f);
202 	skip_pascal_string(f);
203 
204 	/*Little Miscellaneous text*/
205 	skip_pascal_string(f);
206 	for (unsigned int i = 0; i < COUNTOF(miscTextB); ++i)
207 		read_encrypted_pascal_string(miscTextB[i], sizeof(miscTextB[i]), f);
208 	skip_pascal_string(f);
209 
210 	/*Key names*/
211 	skip_pascal_string(f);
212 	for (unsigned int i = 0; i < menuInt_entries[6]; ++i)
213 		read_encrypted_pascal_string(menuInt[6][i], sizeof(menuInt[6][i]), f);
214 	skip_pascal_string(f);
215 
216 	/*Main Menu*/
217 	skip_pascal_string(f);
218 	for (unsigned int i = 0; i < COUNTOF(menuText); ++i)
219 		read_encrypted_pascal_string(menuText[i], sizeof(menuText[i]), f);
220 	skip_pascal_string(f);
221 
222 	/*Event text*/
223 	skip_pascal_string(f);
224 	for (unsigned int i = 0; i < COUNTOF(outputs); ++i)
225 		read_encrypted_pascal_string(outputs[i], sizeof(outputs[i]), f);
226 	skip_pascal_string(f);
227 
228 	/*Help topics*/
229 	skip_pascal_string(f);
230 	for (unsigned int i = 0; i < COUNTOF(topicName); ++i)
231 		read_encrypted_pascal_string(topicName[i], sizeof(topicName[i]), f);
232 	skip_pascal_string(f);
233 
234 	/*Main Menu Help*/
235 	skip_pascal_string(f);
236 	for (unsigned int i = 0; i < COUNTOF(mainMenuHelp); ++i)
237 		read_encrypted_pascal_string(mainMenuHelp[i], sizeof(mainMenuHelp[i]), f);
238 	skip_pascal_string(f);
239 
240 	/*Menu 1 - Main*/
241 	skip_pascal_string(f);
242 	for (unsigned int i = 0; i < menuInt_entries[1]; ++i)
243 		read_encrypted_pascal_string(menuInt[1][i], sizeof(menuInt[1][i]), f);
244 	skip_pascal_string(f);
245 
246 	/*Menu 2 - Items*/
247 	skip_pascal_string(f);
248 	for (unsigned int i = 0; i < menuInt_entries[2]; ++i)
249 		read_encrypted_pascal_string(menuInt[2][i], sizeof(menuInt[2][i]), f);
250 	skip_pascal_string(f);
251 
252 	/*Menu 3 - Options*/
253 	skip_pascal_string(f);
254 	for (unsigned int i = 0; i < menuInt_entries[3]; ++i)
255 		read_encrypted_pascal_string(menuInt[3][i], sizeof(menuInt[3][i]), f);
256 	skip_pascal_string(f);
257 
258 	/*InGame Menu*/
259 	skip_pascal_string(f);
260 	for (unsigned int i = 0; i < COUNTOF(inGameText); ++i)
261 		read_encrypted_pascal_string(inGameText[i], sizeof(inGameText[i]), f);
262 	skip_pascal_string(f);
263 
264 	/*Detail Level*/
265 	skip_pascal_string(f);
266 	for (unsigned int i = 0; i < COUNTOF(detailLevel); ++i)
267 		read_encrypted_pascal_string(detailLevel[i], sizeof(detailLevel[i]), f);
268 	skip_pascal_string(f);
269 
270 	/*Game speed text*/
271 	skip_pascal_string(f);
272 	for (unsigned int i = 0; i < COUNTOF(gameSpeedText); ++i)
273 		read_encrypted_pascal_string(gameSpeedText[i], sizeof(gameSpeedText[i]), f);
274 	skip_pascal_string(f);
275 
276 	// episode names
277 	skip_pascal_string(f);
278 	for (unsigned int i = 0; i < COUNTOF(episode_name); ++i)
279 		read_encrypted_pascal_string(episode_name[i], sizeof(episode_name[i]), f);
280 	skip_pascal_string(f);
281 
282 	// difficulty names
283 	skip_pascal_string(f);
284 	for (unsigned int i = 0; i < COUNTOF(difficulty_name); ++i)
285 		read_encrypted_pascal_string(difficulty_name[i], sizeof(difficulty_name[i]), f);
286 	skip_pascal_string(f);
287 
288 	// gameplay mode names
289 	skip_pascal_string(f);
290 	for (unsigned int i = 0; i < COUNTOF(gameplay_name); ++i)
291 		read_encrypted_pascal_string(gameplay_name[i], sizeof(gameplay_name[i]), f);
292 	skip_pascal_string(f);
293 
294 	/*Menu 10 - 2Player Main*/
295 	skip_pascal_string(f);
296 	for (unsigned int i = 0; i < menuInt_entries[10]; ++i)
297 		read_encrypted_pascal_string(menuInt[10][i], sizeof(menuInt[10][i]), f);
298 	skip_pascal_string(f);
299 
300 	/*Input Devices*/
301 	skip_pascal_string(f);
302 	for (unsigned int i = 0; i < COUNTOF(inputDevices); ++i)
303 		read_encrypted_pascal_string(inputDevices[i], sizeof(inputDevices[i]), f);
304 	skip_pascal_string(f);
305 
306 	/*Network text*/
307 	skip_pascal_string(f);
308 	for (unsigned int i = 0; i < COUNTOF(networkText); ++i)
309 		read_encrypted_pascal_string(networkText[i], sizeof(networkText[i]), f);
310 	skip_pascal_string(f);
311 
312 	/*Menu 11 - 2Player Network*/
313 	skip_pascal_string(f);
314 	for (unsigned int i = 0; i < menuInt_entries[11]; ++i)
315 		read_encrypted_pascal_string(menuInt[11][i], sizeof(menuInt[11][i]), f);
316 	skip_pascal_string(f);
317 
318 	/*HighScore Difficulty Names*/
319 	skip_pascal_string(f);
320 	for (unsigned int i = 0; i < COUNTOF(difficultyNameB); ++i)
321 		read_encrypted_pascal_string(difficultyNameB[i], sizeof(difficultyNameB[i]), f);
322 	skip_pascal_string(f);
323 
324 	/*Menu 12 - Network Options*/
325 	skip_pascal_string(f);
326 	for (unsigned int i = 0; i < menuInt_entries[12]; ++i)
327 		read_encrypted_pascal_string(menuInt[12][i], sizeof(menuInt[12][i]), f);
328 	skip_pascal_string(f);
329 
330 	/*Menu 13 - Joystick*/
331 	skip_pascal_string(f);
332 	for (unsigned int i = 0; i < menuInt_entries[13]; ++i)
333 		read_encrypted_pascal_string(menuInt[13][i], sizeof(menuInt[13][i]), f);
334 	skip_pascal_string(f);
335 
336 	/*Joystick Button Assignments*/
337 	skip_pascal_string(f);
338 	for (unsigned int i = 0; i < COUNTOF(joyButtonNames); ++i)
339 		read_encrypted_pascal_string(joyButtonNames[i], sizeof(joyButtonNames[i]), f);
340 	skip_pascal_string(f);
341 
342 	/*SuperShips - For Super Arcade Mode*/
343 	skip_pascal_string(f);
344 	for (unsigned int i = 0; i < COUNTOF(superShips); ++i)
345 		read_encrypted_pascal_string(superShips[i], sizeof(superShips[i]), f);
346 	skip_pascal_string(f);
347 
348 	/*SuperShips - For Super Arcade Mode*/
349 	skip_pascal_string(f);
350 	for (unsigned int i = 0; i < COUNTOF(specialName); ++i)
351 		read_encrypted_pascal_string(specialName[i], sizeof(specialName[i]), f);
352 	skip_pascal_string(f);
353 
354 	/*Secret DESTRUCT game*/
355 	skip_pascal_string(f);
356 	for (unsigned int i = 0; i < COUNTOF(destructHelp); ++i)
357 		read_encrypted_pascal_string(destructHelp[i], sizeof(destructHelp[i]), f);
358 	skip_pascal_string(f);
359 
360 	/*Secret DESTRUCT weapons*/
361 	skip_pascal_string(f);
362 	for (unsigned int i = 0; i < COUNTOF(weaponNames); ++i)
363 		read_encrypted_pascal_string(weaponNames[i], sizeof(weaponNames[i]), f);
364 	skip_pascal_string(f);
365 
366 	/*Secret DESTRUCT modes*/
367 	skip_pascal_string(f);
368 	for (unsigned int i = 0; i < COUNTOF(destructModeName); ++i)
369 		read_encrypted_pascal_string(destructModeName[i], sizeof(destructModeName[i]), f);
370 	skip_pascal_string(f);
371 
372 	/*NEW: Ship Info*/
373 	skip_pascal_string(f);
374 	for (unsigned int i = 0; i < COUNTOF(shipInfo); ++i)
375 	{
376 		read_encrypted_pascal_string(shipInfo[i][0], sizeof(shipInfo[i][0]), f);
377 		read_encrypted_pascal_string(shipInfo[i][1], sizeof(shipInfo[i][1]), f);
378 	}
379 	skip_pascal_string(f);
380 
381 #ifndef TYRIAN2000
382 	/*Menu 12 - Network Options*/
383 	skip_pascal_string(f);
384 	for (unsigned int i = 0; i < menuInt_entries[14]; ++i)
385 		read_encrypted_pascal_string(menuInt[14][i], sizeof(menuInt[14][i]), f);
386 #endif
387 
388 	fclose(f);
389 }
390 
391