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 "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
)
264 else if (buttons_pressed
==8)
266 else if (buttons_pressed
==16)
269 Menu::Mouse(x
,y
,dx
,dy
,buttons_pressed
, buttons_released
, buttons
);
272 bool KeyPressed(int key
, int mod
)
276 else if (key
==SDLK_RIGHT
)
279 return Menu::KeyPressed(key
, mod
);
283 virtual void Render()
285 const double SPD
= 10;
288 sprintf (title
, "Help (Page --)", page_display
+1, page_count
);
290 sprintf (title
, "Help (Page %d/%d)", page_display
+1, page_count
);
295 y
= SCREEN_H
/4+int(MAX(0, time
*SPD
)*-page_dir
*SCREEN_H
);
297 y
= SCREEN_H
/4+int(MAX(0, 1-time
*SPD
)*page_dir
*SCREEN_H
);
301 PrintC(false, SCREEN_W
/2, y
-FONT_SPACING
*2, "^");
302 PrintC(false, SCREEN_W
/2, y
+FONT_SPACING
*(numLines
+1)+FONT_SPACING
/2-2, "_");
305 HintMessage::Render(0,y
);
307 if (time
> 1.0/SPD
&& page_dir
&& state
==0)
310 page
= (page
+page_dir
) & 31;
312 if (hint
[page
]) break;
314 } while (hint
[page
]==0 || !(flags
&(1<<page
)));
317 page_display
= (page_display
+ page_count
+ page_dir
) % page_count
;
322 if (time
>1.0/SPD
&& state
==1)
323 state
=0, page_dir
= 0;
325 virtual void Update(double timedelta
)
327 Menu::Update(timedelta
);
339 #define MAX_GAMESLOT 4
342 OPT_GAMESLOT_LAST
= OPT_GAMESLOT_0
+ MAX_GAMESLOT
- 1,
346 OPT_GOTO_MAP_CONTINUE
,
352 OPT_QUIT_MENU_CONFIRM
,
362 char optionSlotName
[MAX_GAMESLOT
][40] = {0};
363 char currentSlot
[80] = "";
365 char* GetSlotName(int i
, char * t
)
367 sprintf(t
, "save%d.dat", i
+1);
371 char * optionString
[] = {
388 "Yes, really delete it!",
392 "View Credits Sequence", "View Credits Sequence",
396 struct OptMenu
: public Menu
405 OptMenu(const char * t
) : select(0), title(t
)
414 r
.x
=(SCREEN_W
-r
.w
)/2;
419 const int SPACE
= int(FONT_SPACING
* 1.5);
421 r2
.h
= SPACE
*num_opt
+ FONT_SPACING
/2;
422 r
.h
= r2
.h
+ (FONT_SPACING
+2*2);
423 r
.y
-= FONT_SPACING
+2;
428 void RenderOption(int o
, const char * s
)
430 int y
= r2
.y
+ FONT_SPACING
/2 + int(FONT_SPACING
* 1.5) * o
;
433 int x
= r
.x
+ font
[' '].w
;
434 int x1
= x
+ (font
[' '].w
+ font
['>'].w
+ FONT_X_SPACING
*2) / 2;
437 //x += int( sin(time*9)*2.5 );
438 //y += int( sin(time*9 + 1.5)*1.5 );
439 Print(x
, y
, "> %s", s
);
443 Print(x1
, y
, "%s", s
);
451 //x += int( sin(time*9)*2.5 );
452 //y += int( sin(time*9 + 1.5)*1.5 );
453 PrintC(false, x
, y
, "> %s <", s
);
457 PrintC(false, x
, y
, "%s", s
);
465 if (select
<0) select
= num_opt
-1;
466 if (select
>=num_opt
) select
= 0;
468 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
472 if (x
<r2
.x
|| y
<r2
.y
|| x
>r2
.x
+r2
.w
|| y
>r2
.y
+r2
.h
)
474 if (buttons_pressed
!=4 && buttons_pressed
!=2)
479 select
= (y
-r2
.y
-FONT_SPACING
/3) / int(FONT_SPACING
*1.5);
480 if (select
<0) select
= 0;
481 if (select
>=num_opt
) select
= num_opt
-1;
484 if (buttons_pressed
==1)
486 Menu::Mouse(x
, y
, dx
, dy
, buttons_pressed
, buttons_released
, buttons
);
498 SDL_FillRect(screen
, &r
, SDL_MapRGB(screen
->format
, 60,90,90));
499 SDL_FillRect(screen
, &r2
, SDL_MapRGB(screen
->format
, 20,50,50));
503 int y
= r2
.y
+ FONT_SPACING
/ 2;
505 Print(r2
.x
+font
[' '].w
, r
.y
+4, title
);
507 PrintC(false, r2
.x
+r2
.w
/2, r
.y
+4, title
);
511 for (int i
=0; i
<num_opt
; i
++)
512 RenderOption(i
, optionString
[opt
[i
]]);
520 struct WinLoseScreen
: public OptMenu
523 int score
, par
, best_score
;
524 WinLoseScreen(bool _win
, int _score
=0, int _par
=0, int _prev_score
=0) :
527 best_score(_prev_score
),
529 OptMenu(_win
? "Level Complete!" : "Emi can't swim...")
532 opt
[num_opt
++] = OPT_UNDO
;
534 opt
[num_opt
++] = OPT_RESTART
;
535 opt
[num_opt
++] = win
? OPT_GOTO_MAP_CONTINUE
: OPT_GOTO_MAP
;
541 r
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
542 r2
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
549 OptMenu::RenderTitle();
552 r2
.y
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
554 OptMenu::RenderOptions();
557 r2
.y
-= FONT_SPACING
* 3 + FONT_SPACING
/2;
562 int y
= r2
.y
+ FONT_SPACING
/2;
563 if (score
< best_score
&& score
<= par
)
564 PrintC(true, x
, y
, "New Best Score: %d Par Score: %d Par Beaten!", score
, par
);
565 else if (score
< best_score
)
566 PrintC(true, x
, y
, "New Best Score: %d Par Score: %d", score
, par
);
567 else if (par
&& best_score
)
568 PrintC(true, x
, y
, "Score: %d Previous Best: %d Par Score: %d", score
, best_score
, par
);
570 PrintC(true, x
, y
+FONT_SPACING
/2, "Well Done! Level Completed!");
577 HackKeyPress('z', 0);
579 bool KeyPressed(int key
, int mod
)
581 if (key
=='z' || key
=='u' || key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
)
583 if (key
=='r' && (mod
& KMOD_CTRL
))
586 HackKeyPress(key
, mod
);
589 return OptMenu::KeyPressed(key
, mod
);
591 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
593 if (buttons_pressed
==4)
599 OptMenu::Mouse(x
, y
, dx
, dy
, buttons_pressed
, buttons_released
, buttons
);
610 struct OptMenuTitle
: public OptMenu
612 OptMenuTitle(const char * t
) : OptMenu(t
)
620 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
621 // SDL_FillRect(screen, &a, SDL_MapRGB(screen->format, 10,25,25));
624 SDL_BlitSurface(titlePage
, &a
, screen
, &a
);
626 OptMenu::RenderTitle();
627 OptMenu::RenderOptions();
636 int x
= SCREEN_W
- r
.x
- r
.w
;// - FONT_SPACING;
637 int y
= SCREEN_H
- r
.y
- r
.h
+ FONT_SPACING
/4;// - FONT_SPACING;
640 r
.w
+=20; r2
.w
+=20; r
.h
+=20; r2
.h
+=20;
642 r
.h
= r2
.h
= SCREEN_H
;
644 r
.y
= r2
.y
- FONT_SPACING
- 2;
648 const char *ending
[] = {
650 "", "", "", "", "", "",
652 "", "", "*15,4", "", "",
654 "All Levels Cleared!",
656 "", "", "*5,7", "", "",
658 "Not a single green hexagon is left unbroken.",
660 "Truly, you are a master of hexagon hopping!",
662 "", "", "*9,10", "", "",
664 "", "Credits", "", "", "",
665 "<Design & Direction:", ">Tom Beaumont", "", "",
666 "<Programming:", ">Tom Beaumont", "", "",
667 "<Graphics:", ">Tom Beaumont", "", "",
668 "<Thanks to:", ">Kris Beaumont", "", "",
669 // "", "<Some useless facts...", "",
670 "<Tools and libraries used:", "", ">Photoshop LE", ">Inno Setup", ">Wings 3D", ">MSVC", ">SDL", "",
671 "<Fonts used:", "", ">Copperplate gothic bold", ">Verdana", "",
673 "", "", "*12,14", "", "",
675 "Thanks for playing!"
678 const char *ending2
[] = {
679 " Absolutely Amazing! ",
682 "", "", "*15,4", "", "",
684 "All Levels Mastered!!",
686 "", "", "*5,7", "", "",
688 "You crushed every last green hexagon with",
689 "breathtaking efficiency!",
691 "You truly are a grand master of hexagon hopping!",
694 const int endingLen
= sizeof(ending
)/sizeof(ending
[0]);
695 const int endingLen2
= sizeof(ending2
)/sizeof(ending2
[0]);
696 const int scrollMax
= SCREEN_H
+ (endingLen
+1) * FONT_SPACING
;
698 struct Ending
: public Menu
701 double x
,y
,xs
,ys
,xa
,ya
;
705 void Update(double td
)
707 if (type
==EMPTY
) return;
714 if (type
==TILE_LASER_HEAD
&& time
<0.3)
715 type
=TILE_FIRE_PARTICLE_1
;
716 if (type
==TILE_FIRE_PARTICLE_1
&& time
<0.1)
717 type
=TILE_FIRE_PARTICLE_2
;
719 // if (type==COLLAPSABLE || type==COLLAPSE_DOOR)
720 // for (int i=int((time)*40); i<int((time+td)*40); i++)
721 // new Particle(TILE_GREEN_FRAGMENT_1, x+32-rand()%63, y+20-rand()%40);
723 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT
)
724 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_1
, time
+=rand()%100*0.01;
725 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_1
)
726 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_2
, time
+=rand()%100*0.01;
727 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_2
)
734 for (int i
=0; i
<40; i
++)
735 new Particle(TILE_LASER_HEAD
, x
, y
);
736 for (int i
=0; i
<40; i
++)
737 new Particle(TILE_GREEN_FRAGMENT
+ rand() % 3, x
+32-rand()%63, y
+20-rand()%40);
739 if (type
==COLLAPSE_DOOR
)
750 if (type
==EMPTY
) return;
752 if (type
<0.05 && type
<15)
753 RenderTile(false, tileSolid
[type
] ? TILE_WHITE_WALL
: TILE_WHITE_TILE
, int(x
)+scrollX
, int(y
)+scrollY
);
755 RenderTile(false, type
, int(x
)+scrollX
, int(y
)+scrollY
);
758 Particle() : type(EMPTY
) {}
759 Particle(int t
, int _x
) : type(t
), x(_x
)
766 //x=rand() % SCREEN_W;
767 //y=rand() % SCREEN_H;
772 Particle(int t
, double _x
, double _y
) : type(t
)
776 double r
= (rand() % 2000) * PI
/ 1000;
777 double d
= rand() % 50 + 250;
781 time
= 1 + (rand() & 255) /255.0;
782 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
784 xa
=-xs
/time
; ya
=-ys
/time
;
785 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
786 ya
+= 500, ya
/=2, xa
/=2, xs
/=2, ys
/=2;
788 ~Particle() { type
= EMPTY
; }
789 void* operator new(size_t sz
);
797 static Ending
* ending
;
799 Ending(bool _goodEnd
) : goodEnding(_goodEnd
)
801 memset(p
, 0, sizeof(p
));
810 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
811 SDL_FillRect(screen
, &a
, SDL_MapRGB(screen
->format
, 10,25,25));
813 for (int i
=0; i
<sizeof(p
)/sizeof(p
[0]); i
++)
818 int xr
= SCREEN_W
*4/5;
819 int y
= SCREEN_H
- int(scroll
);
820 for (int i
=0; i
<endingLen
; i
++)
822 if (y
>-FONT_SPACING
*2 && y
<SCREEN_H
+FONT_SPACING
)
824 const char * xx
= (i
<endingLen2
&& goodEnding
) ? ending2
[i
] : ::ending
[i
];
826 Print(xl
, y
+FONT_SPACING
, xx
+1);
831 RenderTile(false, atoi(xx
+1), (xl
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
832 RenderTile(false, atoi(strchr(xx
, ',')+1), (xr
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
835 PrintC(false, x
, y
, xx
);
839 if (scroll
> scrollMax
+ FONT_SPACING
*10)
840 PrintC(true, x
, SCREEN_H
/2-FONT_SPACING
/2, "The End");
845 bool KeyPressed(int key
, int mod
)
847 if (key
=='r' && (mod
& KMOD_CTRL
))
850 memset(p
, 0, sizeof(p
));
853 return Menu::KeyPressed(key
, mod
);
857 void Update(double td
)
864 if (keyState
[SDLK_LSHIFT
])
867 t
= MAX(-td
*5, -time
);
870 double s
= scroll
= time
* 50;
871 // if (scroll > scrollMax)
872 // scroll = fmod(scroll, scrollMax);
873 // scroll = 0, time = 0;
875 if (old
>4 && time
> 4)
877 if (scroll
< scrollMax
+ FONT_SPACING
*17)
879 for (int i
=int( old
/2.5); i
<int(time
/2.5); i
++)
881 int xs
= (rand()%SCREEN_W
* 6 + 1) / 8;
882 for (int j
=rand()%3+1; j
; j
--)
883 new Particle(rand()&1 ? COLLAPSABLE
: COLLAPSE_DOOR
, xs
+j
*64);
886 if (scroll
> scrollMax
+ FONT_SPACING
*27)
893 Ending
* Ending::ending
= 0;
894 void* Ending::Particle::operator new(size_t sz
)
896 static int start
= 0;
897 const int max
= sizeof(ending
->p
)/sizeof(ending
->p
[0]);
898 for (int i
=0; i
<max
; i
++)
901 if (start
==max
) start
=0;
902 if (ending
->p
[start
].type
==EMPTY
)
903 return &ending
->p
[start
];
905 return &ending
->p
[rand() % max
];
908 struct TitleMenu
: public OptMenuTitle
910 TitleMenu() : OptMenuTitle("")
916 for (int i
=0; i
<MAX_GAMESLOT
; i
++)
920 FILE* f
= file_open(tmp
, "rb");
923 p
.LoadSave(f
, false);
926 if (p
.general
.completionPercentage
==100 && p
.general
.masteredPercentage
==100)
927 sprintf(optionSlotName
[i
], "Continue game %d (All Clear!)", i
+1, p
.general
.completionPercentage
, p
.general
.masteredPercentage
);
928 else if (p
.general
.completionPercentage
==100)
929 sprintf(optionSlotName
[i
], "Continue game %d (%d%% + %d%%)", i
+1, p
.general
.completionPercentage
, p
.general
.masteredPercentage
);
931 sprintf(optionSlotName
[i
], "Continue game %d (%d%% complete)", i
+1, p
.general
.completionPercentage
);
933 opt
[num_opt
++] = OPT_GAMESLOT_0
+ i
;
937 // sprintf(optionSlotName[i], "Start new game (slot %d)", i+1);
938 // opt[num_opt++] = OPT_GAMESLOT_0 + i;
946 if (num_opt
< MAX_GAMESLOT
)
947 opt
[num_opt
++] = OPT_GAMESLOT_NEW
;
949 opt
[num_opt
++] = OPT_OPTIONS
;
951 opt
[num_opt
++] = OPT_END
;
952 opt
[num_opt
++] = OPT_END2
;
954 opt
[num_opt
++] = OPT_QUIT
;
959 r2
.y
-=FONT_SPACING
*2;
962 r
.y
+=FONT_SPACING
+FONT_SPACING
/2, r2
.y
+=FONT_SPACING
+FONT_SPACING
/2;
965 bool KeyPressed(int key
, int mod
);
968 struct QuitConfirmMenu
: public OptMenuTitle
970 QuitConfirmMenu() : OptMenuTitle("Quit: Are you sure?")
972 opt
[num_opt
++] = OPT_QUIT_CONFIRM
;
973 opt
[select
=num_opt
++] = OPT_QUIT_CANCEL
;
976 r
.y
+= FONT_SPACING
*1;
977 r2
.y
+= FONT_SPACING
*2;
982 struct DeleteConfirmMenu
: public OptMenuTitle
986 DeleteConfirmMenu(int _num
) : OptMenuTitle(&tmp
[0]), num(_num
)
990 sprintf(tmp
, "Really delete game %d?", num
+1);
991 opt
[num_opt
++] = OPT_DELETE_CONFIRM
;
992 opt
[select
=num_opt
++] = OPT_DELETE_CANCEL
;
995 r
.y
+= FONT_SPACING
*1;
996 r2
.y
+= FONT_SPACING
*2;
1000 if (select
<0 || select
>=num_opt
)
1002 if (opt
[select
] == OPT_DELETE_CONFIRM
)
1004 GetSlotName(num
, tmp
);
1013 bool TitleMenu::KeyPressed(int key
, int mod
)
1015 if (key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
|| key
==SDLK_F2
)
1017 if (select
<0 || select
>=num_opt
|| opt
[select
]<OPT_GAMESLOT_0
|| opt
[select
]>OPT_GAMESLOT_LAST
)
1019 int i
= opt
[select
] - OPT_GAMESLOT_0
;
1021 new DeleteConfirmMenu(i
);
1025 return OptMenu::KeyPressed(key
, mod
);
1028 struct PauseMenu
: public OptMenu
1030 PauseMenu(bool isMap
, bool allowGotoMap
, int allowEnd
, int allowEnd2
) : OptMenu("Paused")
1032 opt
[num_opt
++] = OPT_RESUME
;
1034 opt
[num_opt
++] = OPT_RESTART
;
1035 opt
[num_opt
++] = OPT_OPTIONS
;
1036 opt
[num_opt
++] = OPT_HELP
;
1037 if (allowEnd
|| allowEnd2
)
1038 opt
[num_opt
++] = allowEnd2
? OPT_END2
: OPT_END
;
1039 opt
[num_opt
++] = (isMap
|| !allowGotoMap
) ? OPT_QUIT_MENU_CONFIRM
: OPT_GOTO_MAP
;
1042 virtual bool KeyPressed(int key
, int mod
)
1044 if (key
=='p' || key
==SDLK_PAUSE
)
1049 return Menu::KeyPressed(key
, mod
);
1054 struct OptionMenu
: public OptMenuTitle
1057 OptionMenu(bool _title
) : OptMenuTitle("Options"), title(_title
)
1059 opt
[num_opt
++] = OPT_FULLSCREEN
;
1061 opt
[num_opt
++] = OPT_BACK
;
1065 OptMenuTitle::Init(), renderBG
=false;
1066 r
.y
+= FONT_SPACING
;
1067 r2
.y
+= FONT_SPACING
*2;
1070 OptMenu::Init(), renderBG
=true;
1075 OptMenuTitle::Render();
1081 void RenderFade(double time
, int dir
, int seed
);
1083 struct Fader
: public Menu
1088 Fader(int _dir
, int _result
, double _speed
=1) : dir(_dir
), result(_result
), speed(_speed
)
1090 renderBG
= under
? under
->renderBG
: true;
1097 RenderFade(time
, dir
, (long)this);
1099 void Update(double timedelta
)
1101 Menu::Update(timedelta
* speed
);
1107 else if (time
>= 0.5)
1117 Pop(); // Remove old menu
1118 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
| KMOD_SHIFT
); // Reload map combination!
1122 Pop(); // Remove old menu
1123 new Fader(1, 0, speed
);
1125 if (result
==-5 || result
==-7)
1127 new Ending(result
==-7);
1128 new Fader(1, 0, speed
);
1134 void Ending::Cancel()
1136 new Fader(-1, -6, 0.3);
1140 void ToggleFullscreen();
1142 void OptMenu::Select()
1144 if (select
<0 || select
>=num_opt
)
1154 HackKeyPress('r', KMOD_CTRL
);
1158 case OPT_GOTO_MAP_CONTINUE
:
1160 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
);
1164 new QuitConfirmMenu();
1167 case OPT_FULLSCREEN
:
1171 case OPT_QUIT_CONFIRM
:
1175 case OPT_QUIT_MENU_CONFIRM
:
1181 new OptionMenu(!activeMenu
->renderBG
);
1188 case OPT_QUIT_CANCEL
:
1194 new Fader(-1, -5, 0.3);
1198 new Fader(-1, -7, 0.3);
1203 HackKeyPress('z', 0);
1207 if (opt
[select
]>=OPT_GAMESLOT_0
&& opt
[select
]<=OPT_GAMESLOT_LAST
1208 || opt
[select
]==OPT_GAMESLOT_NEW
&& freeSlot
>=0)
1210 if (opt
[select
]==OPT_GAMESLOT_NEW
)
1211 GetSlotName(freeSlot
, currentSlot
);
1213 GetSlotName(opt
[select
]-OPT_GAMESLOT_0
, currentSlot
);