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() : under(activeMenu
), time(0), renderBG(true) { 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 /* TRANSLATORS: pop means vanish and Emy drowns (you loose) */
116 _("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."),
118 _("The blue lifts go up or down when you land on them."),
124 _("The spiky anti-ice pickups turn icy tiles into blue ones. They get used automatically when you land on ice."),
126 /* TRANSLATORS: Normally you jump from one plate to another. The golden jump (a
127 pickup) allows you to jump and land on the *same* plate */
128 _("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."),
133 _("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."),
136 /* TRANSLATORS: Levels are depicted as black balls. Once you passed them, they
137 turn silver. If you reached the par, they turn golden (with a crown), and if
138 you beat the par, they turn their shape/color once more */
139 _("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?"),
144 _("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!"),
146 // First help page (31)
147 /* TRANSLATORS: This string is copied twice into the POT file to workaround a
148 gettext limitation (no macro expansion). The extracted string "Welcome to "
150 _("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."),
153 struct HintMessage
: public Menu
162 static bool FlagTile(int t
, bool newStuff
=true)
164 if (t
==LIFT_UP
) t
=LIFT_DOWN
;
165 if (newStuff
&& (flags
& (1<<t
))) return false;
166 if (!newStuff
&& !(flags
& (1<<t
))) return false;
167 if (t
>31) return false;
168 if (!hint
[t
]) return false;
171 new HintMessage(hint
[t
]);
175 HintMessage(const char * m
) { Init(m
); }
177 void Init(const char * m
)
181 memset(title
, 0, sizeof(title
));
182 char * x
= strstr(m
, "|");
186 strcpy(title
, _("Info:"));
190 strncpy(title
, m
, x
-m
);
195 while ((s
=strstr(s
, " ")))
199 virtual void Render()
201 int y
= SCREEN_H
/4 + int(SCREEN_H
*MAX(1-time
*5, 0)*3/4);
203 y
= SCREEN_H
/4 + int(SCREEN_H
*(-time
*5)*3/4);
207 if (!state
&& time
>0.2)
208 Print(SCREEN_W
*3/4, SCREEN_H
-FONT_SPACING
, _("Press any key"));
211 void Render(int x
, int y
)
213 SDL_Rect r2
= {x
+TILE_W1
, y
, SCREEN_W
-TILE_W1
*2, numLines
*FONT_SPACING
+FONT_SPACING
};
214 SDL_Rect r
= {r2
.x
-2, r2
.y
-2-FONT_SPACING
, r2
.w
+4, r2
.h
+4+FONT_SPACING
};
215 SDL_FillRect(screen
, &r
, SDL_MapRGB(screen
->format
, 60,90,90));
216 SDL_FillRect(screen
, &r2
, SDL_MapRGB(screen
->format
, 20,50,50));
217 Print(r
.x
+FONT_SPACING
/4, y
-FONT_SPACING
, title
);
218 PrintC(true, x
+SCREEN_W
/2, y
+FONT_SPACING
/2, msg
);
221 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
223 if (buttons_pressed
&& state
==0 && time
>0.2)
227 bool KeyPressed(int key
, int mod
)
229 if (state
==0 && time
>0.2)
234 virtual void Update(double timedelta
)
236 Menu::Update(timedelta
);
237 if(state
&& time
> 0.2)
242 int HintMessage::flags
= 1<<31 | 1<<30;
244 struct HintReview
: public HintMessage
250 HintReview() : HintMessage(hint
[31]), page(31), page_dir(0), page_display(0)
253 for (int i
=0; i
<32; i
++)
258 void Cancel() { Pop(); }
259 void Select() { Pop(); }
262 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
264 if (buttons_pressed
==1)
266 if (y
< SCREEN_H
/4-FONT_SPACING
+2)
268 else if (y
> SCREEN_H
/4+FONT_SPACING
*numLines
+FONT_SPACING
)
274 Menu::Mouse(x
,y
,dx
,dy
,buttons_pressed
, buttons_released
, buttons
);
277 bool KeyPressed(int key
, int mod
)
281 else if (key
==SDLK_RIGHT
)
284 return Menu::KeyPressed(key
, mod
);
288 virtual void Render()
290 const double SPD
= 10;
293 sprintf (title
, _("Help (Page --)"), page_display
+1, page_count
);
295 sprintf (title
, _("Help (Page %d/%d)"), page_display
+1, page_count
);
300 y
= SCREEN_H
/4+int(MAX(0, time
*SPD
)*-page_dir
*SCREEN_H
);
302 y
= SCREEN_H
/4+int(MAX(0, 1-time
*SPD
)*page_dir
*SCREEN_H
);
306 PrintC(false, SCREEN_W
/2, y
-FONT_SPACING
*2, "^");
307 PrintC(false, SCREEN_W
/2, y
+FONT_SPACING
*(numLines
+1)+FONT_SPACING
/2-2, "_");
310 HintMessage::Render(0,y
);
312 if (time
> 1.0/SPD
&& page_dir
&& state
==0)
315 page
= (page
+page_dir
) & 31;
317 if (hint
[page
]) break;
319 } while (hint
[page
]==0 || !(flags
&(1<<page
)));
322 page_display
= (page_display
+ page_count
+ page_dir
) % page_count
;
327 if (time
>1.0/SPD
&& state
==1)
328 state
=0, page_dir
= 0;
330 virtual void Update(double timedelta
)
332 Menu::Update(timedelta
);
344 #define MAX_GAMESLOT 4
347 OPT_GAMESLOT_LAST
= OPT_GAMESLOT_0
+ MAX_GAMESLOT
- 1,
351 OPT_GOTO_MAP_CONTINUE
,
357 OPT_QUIT_MENU_CONFIRM
,
367 char optionSlotName
[MAX_GAMESLOT
][40] = {0};
368 char currentSlot
[80] = "";
370 char* GetSlotName(int i
, char * t
)
372 sprintf(t
, "save%d.dat", i
+1);
376 char * optionString
[] = {
385 _("Toggle Fullscreen"),
390 _("Return to Title"),
393 _("Yes, really delete it!"),
397 _("View Credits Sequence"), _("View Credits Sequence"),
401 struct OptMenu
: public Menu
410 OptMenu(const char * t
) : select(0), title(t
)
419 r
.x
=(SCREEN_W
-r
.w
)/2;
424 const int SPACE
= int(FONT_SPACING
* 1.5);
426 r2
.h
= SPACE
*num_opt
+ FONT_SPACING
/2;
427 r
.h
= r2
.h
+ (FONT_SPACING
+2*2);
428 r
.y
-= FONT_SPACING
+2;
433 void RenderOption(int o
, const char * s
)
435 int y
= r2
.y
+ FONT_SPACING
/2 + int(FONT_SPACING
* 1.5) * o
;
438 int x
= r
.x
+ font
[' '].w
;
439 int x1
= x
+ (font
[' '].w
+ font
['>'].w
+ FONT_X_SPACING
*2) / 2;
442 //x += int( sin(time*9)*2.5 );
443 //y += int( sin(time*9 + 1.5)*1.5 );
444 Print(x
, y
, "> %s", s
);
448 Print(x1
, y
, "%s", s
);
456 //x += int( sin(time*9)*2.5 );
457 //y += int( sin(time*9 + 1.5)*1.5 );
458 PrintC(false, x
, y
, "> %s <", s
);
462 PrintC(false, x
, y
, "%s", s
);
470 if (select
<0) select
= num_opt
-1;
471 if (select
>=num_opt
) select
= 0;
473 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
477 if (x
<r2
.x
|| y
<r2
.y
|| x
>r2
.x
+r2
.w
|| y
>r2
.y
+r2
.h
)
479 if (buttons_pressed
!=4 && buttons_pressed
!=2)
484 select
= (y
-r2
.y
-FONT_SPACING
/3) / int(FONT_SPACING
*1.5);
485 if (select
<0) select
= 0;
486 if (select
>=num_opt
) select
= num_opt
-1;
489 if (buttons_pressed
==1)
491 Menu::Mouse(x
, y
, dx
, dy
, buttons_pressed
, buttons_released
, buttons
);
503 SDL_FillRect(screen
, &r
, SDL_MapRGB(screen
->format
, 60,90,90));
504 SDL_FillRect(screen
, &r2
, SDL_MapRGB(screen
->format
, 20,50,50));
508 int y
= r2
.y
+ FONT_SPACING
/ 2;
510 Print(r2
.x
+font
[' '].w
, r
.y
+4, title
);
512 PrintC(false, r2
.x
+r2
.w
/2, r
.y
+4, title
);
516 for (int i
=0; i
<num_opt
; i
++)
517 RenderOption(i
, optionString
[opt
[i
]]);
525 struct WinLoseScreen
: public OptMenu
528 int score
, par
, best_score
;
529 WinLoseScreen(bool _win
, int _score
=0, int _par
=0, int _prev_score
=0) :
532 best_score(_prev_score
),
534 OptMenu(_win
? _("Level Complete!") : _("Emi can't swim..."))
537 opt
[num_opt
++] = OPT_UNDO
;
539 opt
[num_opt
++] = OPT_RESTART
;
540 opt
[num_opt
++] = win
? OPT_GOTO_MAP_CONTINUE
: OPT_GOTO_MAP
;
546 r
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
547 r2
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
554 OptMenu::RenderTitle();
557 r2
.y
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
559 OptMenu::RenderOptions();
562 r2
.y
-= FONT_SPACING
* 3 + FONT_SPACING
/2;
567 int y
= r2
.y
+ FONT_SPACING
/2;
568 if (score
< best_score
&& score
<= par
)
569 PrintC(true, x
, y
, _("New Best Score: %d Par Score: %d Par Beaten!"), score
, par
);
570 else if (score
< best_score
)
571 PrintC(true, x
, y
, _("New Best Score: %d Par Score: %d"), score
, par
);
572 else if (par
&& best_score
)
573 PrintC(true, x
, y
, _("Score: %d Previous Best: %d Par Score: %d"), score
, best_score
, par
);
575 PrintC(true, x
, y
+FONT_SPACING
/2, _("Well Done! Level Completed!"));
582 HackKeyPress('z', 0);
584 bool KeyPressed(int key
, int mod
)
586 if (key
=='z' || key
=='u' || key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
)
588 if (key
=='r' && (mod
& KMOD_CTRL
))
591 HackKeyPress(key
, mod
);
594 return OptMenu::KeyPressed(key
, mod
);
596 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
598 if (buttons_pressed
==4)
604 OptMenu::Mouse(x
, y
, dx
, dy
, buttons_pressed
, buttons_released
, buttons
);
615 struct OptMenuTitle
: public OptMenu
617 OptMenuTitle(const char * t
) : OptMenu(t
)
625 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
626 // SDL_FillRect(screen, &a, SDL_MapRGB(screen->format, 10,25,25));
629 SDL_BlitSurface(titlePage
, &a
, screen
, &a
);
631 OptMenu::RenderTitle();
632 OptMenu::RenderOptions();
641 int x
= SCREEN_W
- r
.x
- r
.w
;// - FONT_SPACING;
642 int y
= SCREEN_H
- r
.y
- r
.h
+ FONT_SPACING
/4;// - FONT_SPACING;
645 r
.w
+=20; r2
.w
+=20; r
.h
+=20; r2
.h
+=20;
647 r
.h
= r2
.h
= SCREEN_H
;
649 r
.y
= r2
.y
- FONT_SPACING
- 2;
653 const char *ending
[] = {
654 _(" Very Well Done! "),
655 "", "", "", "", "", "",
657 "", "", "*15,4", "", "",
659 _("All Levels Cleared!"),
661 "", "", "*5,7", "", "",
663 _("Not a single green hexagon is left unbroken."),
665 _("Truly, you are a master of hexagon hopping!"),
667 "", "", "*9,10", "", "",
669 "", _("Credits"), "", "", "",
670 _("<Design & Direction:"), ">Tom Beaumont", "", "",
671 _("<Programming:"), ">Tom Beaumont", "", "",
672 _("<Graphics:"), ">Tom Beaumont", "", "",
673 _("<Thanks to:"), ">Kris Beaumont", "", "",
674 // "", "<Some useless facts...", "",
675 _("<Tools and libraries used:"), "", ">Photoshop LE", ">Inno Setup", ">Wings 3D", ">MSVC", ">SDL", "",
676 _("<Fonts used:"), "", ">Copperplate gothic bold", ">Verdana", "",
678 "", "", "*12,14", "", "",
680 _("Thanks for playing!")
683 const char *ending2
[] = {
684 _(" Absolutely Amazing! "),
687 "", "", "*15,4", "", "",
689 _("All Levels Mastered!!"),
691 "", "", "*5,7", "", "",
693 _("You crushed every last green hexagon with"),
694 _("breathtaking efficiency!"),
696 _("You truly are a grand master of hexagon hopping!"),
699 const int endingLen
= sizeof(ending
)/sizeof(ending
[0]);
700 const int endingLen2
= sizeof(ending2
)/sizeof(ending2
[0]);
701 const int scrollMax
= SCREEN_H
+ (endingLen
+1) * FONT_SPACING
;
703 struct Ending
: public Menu
706 double x
,y
,xs
,ys
,xa
,ya
;
710 void Update(double td
)
712 if (type
==EMPTY
) return;
719 if (type
==TILE_LASER_HEAD
&& time
<0.3)
720 type
=TILE_FIRE_PARTICLE_1
;
721 if (type
==TILE_FIRE_PARTICLE_1
&& time
<0.1)
722 type
=TILE_FIRE_PARTICLE_2
;
724 // if (type==COLLAPSABLE || type==COLLAPSE_DOOR)
725 // for (int i=int((time)*40); i<int((time+td)*40); i++)
726 // new Particle(TILE_GREEN_FRAGMENT_1, x+32-rand()%63, y+20-rand()%40);
728 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT
)
729 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_1
, time
+=rand()%100*0.01;
730 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_1
)
731 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_2
, time
+=rand()%100*0.01;
732 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_2
)
739 for (int i
=0; i
<40; i
++)
740 new Particle(TILE_LASER_HEAD
, x
, y
);
741 for (int i
=0; i
<40; i
++)
742 new Particle(TILE_GREEN_FRAGMENT
+ rand() % 3, x
+32-rand()%63, y
+20-rand()%40);
744 if (type
==COLLAPSE_DOOR
)
755 if (type
==EMPTY
) return;
757 if (type
<0.05 && type
<15)
758 RenderTile(false, tileSolid
[type
] ? TILE_WHITE_WALL
: TILE_WHITE_TILE
, int(x
)+scrollX
, int(y
)+scrollY
);
760 RenderTile(false, type
, int(x
)+scrollX
, int(y
)+scrollY
);
763 Particle() : type(EMPTY
) {}
764 Particle(int t
, int _x
) : type(t
), x(_x
)
771 //x=rand() % SCREEN_W;
772 //y=rand() % SCREEN_H;
777 Particle(int t
, double _x
, double _y
) : type(t
)
781 double r
= (rand() % 2000) * PI
/ 1000;
782 double d
= rand() % 50 + 250;
786 time
= 1 + (rand() & 255) /255.0;
787 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
789 xa
=-xs
/time
; ya
=-ys
/time
;
790 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
791 ya
+= 500, ya
/=2, xa
/=2, xs
/=2, ys
/=2;
793 ~Particle() { type
= EMPTY
; }
794 void* operator new(size_t sz
);
802 static Ending
* ending
;
804 Ending(bool _goodEnd
) : goodEnding(_goodEnd
)
806 memset(p
, 0, sizeof(p
));
815 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
816 SDL_FillRect(screen
, &a
, SDL_MapRGB(screen
->format
, 10,25,25));
818 for (int i
=0; i
<sizeof(p
)/sizeof(p
[0]); i
++)
823 int xr
= SCREEN_W
*4/5;
824 int y
= SCREEN_H
- int(scroll
);
825 for (int i
=0; i
<endingLen
; i
++)
827 if (y
>-FONT_SPACING
*2 && y
<SCREEN_H
+FONT_SPACING
)
829 const char * xx
= (i
<endingLen2
&& goodEnding
) ? ending2
[i
] : ::ending
[i
];
831 Print(xl
, y
+FONT_SPACING
, xx
+1);
836 RenderTile(false, atoi(xx
+1), (xl
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
837 RenderTile(false, atoi(strchr(xx
, ',')+1), (xr
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
840 PrintC(false, x
, y
, xx
);
844 if (scroll
> scrollMax
+ FONT_SPACING
*10)
845 PrintC(true, x
, SCREEN_H
/2-FONT_SPACING
/2, _("The End"));
850 bool KeyPressed(int key
, int mod
)
852 if (key
=='r' && (mod
& KMOD_CTRL
))
855 memset(p
, 0, sizeof(p
));
858 return Menu::KeyPressed(key
, mod
);
862 void Update(double td
)
869 if (keyState
[SDLK_LSHIFT
])
872 t
= MAX(-td
*5, -time
);
875 double s
= scroll
= time
* 50;
876 // if (scroll > scrollMax)
877 // scroll = fmod(scroll, scrollMax);
878 // scroll = 0, time = 0;
880 if (old
>4 && time
> 4)
882 if (scroll
< scrollMax
+ FONT_SPACING
*17)
884 for (int i
=int( old
/2.5); i
<int(time
/2.5); i
++)
886 int xs
= (rand()%SCREEN_W
* 6 + 1) / 8;
887 for (int j
=rand()%3+1; j
; j
--)
888 new Particle(rand()&1 ? COLLAPSABLE
: COLLAPSE_DOOR
, xs
+j
*64);
891 if (scroll
> scrollMax
+ FONT_SPACING
*27)
898 Ending
* Ending::ending
= 0;
899 void* Ending::Particle::operator new(size_t sz
)
901 static int start
= 0;
902 const int max
= sizeof(ending
->p
)/sizeof(ending
->p
[0]);
903 for (int i
=0; i
<max
; i
++)
906 if (start
==max
) start
=0;
907 if (ending
->p
[start
].type
==EMPTY
)
908 return &ending
->p
[start
];
910 return &ending
->p
[rand() % max
];
913 struct TitleMenu
: public OptMenuTitle
915 TitleMenu() : OptMenuTitle("")
921 for (int i
=0; i
<MAX_GAMESLOT
; i
++)
925 FILE* f
= file_open(tmp
, "rb");
928 p
.LoadSave(f
, false);
931 if (p
.general
.completionPercentage
==100 && p
.general
.masteredPercentage
==100)
932 sprintf(optionSlotName
[i
], _("Continue game %d (All Clear!)"), i
+1, p
.general
.completionPercentage
, p
.general
.masteredPercentage
);
933 else if (p
.general
.completionPercentage
==100)
934 sprintf(optionSlotName
[i
], _("Continue game %d (%d%% + %d%%)"), i
+1, p
.general
.completionPercentage
, p
.general
.masteredPercentage
);
936 sprintf(optionSlotName
[i
], _("Continue game %d (%d%% complete)"), i
+1, p
.general
.completionPercentage
);
938 opt
[num_opt
++] = OPT_GAMESLOT_0
+ i
;
942 // sprintf(optionSlotName[i], "Start new game (slot %d)", i+1);
943 // opt[num_opt++] = OPT_GAMESLOT_0 + i;
951 if (num_opt
< MAX_GAMESLOT
)
952 opt
[num_opt
++] = OPT_GAMESLOT_NEW
;
954 opt
[num_opt
++] = OPT_OPTIONS
;
956 opt
[num_opt
++] = OPT_END
;
957 opt
[num_opt
++] = OPT_END2
;
959 opt
[num_opt
++] = OPT_QUIT
;
964 r2
.y
-=FONT_SPACING
*2;
967 r
.y
+=FONT_SPACING
+FONT_SPACING
/2, r2
.y
+=FONT_SPACING
+FONT_SPACING
/2;
970 bool KeyPressed(int key
, int mod
);
973 struct QuitConfirmMenu
: public OptMenuTitle
975 QuitConfirmMenu() : OptMenuTitle(_("Quit: Are you sure?"))
977 opt
[num_opt
++] = OPT_QUIT_CONFIRM
;
978 opt
[select
=num_opt
++] = OPT_QUIT_CANCEL
;
981 r
.y
+= FONT_SPACING
*1;
982 r2
.y
+= FONT_SPACING
*2;
987 struct DeleteConfirmMenu
: public OptMenuTitle
991 DeleteConfirmMenu(int _num
) : OptMenuTitle(&tmp
[0]), num(_num
)
995 sprintf(tmp
, _("Really delete game %d?"), num
+1);
996 opt
[num_opt
++] = OPT_DELETE_CONFIRM
;
997 opt
[select
=num_opt
++] = OPT_DELETE_CANCEL
;
1000 r
.y
+= FONT_SPACING
*1;
1001 r2
.y
+= FONT_SPACING
*2;
1005 if (select
<0 || select
>=num_opt
)
1007 if (opt
[select
] == OPT_DELETE_CONFIRM
)
1009 GetSlotName(num
, tmp
);
1018 bool TitleMenu::KeyPressed(int key
, int mod
)
1020 if (key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
|| key
==SDLK_F2
)
1022 if (select
<0 || select
>=num_opt
|| opt
[select
]<OPT_GAMESLOT_0
|| opt
[select
]>OPT_GAMESLOT_LAST
)
1024 int i
= opt
[select
] - OPT_GAMESLOT_0
;
1026 new DeleteConfirmMenu(i
);
1030 return OptMenu::KeyPressed(key
, mod
);
1033 struct PauseMenu
: public OptMenu
1035 PauseMenu(bool isMap
, bool allowGotoMap
, int allowEnd
, int allowEnd2
) : OptMenu(_("Paused"))
1037 opt
[num_opt
++] = OPT_RESUME
;
1039 opt
[num_opt
++] = OPT_RESTART
;
1040 opt
[num_opt
++] = OPT_OPTIONS
;
1041 opt
[num_opt
++] = OPT_HELP
;
1042 if (allowEnd
|| allowEnd2
)
1043 opt
[num_opt
++] = allowEnd2
? OPT_END2
: OPT_END
;
1044 opt
[num_opt
++] = (isMap
|| !allowGotoMap
) ? OPT_QUIT_MENU_CONFIRM
: OPT_GOTO_MAP
;
1047 virtual bool KeyPressed(int key
, int mod
)
1049 if (key
=='p' || key
==SDLK_PAUSE
)
1054 return Menu::KeyPressed(key
, mod
);
1059 struct OptionMenu
: public OptMenuTitle
1062 OptionMenu(bool _title
) : OptMenuTitle(_("Options")), title(_title
)
1064 opt
[num_opt
++] = OPT_FULLSCREEN
;
1066 opt
[num_opt
++] = OPT_BACK
;
1070 OptMenuTitle::Init(), renderBG
=false;
1071 r
.y
+= FONT_SPACING
;
1072 r2
.y
+= FONT_SPACING
*2;
1075 OptMenu::Init(), renderBG
=true;
1080 OptMenuTitle::Render();
1086 void RenderFade(double time
, int dir
, int seed
);
1088 struct Fader
: public Menu
1093 Fader(int _dir
, int _result
, double _speed
=1) : dir(_dir
), result(_result
), speed(_speed
)
1095 renderBG
= under
? under
->renderBG
: true;
1102 RenderFade(time
, dir
, (long)this);
1104 void Update(double timedelta
)
1106 Menu::Update(timedelta
* speed
);
1112 else if (time
>= 0.5)
1122 Pop(); // Remove old menu
1123 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
| KMOD_SHIFT
); // Reload map combination!
1127 Pop(); // Remove old menu
1128 new Fader(1, 0, speed
);
1130 if (result
==-5 || result
==-7)
1132 new Ending(result
==-7);
1133 new Fader(1, 0, speed
);
1139 void Ending::Cancel()
1141 new Fader(-1, -6, 0.3);
1145 void ToggleFullscreen();
1147 void OptMenu::Select()
1149 if (select
<0 || select
>=num_opt
)
1159 HackKeyPress('r', KMOD_CTRL
);
1163 case OPT_GOTO_MAP_CONTINUE
:
1165 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
);
1169 new QuitConfirmMenu();
1172 case OPT_FULLSCREEN
:
1176 case OPT_QUIT_CONFIRM
:
1180 case OPT_QUIT_MENU_CONFIRM
:
1186 new OptionMenu(!activeMenu
->renderBG
);
1193 case OPT_QUIT_CANCEL
:
1199 new Fader(-1, -5, 0.3);
1203 new Fader(-1, -7, 0.3);
1208 HackKeyPress('z', 0);
1212 if (opt
[select
]>=OPT_GAMESLOT_0
&& opt
[select
]<=OPT_GAMESLOT_LAST
1213 || opt
[select
]==OPT_GAMESLOT_NEW
&& freeSlot
>=0)
1215 if (opt
[select
]==OPT_GAMESLOT_NEW
)
1216 GetSlotName(freeSlot
, currentSlot
);
1218 GetSlotName(opt
[select
]-OPT_GAMESLOT_0
, currentSlot
);