2 Copyright (C) 2005-2007 Tom Beaumont
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.
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.
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
24 static void HackKeyPress(int key
, int mod
)
26 int k
= keyState
[key
];
27 StateMakerBase::current
->KeyPressed(key
, mod
);
34 Menu() : renderBG(true), under(activeMenu
), time(0) { activeMenu
= this; }
37 if(this!=deadMenu
) FATAL("this!=deadMenu");
43 if (!activeMenu
) return;
45 activeMenu
= activeMenu
->under
;
50 virtual bool KeyPressed(int key
, int /*mod*/)
52 if (key
=='w' || key
==SDLK_UP
|| key
==SDLK_KP8
|| key
=='q' || key
=='e' || key
==SDLK_KP7
|| key
==SDLK_KP9
)
54 else if (key
=='s' || key
==SDLK_DOWN
|| key
==SDLK_KP2
|| key
=='a' || key
=='d' || key
==SDLK_KP1
|| key
==SDLK_KP3
)
56 else if (key
==' ' || key
==SDLK_RETURN
)
61 else if (key
==SDLK_ESCAPE
|| key
==SDLK_BACKSPACE
|| key
==SDLK_KP_PERIOD
|| key
==SDLK_DELETE
)
67 virtual void Mouse(int /*x*/, int /*y*/, int /*dx*/, int /*dy*/, int buttons_pressed
, int /*buttons_released*/, int /*buttons*/)
69 if (buttons_pressed
==4 || buttons_pressed
==2)
73 virtual void Move(int /*dir*/) {}
74 virtual void Select() {}
75 virtual void Cancel() {}
77 virtual void Update(double timedelta
) {time
+=timedelta
;}
78 virtual void Render() = 0;
84 const char * hint
[] = {
87 "Basic controls:|Move around with the keys Q,W,E,A,S,D or the numeric keypad. Alternatively, you can use the mouse and click on the tile you'd like to move to. Use 'U', backspace or the right mouse button to undo mistakes. The 'Esc' key (or middle mouse button) brings up a menu from which you can restart if you get stuck.",
91 "Objective:|Your goal is to break all the green tiles. You mainly do this by jumping on them. They will crack when you land on them, and only disintegrate when you jump off. Try not to trap yourself!",
93 "The coloured walls flatten themselves when there are no matching coloured tiles remaining.",
95 "You can bounce on the purple trampoline tiles to get around. But try not to fall in the water. If you do, remember you can undo with 'U', backspace or the right mouse button!",
97 "A red spinner tile will rotate the pieces around it when you step on it.",
101 "You don't need to destroy blue tiles to complete the level. But they'll turn green when you step off them, and you know what you have to do to green tiles...",
105 "Yellow laser tiles fire when you step on them. Shooting other laser tiles is more destructive.",
107 "Ice is slippery! Please be careful!!",
111 "The dark grey tiles with arrows on are builders. Landing on one creates green tiles in any adjacent empty tile, and turns green tiles into walls.",
115 "You can ride on the pink floating boats to get across water. They'll pop if you try and float off the edge of the screen though, so look where you're going.",
117 "The blue lifts go up or down when you land on them.",
123 "The spiky anti-ice pickups turn icy tiles into blue ones. They get used automatically when you land on ice.",
125 "Collecting the golden jump pickups will allow you to do a big vertical jump. Try it out on different types of tile. Use the space bar or return key to jump. Or click on the tile you're currently on with the mouse.",
130 "Map Screen:|You can choose which level to attempt next from the map screen. Silver levels are ones you've cleared. Black levels are ones you haven't completed yet, but are available to play.",
133 "New feature unlocked!|Each level has an efficiency target for you to try and beat. Every move you make and each non-green tile you destroy counts against you. Why not try replaying some levels and going for gold?",
138 "Thanks for playing this little game. I hope you enjoy it! -- -- All content is Copyright 2005 Tom Beaumont email: tombeaumont@yahoo.com Any constructive criticism gratefully received!",
140 // First help page (31)
141 "Welcome to " GAMENAME
"! This is a puzzle game based on hexagonal tiles. There is no time limit and no real-time elements, so take as long as you like. Use the cursor keys or click on the arrows to scroll through the help pages. More pages will be added as you progress through the game.",
144 struct HintMessage
: public Menu
153 static bool FlagTile(int t
, bool newStuff
=true)
155 if (t
==LIFT_UP
) t
=LIFT_DOWN
;
156 if (newStuff
&& (flags
& (1<<t
))) return false;
157 if (!newStuff
&& !(flags
& (1<<t
))) return false;
158 if (t
>31) return false;
159 if (!hint
[t
]) return false;
162 new HintMessage(hint
[t
]);
166 HintMessage(const char * m
) { Init(m
); }
168 void Init(const char * m
)
172 memset(title
, 0, sizeof(title
));
173 char * x
= strstr(m
, "|");
177 strcpy(title
, "Info:");
181 strncpy(title
, m
, x
-m
);
186 while ((s
=strstr(s
, " ")))
190 virtual void Render()
192 int y
= SCREEN_H
/4 + int(SCREEN_H
*MAX(1-time
*5, 0)*3/4);
194 y
= SCREEN_H
/4 + int(SCREEN_H
*(-time
*5)*3/4);
198 if (!state
&& time
>0.2)
199 Print(SCREEN_W
*3/4, SCREEN_H
-FONT_SPACING
, "Press any key");
202 void Render(int x
, int y
)
204 SDL_Rect r2
= {x
+TILE_W1
, y
, SCREEN_W
-TILE_W1
*2, numLines
*FONT_SPACING
+FONT_SPACING
};
205 SDL_Rect r
= {r2
.x
-2, r2
.y
-2-FONT_SPACING
, r2
.w
+4, r2
.h
+4+FONT_SPACING
};
206 SDL_FillRect(screen
, &r
, SDL_MapRGB(screen
->format
, 60,90,90));
207 SDL_FillRect(screen
, &r2
, SDL_MapRGB(screen
->format
, 20,50,50));
208 Print(r
.x
+FONT_SPACING
/4, y
-FONT_SPACING
, title
);
209 PrintC(true, x
+SCREEN_W
/2, y
+FONT_SPACING
/2, msg
);
212 virtual void Mouse(int /*x*/, int /*y*/, int /*dx*/, int /*dy*/, int buttons_pressed
, int /*buttons_released*/, int /*buttons*/)
214 if (buttons_pressed
&& state
==0 && time
>0.2)
218 bool KeyPressed(int /*key*/, int /*mod*/)
220 if (state
==0 && time
>0.2)
225 virtual void Update(double timedelta
)
227 Menu::Update(timedelta
);
228 if(state
&& time
> 0.2)
233 int HintMessage::flags
= 1<<31 | 1<<30;
235 struct HintReview
: public HintMessage
241 HintReview() : HintMessage(hint
[31]), page(31), page_dir(0), page_display(0)
244 for (int i
=0; i
<32; i
++)
249 void Cancel() { Pop(); }
250 void Select() { Pop(); }
253 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
255 if (buttons_pressed
==1)
257 if (y
< SCREEN_H
/4-FONT_SPACING
+2)
259 else if (y
> SCREEN_H
/4+FONT_SPACING
*numLines
+FONT_SPACING
)
265 Menu::Mouse(x
,y
,dx
,dy
,buttons_pressed
, buttons_released
, buttons
);
268 bool KeyPressed(int key
, int mod
)
272 else if (key
==SDLK_RIGHT
)
275 return Menu::KeyPressed(key
, mod
);
279 virtual void Render()
281 const double SPD
= 10;
284 sprintf (title
, "Help (Page --)", page_display
+1, page_count
);
286 sprintf (title
, "Help (Page %d/%d)", page_display
+1, page_count
);
291 y
= SCREEN_H
/4+int(MAX(0, time
*SPD
)*-page_dir
*SCREEN_H
);
293 y
= SCREEN_H
/4+int(MAX(0, 1-time
*SPD
)*page_dir
*SCREEN_H
);
297 PrintC(false, SCREEN_W
/2, y
-FONT_SPACING
*2, "^");
298 PrintC(false, SCREEN_W
/2, y
+FONT_SPACING
*(numLines
+1)+FONT_SPACING
/2-2, "_");
301 HintMessage::Render(0,y
);
303 if (time
> 1.0/SPD
&& page_dir
&& state
==0)
306 page
= (page
+page_dir
) & 31;
308 if (hint
[page
]) break;
310 } while (hint
[page
]==0 || !(flags
&(1<<page
)));
313 page_display
= (page_display
+ page_count
+ page_dir
) % page_count
;
318 if (time
>1.0/SPD
&& state
==1)
319 state
=0, page_dir
= 0;
321 virtual void Update(double timedelta
)
323 Menu::Update(timedelta
);
335 #define MAX_GAMESLOT 4
338 OPT_GAMESLOT_LAST
= OPT_GAMESLOT_0
+ MAX_GAMESLOT
- 1,
342 OPT_GOTO_MAP_CONTINUE
,
348 OPT_QUIT_MENU_CONFIRM
,
358 char optionSlotName
[MAX_GAMESLOT
][40] = { {0} };
359 char currentSlot
[80] = "";
361 char* GetSlotName(int i
, char * t
)
363 sprintf(t
, "save%d.dat", i
+1);
367 char * optionString
[] = {
384 "Yes, really delete it!",
388 "View Credits Sequence", "View Credits Sequence",
392 struct OptMenu
: public Menu
401 OptMenu(const char * t
) : select(0), title(t
)
410 r
.x
=(SCREEN_W
-r
.w
)/2;
415 const int SPACE
= int(FONT_SPACING
* 1.5);
417 r2
.h
= SPACE
*num_opt
+ FONT_SPACING
/2;
418 r
.h
= r2
.h
+ (FONT_SPACING
+2*2);
419 r
.y
-= FONT_SPACING
+2;
424 void RenderOption(int o
, const char * s
)
426 int y
= r2
.y
+ FONT_SPACING
/2 + int(FONT_SPACING
* 1.5) * o
;
429 int x
= r
.x
+ font
[' '].w
;
430 int x1
= x
+ (font
[' '].w
+ font
['>'].w
+ FONT_X_SPACING
*2) / 2;
433 //x += int( sin(time*9)*2.5 );
434 //y += int( sin(time*9 + 1.5)*1.5 );
435 Print(x
, y
, "> %s", s
);
439 Print(x1
, y
, "%s", s
);
447 //x += int( sin(time*9)*2.5 );
448 //y += int( sin(time*9 + 1.5)*1.5 );
449 PrintC(false, x
, y
, "> %s <", s
);
453 PrintC(false, x
, y
, "%s", s
);
461 if (select
<0) select
= num_opt
-1;
462 if (select
>=num_opt
) select
= 0;
464 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
468 if (x
<r2
.x
|| y
<r2
.y
|| x
>r2
.x
+r2
.w
|| y
>r2
.y
+r2
.h
)
470 if (buttons_pressed
!=4 && buttons_pressed
!=2)
475 select
= (y
-r2
.y
-FONT_SPACING
/3) / int(FONT_SPACING
*1.5);
476 if (select
<0) select
= 0;
477 if (select
>=num_opt
) select
= num_opt
-1;
480 if (buttons_pressed
==1)
482 Menu::Mouse(x
, y
, dx
, dy
, buttons_pressed
, buttons_released
, buttons
);
494 SDL_FillRect(screen
, &r
, SDL_MapRGB(screen
->format
, 60,90,90));
495 SDL_FillRect(screen
, &r2
, SDL_MapRGB(screen
->format
, 20,50,50));
500 Print(r2
.x
+font
[' '].w
, r
.y
+4, title
);
502 PrintC(false, r2
.x
+r2
.w
/2, r
.y
+4, title
);
506 for (int i
=0; i
<num_opt
; i
++)
507 RenderOption(i
, optionString
[opt
[i
]]);
515 struct WinLoseScreen
: public OptMenu
518 int score
, par
, best_score
;
519 WinLoseScreen(bool _win
, int _score
=0, int _par
=0, int _prev_score
=0) :
520 OptMenu(_win
? _("Level Complete!") : _("Emi can't swim...")),
524 best_score(_prev_score
)
527 opt
[num_opt
++] = OPT_UNDO
;
529 opt
[num_opt
++] = OPT_RESTART
;
530 opt
[num_opt
++] = win
? OPT_GOTO_MAP_CONTINUE
: OPT_GOTO_MAP
;
536 r
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
537 r2
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
544 OptMenu::RenderTitle();
547 r2
.y
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
549 OptMenu::RenderOptions();
552 r2
.y
-= FONT_SPACING
* 3 + FONT_SPACING
/2;
557 int y
= r2
.y
+ FONT_SPACING
/2;
558 if (score
< best_score
&& score
<= par
)
559 PrintC(true, x
, y
, "New Best Score: %d Par Score: %d Par Beaten!", score
, par
);
560 else if (score
< best_score
)
561 PrintC(true, x
, y
, "New Best Score: %d Par Score: %d", score
, par
);
562 else if (par
&& best_score
)
563 PrintC(true, x
, y
, "Score: %d Previous Best: %d Par Score: %d", score
, best_score
, par
);
565 PrintC(true, x
, y
+FONT_SPACING
/2, "Well Done! Level Completed!");
572 HackKeyPress('z', 0);
574 bool KeyPressed(int key
, int mod
)
576 if (key
=='z' || key
=='u' || key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
)
578 if (key
=='r' && (mod
& KMOD_CTRL
))
581 HackKeyPress(key
, mod
);
584 return OptMenu::KeyPressed(key
, mod
);
586 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
588 if (buttons_pressed
==4)
594 OptMenu::Mouse(x
, y
, dx
, dy
, buttons_pressed
, buttons_released
, buttons
);
605 struct OptMenuTitle
: public OptMenu
607 OptMenuTitle(const char * t
) : OptMenu(t
)
615 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
616 // SDL_FillRect(screen, &a, SDL_MapRGB(screen->format, 10,25,25));
619 SDL_BlitSurface(titlePage
, &a
, screen
, &a
);
621 OptMenu::RenderTitle();
622 OptMenu::RenderOptions();
631 int x
= SCREEN_W
- r
.x
- r
.w
;// - FONT_SPACING;
632 int y
= SCREEN_H
- r
.y
- r
.h
+ FONT_SPACING
/4;// - FONT_SPACING;
635 r
.w
+=20; r2
.w
+=20; r
.h
+=20; r2
.h
+=20;
637 r
.h
= r2
.h
= SCREEN_H
;
639 r
.y
= r2
.y
- FONT_SPACING
- 2;
643 const char *ending
[] = {
645 "", "", "", "", "", "",
647 "", "", "*15,4", "", "",
649 "All Levels Cleared!",
651 "", "", "*5,7", "", "",
653 "Not a single green hexagon is left unbroken.",
655 "Truly, you are a master of hexagon hopping!",
657 "", "", "*9,10", "", "",
659 "", "Credits", "", "", "",
660 "<Design & Direction:", ">Tom Beaumont", "", "",
661 "<Programming:", ">Tom Beaumont", "", "",
662 "<Graphics:", ">Tom Beaumont", "", "",
663 "<Thanks to:", ">Kris Beaumont", "", "",
664 // "", "<Some useless facts...", "",
665 "<Tools and libraries used:", "", ">Photoshop LE", ">Inno Setup", ">Wings 3D", ">MSVC", ">SDL", "",
666 "<Fonts used:", "", ">Copperplate gothic bold", ">Verdana", "",
668 "", "", "*12,14", "", "",
670 "Thanks for playing!"
673 const char *ending2
[] = {
674 " Absolutely Amazing! ",
677 "", "", "*15,4", "", "",
679 "All Levels Mastered!!",
681 "", "", "*5,7", "", "",
683 "You crushed every last green hexagon with",
684 "breathtaking efficiency!",
686 "You truly are a grand master of hexagon hopping!",
689 const int endingLen
= sizeof(ending
)/sizeof(ending
[0]);
690 const int endingLen2
= sizeof(ending2
)/sizeof(ending2
[0]);
691 const int scrollMax
= SCREEN_H
+ (endingLen
+1) * FONT_SPACING
;
693 struct Ending
: public Menu
696 double x
,y
,xs
,ys
,xa
,ya
;
700 void Update(double td
)
702 if (type
==EMPTY
) return;
709 if (type
==TILE_LASER_HEAD
&& time
<0.3)
710 type
=TILE_FIRE_PARTICLE_1
;
711 if (type
==TILE_FIRE_PARTICLE_1
&& time
<0.1)
712 type
=TILE_FIRE_PARTICLE_2
;
714 // if (type==COLLAPSABLE || type==COLLAPSE_DOOR)
715 // for (int i=int((time)*40); i<int((time+td)*40); i++)
716 // new Particle(TILE_GREEN_FRAGMENT_1, x+32-rand()%63, y+20-rand()%40);
718 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT
)
719 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_1
, time
+=rand()%100*0.01;
720 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_1
)
721 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_2
, time
+=rand()%100*0.01;
722 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_2
)
729 for (int i
=0; i
<40; i
++)
730 new Particle(TILE_LASER_HEAD
, x
, y
);
731 for (int i
=0; i
<40; i
++)
732 new Particle(TILE_GREEN_FRAGMENT
+ rand() % 3, x
+32-rand()%63, y
+20-rand()%40);
734 if (type
==COLLAPSE_DOOR
)
745 if (type
==EMPTY
) return;
747 if (type
<0.05 && type
<15)
748 RenderTile(false, tileSolid
[type
] ? TILE_WHITE_WALL
: TILE_WHITE_TILE
, int(x
)+scrollX
, int(y
)+scrollY
);
750 RenderTile(false, type
, int(x
)+scrollX
, int(y
)+scrollY
);
753 Particle() : type(EMPTY
) {}
754 Particle(int t
, int _x
) : x(_x
), type(t
)
761 //x=rand() % SCREEN_W;
762 //y=rand() % SCREEN_H;
767 Particle(int t
, double _x
, double _y
) : type(t
)
771 double r
= (rand() % 2000) * PI
/ 1000;
772 double d
= rand() % 50 + 250;
776 time
= 1 + (rand() & 255) /255.0;
777 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
779 xa
=-xs
/time
; ya
=-ys
/time
;
780 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
781 ya
+= 500, ya
/=2, xa
/=2, xs
/=2, ys
/=2;
783 ~Particle() { type
= EMPTY
; }
784 void* operator new(size_t sz
);
792 static Ending
* ending
;
794 Ending(bool _goodEnd
) : goodEnding(_goodEnd
)
796 memset(p
, 0, sizeof(p
));
805 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
806 SDL_FillRect(screen
, &a
, SDL_MapRGB(screen
->format
, 10,25,25));
808 for (unsigned int i
=0; i
<sizeof(p
)/sizeof(p
[0]); i
++)
813 int xr
= SCREEN_W
*4/5;
814 int y
= SCREEN_H
- int(scroll
);
815 for (int i
=0; i
<endingLen
; i
++)
817 if (y
>-FONT_SPACING
*2 && y
<SCREEN_H
+FONT_SPACING
)
819 const char * xx
= (i
<endingLen2
&& goodEnding
) ? ending2
[i
] : ::ending
[i
];
821 Print(xl
, y
+FONT_SPACING
, xx
+1);
826 RenderTile(false, atoi(xx
+1), (xl
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
827 RenderTile(false, atoi(strchr(xx
, ',')+1), (xr
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
830 PrintC(false, x
, y
, xx
);
834 if (scroll
> scrollMax
+ FONT_SPACING
*10)
835 PrintC(true, x
, SCREEN_H
/2-FONT_SPACING
/2, "The End");
840 bool KeyPressed(int key
, int mod
)
842 if (key
=='r' && (mod
& KMOD_CTRL
))
845 memset(p
, 0, sizeof(p
));
848 return Menu::KeyPressed(key
, mod
);
852 void Update(double td
)
859 if (keyState
[SDLK_LSHIFT
])
861 if (keyState
[SDLK_0
])
862 t
= MAX(-td
*5, -time
);
866 // if (scroll > scrollMax)
867 // scroll = fmod(scroll, scrollMax);
868 // scroll = 0, time = 0;
870 if (old
>4 && time
> 4)
872 if (scroll
< scrollMax
+ FONT_SPACING
*17)
874 for (int i
=int( old
/2.5); i
<int(time
/2.5); i
++)
876 int xs
= (rand()%SCREEN_W
* 6 + 1) / 8;
877 for (int j
=rand()%3+1; j
; j
--)
878 new Particle(rand()&1 ? COLLAPSABLE
: COLLAPSE_DOOR
, xs
+j
*64);
881 if (scroll
> scrollMax
+ FONT_SPACING
*27)
888 Ending
* Ending::ending
= 0;
889 void* Ending::Particle::operator new(size_t /*sz*/)
891 static int start
= 0;
892 const int max
= sizeof(ending
->p
)/sizeof(ending
->p
[0]);
893 for (int i
=0; i
<max
; i
++)
896 if (start
==max
) start
=0;
897 if (ending
->p
[start
].type
==EMPTY
)
898 return &ending
->p
[start
];
900 return &ending
->p
[rand() % max
];
903 struct TitleMenu
: public OptMenuTitle
905 TitleMenu() : OptMenuTitle("")
911 for (int i
=0; i
<MAX_GAMESLOT
; i
++)
915 FILE* f
= file_open(tmp
, "rb");
918 p
.LoadSave(f
, false);
921 if (p
.general
.completionPercentage
==100 && p
.general
.masteredPercentage
==100)
922 sprintf(optionSlotName
[i
], _("Continue game %d (All Clear!)"), i
+1);
923 else if (p
.general
.completionPercentage
==100)
924 sprintf(optionSlotName
[i
], "Continue game %d (%d%% + %d%%)", i
+1, p
.general
.completionPercentage
, p
.general
.masteredPercentage
);
926 sprintf(optionSlotName
[i
], "Continue game %d (%d%% complete)", i
+1, p
.general
.completionPercentage
);
928 opt
[num_opt
++] = OPT_GAMESLOT_0
+ i
;
932 // sprintf(optionSlotName[i], "Start new game (slot %d)", i+1);
933 // opt[num_opt++] = OPT_GAMESLOT_0 + i;
941 if (num_opt
< MAX_GAMESLOT
)
942 opt
[num_opt
++] = OPT_GAMESLOT_NEW
;
944 opt
[num_opt
++] = OPT_OPTIONS
;
946 opt
[num_opt
++] = OPT_END
;
947 opt
[num_opt
++] = OPT_END2
;
949 opt
[num_opt
++] = OPT_QUIT
;
954 r2
.y
-=FONT_SPACING
*2;
957 r
.y
+=FONT_SPACING
+FONT_SPACING
/2, r2
.y
+=FONT_SPACING
+FONT_SPACING
/2;
960 bool KeyPressed(int key
, int mod
);
963 struct QuitConfirmMenu
: public OptMenuTitle
965 QuitConfirmMenu() : OptMenuTitle("Quit: Are you sure?")
967 opt
[num_opt
++] = OPT_QUIT_CONFIRM
;
968 opt
[select
=num_opt
++] = OPT_QUIT_CANCEL
;
971 r
.y
+= FONT_SPACING
*1;
972 r2
.y
+= FONT_SPACING
*2;
977 struct DeleteConfirmMenu
: public OptMenuTitle
981 DeleteConfirmMenu(int _num
) : OptMenuTitle(&tmp
[0]), num(_num
)
985 sprintf(tmp
, "Really delete game %d?", num
+1);
986 opt
[num_opt
++] = OPT_DELETE_CONFIRM
;
987 opt
[select
=num_opt
++] = OPT_DELETE_CANCEL
;
990 r
.y
+= FONT_SPACING
*1;
991 r2
.y
+= FONT_SPACING
*2;
995 if (select
<0 || select
>=num_opt
)
997 if (opt
[select
] == OPT_DELETE_CONFIRM
)
999 GetSlotName(num
, tmp
);
1008 bool TitleMenu::KeyPressed(int key
, int mod
)
1010 if (key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
|| key
==SDLK_F2
)
1012 if (select
<0 || select
>=num_opt
|| opt
[select
]<OPT_GAMESLOT_0
|| opt
[select
]>OPT_GAMESLOT_LAST
)
1014 int i
= opt
[select
] - OPT_GAMESLOT_0
;
1016 new DeleteConfirmMenu(i
);
1020 return OptMenu::KeyPressed(key
, mod
);
1023 struct PauseMenu
: public OptMenu
1025 PauseMenu(bool isMap
, bool allowGotoMap
, int allowEnd
, int allowEnd2
) : OptMenu("Paused")
1027 opt
[num_opt
++] = OPT_RESUME
;
1029 opt
[num_opt
++] = OPT_RESTART
;
1030 opt
[num_opt
++] = OPT_OPTIONS
;
1031 opt
[num_opt
++] = OPT_HELP
;
1032 if (allowEnd
|| allowEnd2
)
1033 opt
[num_opt
++] = allowEnd2
? OPT_END2
: OPT_END
;
1034 opt
[num_opt
++] = (isMap
|| !allowGotoMap
) ? OPT_QUIT_MENU_CONFIRM
: OPT_GOTO_MAP
;
1037 virtual bool KeyPressed(int key
, int mod
)
1039 if (key
=='p' || key
==SDLK_PAUSE
)
1044 return Menu::KeyPressed(key
, mod
);
1049 struct OptionMenu
: public OptMenuTitle
1052 OptionMenu(bool _title
) : OptMenuTitle("Options"), title(_title
)
1054 opt
[num_opt
++] = OPT_FULLSCREEN
;
1056 opt
[num_opt
++] = OPT_BACK
;
1060 OptMenuTitle::Init(), renderBG
=false;
1061 r
.y
+= FONT_SPACING
;
1062 r2
.y
+= FONT_SPACING
*2;
1065 OptMenu::Init(), renderBG
=true;
1070 OptMenuTitle::Render();
1076 void RenderFade(double time
, int dir
, int seed
);
1078 struct Fader
: public Menu
1083 Fader(int _dir
, int _result
, double _speed
=1) : dir(_dir
), speed(_speed
), result(_result
)
1085 renderBG
= under
? under
->renderBG
: true;
1092 RenderFade(time
, dir
, (long)this);
1094 void Update(double timedelta
)
1096 Menu::Update(timedelta
* speed
);
1102 else if (time
>= 0.5)
1112 Pop(); // Remove old menu
1113 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
| KMOD_SHIFT
); // Reload map combination!
1117 Pop(); // Remove old menu
1118 new Fader(1, 0, speed
);
1120 if (result
==-5 || result
==-7)
1122 new Ending(result
==-7);
1123 new Fader(1, 0, speed
);
1129 void Ending::Cancel()
1131 new Fader(-1, -6, 0.3);
1135 void ToggleFullscreen();
1137 void OptMenu::Select()
1139 if (select
<0 || select
>=num_opt
)
1149 HackKeyPress('r', KMOD_CTRL
);
1153 case OPT_GOTO_MAP_CONTINUE
:
1155 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
);
1159 new QuitConfirmMenu();
1162 case OPT_FULLSCREEN
:
1166 case OPT_QUIT_CONFIRM
:
1170 case OPT_QUIT_MENU_CONFIRM
:
1176 new OptionMenu(!activeMenu
->renderBG
);
1183 case OPT_QUIT_CANCEL
:
1189 new Fader(-1, -5, 0.3);
1193 new Fader(-1, -7, 0.3);
1198 HackKeyPress('z', 0);
1202 if (opt
[select
]>=OPT_GAMESLOT_0
&& opt
[select
]<=OPT_GAMESLOT_LAST
1203 || opt
[select
]==OPT_GAMESLOT_NEW
&& freeSlot
>=0)
1205 if (opt
[select
]==OPT_GAMESLOT_NEW
)
1206 GetSlotName(freeSlot
, currentSlot
);
1208 GetSlotName(opt
[select
]-OPT_GAMESLOT_0
, currentSlot
);