1 /*  Penguin Command: a clone of the famous Missile Command game
2     Copyright (C) 2000 Karl Bartel
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 
18     Karl Bartel
19     Cecilienstr. 14
20     12307 Berlin
21     GERMANY
22     karlb@gmx.net
23 */
24 #include <main.h>
25 #include <time.h> /* For seeding rand() */
26 #include <string.h>
27 #ifdef JOYSTICK
28 #include "joystick.h"
29 #endif
30 #ifndef VERSION
31 #define VERSION "1.6.?"
32 #endif
33 
34 
35     int fullscreen=1, CityDestroyed[6]={0,0,0,0,0,0},
36 	CannonDestroyed[3]={0,0,0}, Score=0, HWCursor=0, NoAlpha=0, ArcadeMode=0, MusicVol=10, SoundVol=10;
37 //images
38     SDL_Surface *ShotPic,*CityPic,*BackPic,*CityHitPic,*Cannon[21],*Font,
39 		*BombPic[10],*CannonHitPic,*TitlePic,*ExplosionPic[21],
40 		*CursorPic[10],*FlyerPic[16];
41 //event handling
42     SDL_Event event;
43 //other
44     int Quit=0, Loaded=0, StartLevel=0;
45     Uint32 WaitStart=0;
46     int LowDetail=0, MediumDetail=0, HighDetail=1;
47 
Wait(int time_in_ms)48 int Wait( int time_in_ms )
49 {
50     if (WaitStart==0)
51 	WaitStart=SDL_GetTicks();
52     if (WaitStart+time_in_ms <= SDL_GetTicks()) {
53 	WaitStart=0;
54 	return 0;
55     }
56     return 1;
57 }
58 
LoadImages()59 void LoadImages()
60 {
61     int i;
62     char text[200];
63 
64     BackPic = LoadImage("back.jpg",0);
65     SDL_FreeSurface(ShotPic);
66     ShotPic = LoadImage("shot.png",3);
67     CityPic = LoadImage("city.png",4);
68     CityHitPic = LoadImage("cityhit.png",4);
69     CannonHitPic = LoadImage("cannonhit.png",4);
70     for (i=0;i<21;i++) {
71 	sprintf(text,"cannon%d.png",i+1);
72 	SDL_FreeSurface(Cannon[i]);
73 	Cannon[i] = LoadImage(text,3);
74     }
75     for (i=0;i<10;i++) {
76 	sprintf(text,"bomb%d.png",i+1);
77 	SDL_FreeSurface(BombPic[i]);
78 	BombPic[i] = LoadImage(text,3);
79     }
80     for (i=0;i<20;i++) {
81 	sprintf(text,"%dexplo.png",i+1);
82 	SDL_FreeSurface(ExplosionPic[i]);
83 	ExplosionPic[i] = LoadImage(text,3);
84     }
85     for (i=0;i<9;i++) {
86 	sprintf(text,"%dcursor.png",i+1);
87 	SDL_FreeSurface(CursorPic[i]);
88 	CursorPic[i] = LoadImage(text,3);
89     }
90     CursorPic[9] = CursorPic[0];
91     for (i=0;i<16;i++) {
92 	sprintf(text,"%dflyer.png",i+1);
93 	SDL_FreeSurface(FlyerPic[i]);
94 	FlyerPic[i] = LoadImage(text,3);
95     }
96 }
97 
Button(int x,int y,char * String,int prev,SDL_Surface * Background)98 int Button(int x, int y, char *String, int prev, SDL_Surface *Background)
99 {
100     SDL_Rect rect;
101     int MouseX,MouseY;
102 
103     rect.x=x;
104     rect.y=y;
105     rect.w=SFont_TextWidth(String);
106     rect.h=Font->h;
107 
108     SDL_GetMouseState(&MouseX, &MouseY);
109     if ((MouseX>x)&&(MouseY>y)
110 	&&(MouseX<x+SFont_TextWidth(String))
111 	&&(MouseY<y+Font->h))
112     {
113 	if (prev!=1) {
114 	    // clear
115 	    SDL_SetAlpha(Background,0,0);
116 	    SDL_BlitSurface(Background, &rect, Screen, &rect);
117 	    // draw
118 	    PutString(Screen, x, y, String);
119 	    AddThisRect(rect);
120 	    SDL_BlitSurface(Screen, &rect, BackBuffer, &rect);
121 	    PlaySound(ClickSound);
122 	}
123 	return 1;
124     } else if (prev!=0) {
125 	// clear
126 	SDL_SetAlpha(Background,0,0);
127 	SDL_BlitSurface(Background, &rect, Screen, &rect);
128 	// draw
129 	PutString(Screen, x, y, String);
130 	AddThisRect(rect);
131 	// darken
132 	SDL_SetAlpha(Background,SDL_SRCALPHA,100);
133 	SDL_BlitSurface(Background, &rect, Screen, &rect);
134         SDL_SetAlpha(Background,0,0);
135 	SDL_BlitSurface(Screen, &rect, BackBuffer, &rect);
136     }
137 
138     return 0;
139 }
140 
SetDetail()141 void SetDetail()
142 {
143     if (LowDetail) {
144 	HWCursor=1;
145 	NoAlpha=1;
146     }
147     if (MediumDetail) {
148 	HWCursor=0;
149 	NoAlpha=1;
150     }
151     if (HighDetail) {
152 	HWCursor=0;
153 	NoAlpha=0;
154     }
155 }
156 
ShowHelp()157 void ShowHelp()
158 {
159     float anim=0;
160     SDL_Rect rect;
161     SDL_Event WaitEvent;
162     char DetailString[100],LevelString[100],text[100];
163     int Level=3,SoundV=3,MusicV=3;
164 
165     Blit(0,0,BackPic);
166     ExplosionCount=0;
167     XCenteredString(Screen,10,"< Penguin Command Help & Options >");
168     PutString(Screen,20,60,"Objective: Defend cities!");
169     PutString(Screen,20,100,"Controls: Mouse, or mouse + a,s,d keys");
170     PutString(Screen,20,140,"Score:");
171     PutString(Screen,150,185,"10    Remaining Shot");
172     PutString(Screen,150,220,"20    Destroyed Missile");
173     PutString(Screen,150,255,"30    Destroyed Smartbomb");
174     PutString(Screen,150,290,"80    Remaining City");
175     Blit(80-ShotPic->w/2,200-ShotPic->h/2,ShotPic);
176     Blit(80-CityPic->w/2,310-CityPic->h/2,CityPic);
177     XCenteredString(Screen,380,"< Settings >");
178     SDL_BlitSurface(Screen,NULL,BackBuffer,NULL);
179     SDL_BlitSurface(Screen,NULL,FadeBuffer,NULL);
180     Update();
181     Now=SDL_GetTicks();
182     while (Level || SoundV || MusicV) {
183 		SDL_PollEvent(&WaitEvent);
184 		while (   (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(1))
185 				  ||(SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(2))
186 				  ||(SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(3)) )
187 	    {SDL_PollEvent(&WaitEvent);}
188         while (WaitEvent.type!=SDL_KEYDOWN && WaitEvent.type!=SDL_MOUSEBUTTONDOWN) {
189     	    SDL_PollEvent(&WaitEvent);
190 			UndrawMouse();
191 			// Explosion
192 			UndrawExplosion();
193 			if (ExplosionCount<1) CreateExplosion(80,235);
194 			HandleExplosion(0);
195 			DrawExplosion();
196 			// Bomb
197 			anim+=Speed/100;
198 			if ((int)anim>=10) anim-=10;
199 			rect.x=80-BombPic[0]->w/2; rect.y=270-BombPic[0]->h/2;
200 			rect.w=BombPic[0]->w; rect.h=BombPic[0]->h;
201 			SDL_BlitSurface( BackBuffer, &rect, Screen, &rect);
202 			Blit(rect.x,rect.y,BombPic[(int)anim]);
203 			AddThisRect(blitrect);
204 			// detail button
205 			if (LowDetail) strcpy(DetailString,"Low Detail");
206 			if (MediumDetail) strcpy(DetailString,"Medium Detail");
207 			if (HighDetail) strcpy(DetailString,"High Detail");
208 			//	    Detail=Button(400-SFont_TextWidth(DetailString)/2,430,DetailString,Detail,FadeBuffer);
209 			// level start button
210 			sprintf(LevelString,"Starting at Wave %d", StartLevel+1);
211 			Level=Button(400-SFont_TextWidth(LevelString)/2,430,LevelString,Level,FadeBuffer);
212 			// sound buttons
213 			sprintf(text,"Music Volume: %d", MusicVol);
214 			MusicV=Button(390-SFont_TextWidth(text),490,text,MusicV,FadeBuffer);
215 			sprintf(text,"Sound Volume: %d", SoundVol);
216 			SoundV=Button(410,490,text,SoundV,FadeBuffer);
217 			// display
218 			GetSpeed();
219 			DrawMouse();
220 			Update();
221 		}
222 		if (SoundV) {
223 			if (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(1))
224 				if (SoundVol<15) SoundVol++;
225 			if (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(3))
226 				if (SoundVol>0) SoundVol--;
227 			SoundV=3;
228 			rect.x=400;
229 			rect.y=490;
230 			rect.w=400;
231 			rect.h=Font->h;
232 			AddThisRect(rect);
233             SDL_SetAlpha( FadeBuffer, 0, 0);
234 			SDL_BlitSurface( FadeBuffer, &rect, BackBuffer, &rect);
235 			SDL_BlitSurface( FadeBuffer, &rect, Screen, &rect);
236 			SetVol();
237 		}
238 		if (MusicV) {
239 			if (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(1))
240 				if (MusicVol<15) MusicVol++;
241 			if (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(3))
242 				if (MusicVol>0) MusicVol--;
243 			MusicV=3;
244 			rect.x=0;
245 			rect.y=490;
246 			rect.w=400;
247 			rect.h=Font->h;
248 			AddThisRect(rect);
249             SDL_SetAlpha( FadeBuffer, 0, 0);
250 			SDL_BlitSurface( FadeBuffer, &rect, BackBuffer, &rect);
251 			SDL_BlitSurface( FadeBuffer, &rect, Screen, &rect);
252 #ifdef USE_SOUND
253 			Mix_VolumeMusic(MusicVol*7);
254 #endif
255 		}
256 		if (Level) {
257 			if (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(1))
258 				if (StartLevel<30) StartLevel+=5;
259 			if (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(3))
260 				if (StartLevel>0) StartLevel-=5;
261 			Level=3;
262 			rect.x=100;
263 			rect.y=430;
264 			rect.w=600;
265 			rect.h=Font->h;
266             SDL_SetAlpha( FadeBuffer, 0, 0);
267 			SDL_BlitSurface( FadeBuffer, &rect, BackBuffer, &rect);
268 			SDL_BlitSurface( FadeBuffer, &rect, Screen, &rect);
269 			AddThisRect(rect);
270 		}
271 		SDL_Delay(10);
272 		while (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(1)) {SDL_PollEvent(&WaitEvent);SDL_Delay(10);}
273     }
274 	//    SetDetail();
275 	//    LoadImages();
276 	//    SDL_ShowCursor(HWCursor);
277 }
278 
ShowCredits()279 void ShowCredits()
280 {
281     float MusicDown=110;
282 
283     BlitToBB(0,0,BackPic);
284     XCenteredString(BackBuffer,10,"<Penguin Command Credits>");
285     PutString(BackBuffer,20,60 ,"Code:");
286     PutString(BackBuffer,20,90,"- Karl Bartel <karlb@gmx.net>");
287     PutString(BackBuffer,20,140,"Graphics:");
288     PutString(BackBuffer,20,170,"- Karl Bartel");
289     PutString(BackBuffer,20,200,"- Shane Simmons");
290     PutString(BackBuffer,20,140+MusicDown,"Music:");
291     PutString(BackBuffer,20,170+MusicDown,"- Skaven of the Future Crew");
292     PutString(BackBuffer,100,200+MusicDown,"Data Jack");
293     PutString(BackBuffer,100,230+MusicDown,"Ice Frontier");
294     PutString(BackBuffer,100,260+MusicDown,"Rama Gardens");
295     PutString(BackBuffer,20,310+MusicDown,"- Seth Peelle");
296     PutString(BackBuffer,100,340+MusicDown,"Penguin Night");
297     XCenteredString(BackBuffer,560,"http://www.linux-games.com/");
298     FadeScreen(1);
299     Now=SDL_GetTicks();
300     while (SDL_GetMouseState(NULL,NULL)==SDL_BUTTON(1)) {SDL_PollEvent(&event);SDL_Delay(10);}
301     while ((event.type!=SDL_KEYDOWN)&&(event.type!=SDL_MOUSEBUTTONDOWN)) {
302 	SDL_PollEvent(&event);
303 	UndrawMouse();
304 	DrawMouse();
305         GetSpeed();
306 	Update();
307     }
308 }
309 
ShowTitle()310 void ShowTitle()
311 {
312     int start=3,help=3,hiscore=3,quit=3,delay=0,credits=3,arcade=3;
313     float NewExplosion=0;
314 
315     // show Title
316     printf ("** Blit Background **\n");
317     Blit(0,0,TitlePic);
318     printf ("** Background image drawn **\n");
319     if (!Loaded) {
320 	printf("** Loading Font **\n");
321 	Font = LoadImage("abc.png",4);
322 	printf("** Init Font **\n");
323 	InitFont( Font );
324 	//SDL_EventState(SDL_KEYUP, SDL_IGNORE);
325 	printf("** Loading Images **\n");
326 	// load...
327 	LoadImages();
328 	Loaded=1;
329 	MenuEvents();
330     }
331 	SDL_SetAlpha(Font, SDL_SRCALPHA, 0);
332     ExplosionCount=0;CursorAnim=0;
333     SDL_BlitSurface(TitlePic,NULL,BackBuffer,NULL);
334     // menu
335     while (!Quit) {
336 	if (delay) {
337 	    Blit(0,0,TitlePic);
338 	    SDL_BlitSurface(TitlePic,NULL,BackBuffer,NULL);
339 	    while (event.type==SDL_MOUSEBUTTONDOWN)
340 		SDL_PollEvent(&event);
341 	    Now=SDL_GetTicks();
342 	    start=3;help=3;hiscore=3;quit=3;credits=3;arcade=3;
343 	}
344 	UndrawMouse();
345 	hiscore=Button(50,300,"Hiscores",hiscore,TitlePic);
346 	start=Button(400-SFont_TextWidth("Normal Game")/2,300,"Normal Game",start,TitlePic);
347 	arcade=Button(400-SFont_TextWidth("Arcade Game")/2,340,"Arcade Game",arcade,TitlePic);
348 	help=Button(750-SFont_TextWidth("Help&Conf"),300,"Help&Conf",help,TitlePic);
349 	credits=Button(750-SFont_TextWidth("Credits"),450,"Credits",credits,TitlePic);
350 	quit=Button(50,450,"Quit",quit,TitlePic);
351 	// Fancy explosions
352 	UndrawExplosion();
353 	if ((ExplosionCount<10)&&(NewExplosion<0)) {
354 	    CreateExplosion(abrand(0,799),abrand(0,280));
355 	    NewExplosion+=abrand(0,600)+50;
356 	}
357 	NewExplosion-=Speed;
358 	HandleExplosion(0);
359 	DrawExplosion();
360 	GetSpeed();
361 	// Explosions end
362 	DrawMouse();
363 	Update();
364 	delay=0;
365 	SDL_PollEvent(&event);
366 	if (event.type==SDL_MOUSEBUTTONDOWN) {
367 	    if (hiscore) {
368 		ShowHiscore();
369 		SDL_WaitEvent(&event);
370 	    }
371 	    if (start) {
372 		ArcadeMode=0;
373 		break;
374 	    }
375 	    if (arcade) {
376 		ArcadeMode=1;
377 		break;
378 	    }
379 	    if (help) ShowHelp();
380 	    if (credits) ShowCredits();
381 	    if (quit) Quit=1;
382 	    delay=1;
383 	}
384     }
385     ExplosionCount=0;
386 //    SDL_WaitEvent(&event);
387 }
388 
TextHelp(char * argv[])389 void TextHelp(char *argv[])
390 {
391     printf("\nPenguin Command Version %s\n",VERSION);
392     puts("The newest version can be obtained at http://www.linux-games.com/\n");
393     printf("Usage: %s [options]\n",argv[0]);
394     puts("  [-f, --fullscreen]         start in fullscreen mode (default)");
395     puts("  [-w, --windowed]           start in windowed mode");
396     puts("  [-s, --nosound]            start without sound");
397     puts("  [-l, --lefthandedmouse]    swaps left and right mouse buttons");
398     puts("  [-h, --help]               this text\n");
399 
400     exit(0);
401 }
402 
ReadCommandLine(char * argv[])403 void ReadCommandLine(char *argv[])
404 {
405     int i;
406     for ( i=1;argv[i];i++ ) {
407 	if ((strcmp(argv[i],"--fullscreen")==0)||(strcmp(argv[i],"-f")==0)) fullscreen=1; else
408 	if ((strcmp(argv[i],"--windowed")==0)||(strcmp(argv[i],"-w")==0)) fullscreen=0; else
409 	if ((strcmp(argv[i],"--nosound")==0)||(strcmp(argv[i],"-s")==0)) sound=0; else
410 	if ((strcmp(argv[i],"--lefthandedmouse")==0)||(strcmp(argv[i],"-l")==0)) LeftHandedMouse=1; else
411 	if ((strcmp(argv[i],"--help")==0)||(strcmp(argv[i],"-h")==0)) TextHelp(argv);
412 	else {
413 	    printf("\nUnknown parameter: \"%s\" \n", argv[i]);
414 	    TextHelp(argv);
415 	}
416     }
417 }
418 
main(int argc,char * argv[])419 int main(int argc, char *argv[])
420 {
421 // intialisation
422 //    if ( SDL_Init(SDL_INIT_AUDIO ) < 0 ) ComplainAndExit();
423     ReadCommandLine(argv);
424     printf("** Starting SDL init **\n");
425     init_SDL();
426     SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
427     SDL_WM_SetCaption("Penguin Command","Penguin Command");
428     srand((unsigned)time(NULL));
429 #ifdef JOYSTICK
430 /* joystick */
431     printf("** Finding Joysticks **\n");
432     JoystickInit();
433 #endif
434 // load data
435     printf("** Loading Title Screen **\n");
436     TitlePic = LoadImage("title.jpg",0);
437     InitSound();
438 // set volume
439     ReadOptions();
440 // show title screen
441     printf("** Playing Music **\n");
442     SetVol();
443     SDL_EnableUNICODE(1);
444 //    LoadCursor();
445 //    SetDetail();
446     SDL_ShowCursor(HWCursor);
447     printf("** Ready to enter Menu **\n");
448 // start game
449 	PlayMusic();
450     while (!Quit) {
451 #ifdef USE_SOUND
452 		if (sound) {
453 			printf("** Fade in Music **\n");
454 			//Mix_FadeInMusic(Music[abrand(0,MUSICNUM-1)],0,5000);
455 		}
456 #endif
457 		printf("** Showing Title Screen **\n");
458 		ShowTitle();
459 		if (Quit) break;
460 		StartGame();
461 		FinalScore();
462 		ShowHiscore();
463     }
464 // user wants to quit
465 #ifdef USE_SOUND
466     Mix_FadeOutMusic(1000);
467 #endif
468     {SDL_Rect rect; rect.x=0;rect.y=0;rect.w=800;rect.h=600; SDL_FillRect(BackBuffer,&rect,0);}
469     FadeScreen(0.9);
470     WriteOptions();
471 //    printf("Awaiting SDL_Quit()\n");
472     SDL_Quit();
473 //    printf("SDL_Quit() finished.\n");
474     return 0;
475 }
476