1 /*
2 * IceBreaker
3 * Copyright (c) 2002 Matthew Miller <mattdm@mattdm.org>
4 *
5 * <http://www.mattdm.org/icebreaker/>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc., 59
19 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23 #include <SDL.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include "icebreaker.h"
31 #include "globals.h"
32 #include "options.h"
33 #include "sound.h"
34 #include "themes.h"
35
36 ThemeColorsType color;
37 SDL_Surface* spriteimage=NULL;
38 SDL_Surface* spritemirrorimage=NULL;
39
40 static int setrandomtheme();
41 static void setdefaultcolors();
42 static SDL_Surface* loadsprite(char* themename, char* imagefile);
43
44 static int alphasortstringarray(const void *a, const void *b);
45
getthemenames(char *** themenamelist)46 int getthemenames(char*** themenamelist)
47 {
48 int s;
49 int numthemes;
50 int listsize=8;
51 char **listtemp;
52
53 struct dirent* dirtemp;
54 DIR* themedir;
55
56 *themenamelist=malloc(sizeof(char*)*listsize);
57 if (themenamelist==NULL)
58 {
59 fprintf(stderr,"Error: Couldn't get memory to get list of themes. That's bad.\n");
60 return -2;
61 }
62
63 themedir=opendir(DATAPREFIX);
64 if (themedir==NULL)
65 {
66 fprintf(stderr, "Couldn't list data directory. This is going to be a problem.\n");
67 return -1;
68 }
69
70
71 numthemes=0;
72 while ((dirtemp = readdir(themedir)) != NULL)
73 {
74 if (strlen(dirtemp->d_name) <= strlen(THEMEFILEEXTENSION))
75 {
76 // filename too short
77
78 // this space intentionally left blank
79 }
80 else if (strcasecmp( THEMEFILEEXTENSION, dirtemp->d_name+(strlen(dirtemp->d_name)-strlen(THEMEFILEEXTENSION)) ))
81 {
82 // wrong extension
83
84 // this space intentionally left blank
85 }
86 else if (strlen(dirtemp->d_name)-strlen(THEMEFILEEXTENSION)>MAXTHEMENAMELENGTH)
87 {
88 fprintf(stderr, "Theme name %s is too long.\n"
89 "For display reasons, the maximum allowed is %d + %s.\n",dirtemp->d_name,MAXTHEMENAMELENGTH,THEMEFILEEXTENSION);
90 }
91 else
92 { // Valid theme name found
93
94 if (numthemes>=listsize)
95 {
96 // trying to put numthemes+1 themes in a listsize-sized bucket
97 // so double the size of the bucket.
98 listsize *= 2;
99 listtemp = (char **) realloc (*themenamelist,sizeof(char*)*listsize);
100 if (listtemp == NULL)
101 {
102 fprintf(stderr, "Warning: No more memory for theme names.\n");
103 break;
104 }
105 *themenamelist = listtemp;
106
107 }
108
109 s=strlen(dirtemp->d_name)-strlen(THEMEFILEEXTENSION)+1;
110 (*themenamelist)[numthemes]=malloc(s);
111 if ((*themenamelist)[numthemes]==NULL)
112 {
113 fprintf(stderr, "Error: couldn't get memory for theme name entry '%s' (#%d).\n"
114 "Trying to continue with what we've got.\n",dirtemp->d_name,numthemes);
115 }
116 else
117 {
118 snprintf((*themenamelist)[numthemes],s,"%s",dirtemp->d_name);
119 numthemes++;
120 }
121 }
122 }
123
124 closedir(themedir);
125
126 qsort(*themenamelist,numthemes,sizeof(**themenamelist),alphasortstringarray);
127
128 return numthemes;
129 }
130
freethemenames(char *** themenamelist,int numthemes)131 void freethemenames(char*** themenamelist,int numthemes)
132 {
133 int i;
134 for (i=0;i<numthemes;i++)
135 {
136 free((*themenamelist)[i]);
137 }
138 if (numthemes>0) free(*themenamelist);
139 }
140
settheme(char * themename)141 int settheme(char* themename)
142 {
143 int rc=0;
144 int i;
145 FILE* themefile;
146 char linebuf[300];
147 char themefilename[256]; // fix -- use defined OS constant (here and throughout this function)
148 char optbuf[21];
149 char valbuf[256];
150 char loadfilebuf[256];
151 int r,g,b;
152 ThemeColorsType foundcolor;
153
154 if (!strcmp(themename,"random"))
155 {
156 return setrandomtheme(); // whooo recursion!
157 }
158
159 setdefaultcolors();
160 if (spritemirrorimage==spriteimage) spritemirrorimage=NULL; // don't want to double free!
161 if (spriteimage!=NULL)
162 {
163 SDL_FreeSurface(spriteimage);
164 spriteimage=NULL;
165 }
166 if (spritemirrorimage!=NULL)
167 {
168 SDL_FreeSurface(spritemirrorimage);
169 spritemirrorimage=NULL;
170 }
171
172 foundcolor.background = 0;
173 foundcolor.normaltext = 0;
174 foundcolor.gridline = 0;
175 foundcolor.gridhighlight = 0;
176 foundcolor.line1 = 0;
177 foundcolor.line2 = 0;
178 foundcolor.menuhighlight = 0;
179 foundcolor.gameovertext = 0;
180 foundcolor.scorescrolltext = 0;
181 foundcolor.bonusscrolltext = 0;
182 foundcolor.textentrybox = 0;
183 foundcolor.textentrytext = 0;
184 foundcolor.copyrighttext = 0;
185
186 foundcolor.boardfillminr = 0;
187 foundcolor.boardfillming = 0;
188 foundcolor.boardfillminb = 0;
189 foundcolor.boardfillmaxr = 0;
190 foundcolor.boardfillmaxg = 0;
191 foundcolor.boardfillmaxb = 0;
192
193 foundcolor.spritetransparent = 0;
194
195 snprintf(themefilename, sizeof(themefilename),"%s/%s%s",DATAPREFIX,themename,THEMEFILEEXTENSION);
196
197 themefile=fopen(themefilename,"r");
198 if (themefile==NULL)
199 {
200 // FIX -- ??? question: should this actually change the
201 // current setting, or is leaving it at the currently-unavailable
202 // value the right thing to do?
203 fprintf(stderr, "Warning: Can't open theme file %s.\n"
204 "Using default look and sound.\n",themefilename);
205 rc=-18;
206 }
207 else
208 {
209 while(fgets(linebuf,300,themefile))
210 {
211 for (i=0;i<300;i++)
212 {
213 if (linebuf[i]=='\0' || linebuf[i]==' ' || linebuf[i]=='\t') break;
214 linebuf[i]=tolower(linebuf[i]);
215 }
216
217 if (sscanf(linebuf,"%20s %5d %5d %5d",optbuf,&r,&g,&b)==4)
218 {
219 //printf("N: %s = %d,%d,%d\n",optbuf,r,g,b);
220
221 if (r<0 || r>255)
222 {
223 fprintf(stderr,"Warning: invalid red value for %s in theme %s\n",optbuf,themename);
224 r=0;
225 }
226 if (g<0 || g>255)
227 {
228 fprintf(stderr,"Warning: invalid green value for %s in theme %s\n",optbuf,themename);
229 g=0;
230 }
231 if (b<0 || b>255)
232 {
233 fprintf(stderr,"Warning: invalid blue value for %s in theme %s\n",optbuf,themename);
234 b=0;
235 }
236
237 if (!strcmp(optbuf,"background"))
238 {
239 color.background=SDL_MapRGB(screen->format,r,g,b);
240 foundcolor.background++;
241 }
242 else if (!strcmp(optbuf,"normaltext"))
243 {
244 color.normaltext=SDL_MapRGB(screen->format,r,g,b);
245 foundcolor.normaltext++;
246 }
247 else if (!strcmp(optbuf,"boardfillmin"))
248 {
249 color.boardfillminr=r;
250 color.boardfillming=g;
251 color.boardfillminb=b;
252 foundcolor.boardfillminr++;
253 foundcolor.boardfillming++;
254 foundcolor.boardfillminb++;
255
256 }
257 else if (!strcmp(optbuf,"boardfillmax"))
258 {
259 color.boardfillmaxr=r;
260 color.boardfillmaxg=g;
261 color.boardfillmaxb=b;
262 foundcolor.boardfillmaxr++;
263 foundcolor.boardfillmaxg++;
264 foundcolor.boardfillmaxb++;
265 }
266 else if (!strcmp(optbuf,"gridline"))
267 {
268 color.gridline=SDL_MapRGB(screen->format,r,g,b);
269 foundcolor.gridline++;
270 }
271 else if (!strcmp(optbuf,"gridhighlight"))
272 {
273 color.gridhighlight=SDL_MapRGB(screen->format,r,g,b);
274 foundcolor.gridhighlight++;
275 }
276 else if (!strcmp(optbuf,"line1"))
277 {
278 color.line1=SDL_MapRGB(screen->format,r,g,b);
279 foundcolor.line1++;
280 }
281 else if (!strcmp(optbuf,"line2"))
282 {
283 color.line2=SDL_MapRGB(screen->format,r,g,b);
284 foundcolor.line2++;
285 }
286 else if (!strcmp(optbuf,"menuhighlight"))
287 {
288 color.menuhighlight=SDL_MapRGB(screen->format,r,g,b);
289 foundcolor.menuhighlight++;
290
291 }
292 else if (!strcmp(optbuf,"gameovertext"))
293 {
294 color.gameovertext=SDL_MapRGB(screen->format,r,g,b);
295 foundcolor.gameovertext++;
296 }
297 else if (!strcmp(optbuf,"scorescrolltext"))
298 {
299 color.scorescrolltext=SDL_MapRGB(screen->format,r,g,b);
300 foundcolor.scorescrolltext++;
301 }
302 else if (!strcmp(optbuf,"bonusscrolltext"))
303 {
304 color.bonusscrolltext=SDL_MapRGB(screen->format,r,g,b);
305 foundcolor.bonusscrolltext++;
306 }
307 else if (!strcmp(optbuf,"textentrybox"))
308 {
309 color.textentrybox=SDL_MapRGB(screen->format,r,g,b);
310 foundcolor.textentrybox++;
311
312 }
313 else if (!strcmp(optbuf,"textentrytext"))
314 {
315 color.textentrytext=SDL_MapRGB(screen->format,r,g,b);
316 foundcolor.textentrytext++;
317 }
318 else if (!strcmp(optbuf,"copyrighttext"))
319 {
320 color.copyrighttext=SDL_MapRGB(screen->format,r,g,b);
321 foundcolor.copyrighttext++;
322
323 }
324 else if (!strcmp(optbuf,"spritetransparent"))
325 {
326 color.spritetransparent=SDL_MapRGB(screen->format,r,g,b);
327 foundcolor.spritetransparent++;
328 }
329 }
330 else if (sscanf(linebuf,"%20s %255s",optbuf,valbuf)==2)
331 {
332 //printf("S: %s = %s\n",optbuf,valbuf);
333 if (!strcmp(optbuf,"spritebitmap"))
334 {
335 if (strcasecmp( ".bmp", valbuf+(strlen(valbuf)-strlen(".bmp")) ))
336 {
337 fprintf(stderr,"Warning: Sprite bitmap file in theme %s does not end with '.bmp'.\n"
338 "We'll try to load it anyway, but don't be surpised if there's a problem.\n"
339 "(Filename is %s)\n",themename,valbuf);
340 }
341 snprintf(loadfilebuf, sizeof(loadfilebuf),"%s/%s",DATAPREFIX,valbuf);
342 spriteimage=loadsprite(themename,loadfilebuf);
343 }
344 else if (!strcmp(optbuf,"spritemirrorbitmap"))
345 {
346 if (strcasecmp( ".bmp", valbuf+(strlen(valbuf)-strlen(".bmp")) ))
347 {
348 fprintf(stderr,"Warning: Sprite bitmap file in theme %s does not end with '.bmp'.\n"
349 "We'll try to load it anyway, but don't be surpised if there's a problem.\n"
350 "(Filename is %s)\n",themename,valbuf);
351 }
352 snprintf(loadfilebuf, sizeof(loadfilebuf),"%s/%s",DATAPREFIX,valbuf);
353 spritemirrorimage=loadsprite(themename,loadfilebuf);
354 }
355 else if (!strcmp(optbuf,"soundouch"))
356 {
357 if (strcasecmp( ".wav", valbuf+(strlen(valbuf)-strlen(".wav")) ))
358 {
359 fprintf(stderr,"Warning: Ouch sound file in theme %s does not end with '.wav'.\n"
360 "We'll try to load it anyway, but don't be surpised if there's a problem.\n"
361 "(Filename is %s)\n",themename,valbuf);
362 }
363 snprintf(loadfilebuf, sizeof(loadfilebuf),"%s/%s",DATAPREFIX,valbuf);
364 loadsounds(themename,loadfilebuf,NULL);
365 }
366 else if (!strcmp(optbuf,"soundcrash"))
367 {
368 if (strcasecmp( ".wav", valbuf+(strlen(valbuf)-strlen(".wav")) ))
369 {
370 fprintf(stderr,"Warning: Crash sound file in theme %s does not end with '.wav'.\n"
371 "We'll try to load it anyway, but don't be surpised if there's a problem.\n"
372 "(Filename is %s)\n",themename,valbuf);
373 }
374 snprintf(loadfilebuf, 256,"%s/%s",DATAPREFIX,valbuf);
375 loadsounds(themename,NULL,loadfilebuf);
376 }
377 }
378
379 }
380 fclose(themefile);
381 }
382
383
384 if (foundcolor.background == 0)
385 { rc--; fprintf(stderr,"Warning: Background not correctly defined in theme %s. Using default.\n",themename); }
386 if (foundcolor.normaltext == 0)
387 { rc--; fprintf(stderr,"Warning: NormalText not correctly defined in theme %s. Using default.\n",themename); }
388 if (foundcolor.boardfillminr == 0)
389 { rc--; fprintf(stderr,"Warning: BoardFillMin not correctly defined in theme %s. Using default.\n",themename); }
390 if (foundcolor.boardfillmaxr == 0)
391 { rc--; fprintf(stderr,"Warning: BoardFillMax not correctly defined in theme %s. Using default.\n",themename); }
392 if (foundcolor.gridline == 0)
393 { rc--; fprintf(stderr,"Warning: Gridline not correctly defined in theme %s. Using default.\n",themename); }
394 if (foundcolor.gridhighlight == 0)
395 { rc--; fprintf(stderr,"Warning: GridHighlight not correctly defined in theme %s. Using default.\n",themename); }
396 if (foundcolor.line1 == 0)
397 { rc--; fprintf(stderr,"Warning: Line1 not correctly defined in theme %s. Using default.\n",themename); }
398 if (foundcolor.line2 == 0)
399 { rc--; fprintf(stderr,"Warning: Line2 not correctly defined in theme %s. Using default.\n",themename); }
400 if (foundcolor.menuhighlight == 0)
401 { rc--; fprintf(stderr,"Warning: MenuHighlight not correctly defined in theme %s. Using default.\n",themename); }
402 if (foundcolor.gameovertext == 0)
403 { rc--; fprintf(stderr,"Warning: GameoverText not correctly defined in theme %s. Using default.\n",themename); }
404 if (foundcolor.scorescrolltext == 0)
405 { rc--; fprintf(stderr,"Warning: ScorescrollText not correctly defined in theme %s. Using default.\n",themename); }
406 if (foundcolor.bonusscrolltext == 0)
407 { rc--; fprintf(stderr,"Warning: BonusscrollText not correctly defined in theme %s. Using default.\n",themename); }
408 if (foundcolor.textentrybox == 0)
409 { rc--; fprintf(stderr,"Warning: TextentryBox not correctly defined in theme %s. Using default.\n",themename); }
410 if (foundcolor.textentrytext == 0)
411 { rc--; fprintf(stderr,"Warning: TextentryText not correctly defined in theme %s. Using default.\n",themename); }
412 if (foundcolor.copyrighttext == 0)
413 { rc--; fprintf(stderr,"Warning: CopyrightText not correctly defined in theme %s. Using default.\n",themename); }
414
415 if (foundcolor.spritetransparent == 0)
416 {
417 rc--;
418 fprintf(stderr,"Warning: SpriteTransparent not correctly defined in theme %s.\n",themename);
419 color.spritetransparent=SDL_MapRGB(screen->format,255, 0, 0);
420 }
421
422
423 if (color.boardfillmaxr<color.boardfillminr)
424 {
425 color.boardfillmaxr=color.boardfillminr;
426 fprintf(stderr,"Warning: max red value less than min value in theme %s\n",themename);
427 }
428 if (color.boardfillmaxg<color.boardfillming)
429 {
430 color.boardfillmaxg=color.boardfillming;
431 fprintf(stderr,"Warning: max green value less than min value in theme %s\n",themename);
432 }
433 if (color.boardfillmaxb<color.boardfillminb)
434 {
435 color.boardfillmaxb=color.boardfillminb;
436 fprintf(stderr,"Warning: max blue value less than min value in theme %s\n",themename);
437 }
438
439
440 if (spriteimage==NULL)
441 {
442 rc--;
443 fprintf(stderr,"Warning: SpriteBitmap not correctly defined in theme %s. Using default.\n",themename);
444 fprintf(stderr," Also using default SpriteTransparent.\n");
445 color.spritetransparent=SDL_MapRGB(screen->format,255, 0, 0);
446 spriteimage=loadsprite(themename,DATAPREFIX "/" PENGUINBMPFILE);
447 if (spriteimage==NULL)
448 { // uh oh -- no sprite at all. fix -- do something?
449 fprintf(stderr,"Error: couldn't load any sprite at all!!!\n");
450 rc=-255;
451 }
452 }
453
454 if (spritemirrorimage==NULL)
455 {
456 // we don't warn about this -- we just use the
457 // main sprite image and go on silently
458 spritemirrorimage=spriteimage;
459 }
460
461 return rc;
462 }
463
getthemenumber(char ** themenamelist,int numthemes,char * themename)464 int getthemenumber(char** themenamelist,int numthemes,char* themename)
465 {
466 int i;
467 for (i=0;i<numthemes;i++)
468 {
469 if (!strcmp(themenamelist[i],themename))
470 return i;
471 }
472 return -1;
473 }
474
setrandomtheme()475 int setrandomtheme()
476 {
477 char themename[MAXTHEMENAMELENGTH];
478 char** themelist;
479 int themecount;
480
481 themecount=getthemenames(&themelist);
482 if (getthemenumber(themelist,themecount,"random")!=-1)
483 {
484 fprintf(stderr,"Hey! You can't have a theme named random! Please remove the random.ibt\n"
485 "file from your themes directory.\n");
486 strcpy(themename,"linux");
487 }
488 else
489 {
490 snprintf(themename,sizeof(themename),"%s",themelist[random() %themecount]);
491 }
492 freethemenames(&themelist,themecount);
493 return settheme(themename);
494 }
495
setdefaultcolors()496 void setdefaultcolors()
497 {
498 color.background = SDL_MapRGB(screen->format, 0, 64,128);
499 color.normaltext = SDL_MapRGB(screen->format,255,255,255);
500 color.gridline = SDL_MapRGB(screen->format,192,192,192);
501 color.gridhighlight = SDL_MapRGB(screen->format,192,192,192);
502 color.line1 = SDL_MapRGB(screen->format, 0, 0, 0);
503 color.line2 = SDL_MapRGB(screen->format,192, 0, 64);
504 color.menuhighlight = SDL_MapRGB(screen->format,240,240,240);
505 color.gameovertext = SDL_MapRGB(screen->format,192, 0, 64);
506 color.scorescrolltext = SDL_MapRGB(screen->format, 0, 0, 0);
507 color.bonusscrolltext = SDL_MapRGB(screen->format,192, 0, 64);
508 color.textentrybox = SDL_MapRGB(screen->format, 0, 0, 0);
509 color.textentrytext = SDL_MapRGB(screen->format,255,255,255);
510 color.copyrighttext = SDL_MapRGB(screen->format,192,192,192);
511
512 color.boardfillminr = 224;
513 color.boardfillming = 224;
514 color.boardfillminb = 224;
515 color.boardfillmaxr = 255;
516 color.boardfillmaxg = 255;
517 color.boardfillmaxb = 255;
518 }
519
loadsprite(char * themename,char * imagefile)520 SDL_Surface* loadsprite(char* themename, char* imagefile)
521 {
522 SDL_Surface* imageloadtemp1;
523 SDL_Surface* imageloadtemp2;
524
525 imageloadtemp1 = SDL_LoadBMP(imagefile);
526 if (imageloadtemp1==NULL)
527 {
528 fprintf(stderr, "Couldn't load image %s.\n"
529 "SDL error: "
530 "%s\n\n", imagefile, SDL_GetError());
531 return NULL;
532 }
533
534 if (imageloadtemp1->w > BLOCKWIDTH || imageloadtemp1->h > BLOCKHEIGHT)
535 {
536 fprintf(stderr, "Error: Image file %s too large!\n", imagefile);
537 return NULL;
538 }
539 if (imageloadtemp1->w < BLOCKWIDTH-2 || imageloadtemp1->h < BLOCKHEIGHT-2)
540 {
541 fprintf(stderr, "Error: Image file %s too small!\n", imagefile);
542 return NULL;
543 }
544
545 imageloadtemp2 = SDL_DisplayFormat(imageloadtemp1);
546 if (imageloadtemp2==NULL)
547 {
548 fprintf(stderr, "Warning: couldn't convert %s to screen format.\n"
549 "Perhaps we ran out of memory? We'll live, but there will be a performance hit.\n",
550 imagefile);
551 imageloadtemp2 = imageloadtemp1;
552 }
553 else
554 {
555 SDL_FreeSurface(imageloadtemp1);
556 }
557
558 if (SDL_SetColorKey(imageloadtemp2, SDL_SRCCOLORKEY, color.spritetransparent))
559 {
560 if (themename!=NULL)
561 {
562 fprintf(stderr, "Warning: couldn't set colorkey for %s.\n"
563 "This is probably a problem in the '%s' theme.\n",
564 imagefile,themename);
565 return NULL;
566 }
567 else
568 {
569 fprintf(stderr, "Warning: couldn't set colorkey for %s.\n"
570 "Since that's the default image, this probably means there's a serious problem.\n",
571 imagefile);
572 return NULL;
573 }
574 }
575
576 return imageloadtemp2;
577 }
578
alphasortstringarray(const void * a,const void * b)579 static int alphasortstringarray(const void *a, const void *b)
580 {
581 return strcoll ( *(const char **)a, *(const char **)b);
582 }
583