837f08fab22b81e86e705edd0c86f87358fdfca2
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
)
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));
499 int y
= r2
.y
+ FONT_SPACING
/ 2;
501 Print(r2
.x
+font
[' '].w
, r
.y
+4, title
);
503 PrintC(false, r2
.x
+r2
.w
/2, r
.y
+4, title
);
507 for (int i
=0; i
<num_opt
; i
++)
508 RenderOption(i
, optionString
[opt
[i
]]);
516 struct WinLoseScreen
: public OptMenu
519 int score
, par
, best_score
;
520 WinLoseScreen(bool _win
, int _score
=0, int _par
=0, int _prev_score
=0) :
523 best_score(_prev_score
),
525 OptMenu(_win
? "Level Complete!" : "Emi can't swim...")
528 opt
[num_opt
++] = OPT_UNDO
;
530 opt
[num_opt
++] = OPT_RESTART
;
531 opt
[num_opt
++] = win
? OPT_GOTO_MAP_CONTINUE
: OPT_GOTO_MAP
;
537 r
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
538 r2
.h
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
545 OptMenu::RenderTitle();
548 r2
.y
+= FONT_SPACING
* 3 + FONT_SPACING
/2;
550 OptMenu::RenderOptions();
553 r2
.y
-= FONT_SPACING
* 3 + FONT_SPACING
/2;
558 int y
= r2
.y
+ FONT_SPACING
/2;
559 if (score
< best_score
&& score
<= par
)
560 PrintC(true, x
, y
, "New Best Score: %d Par Score: %d Par Beaten!", score
, par
);
561 else if (score
< best_score
)
562 PrintC(true, x
, y
, "New Best Score: %d Par Score: %d", score
, par
);
563 else if (par
&& best_score
)
564 PrintC(true, x
, y
, "Score: %d Previous Best: %d Par Score: %d", score
, best_score
, par
);
566 PrintC(true, x
, y
+FONT_SPACING
/2, "Well Done! Level Completed!");
573 HackKeyPress('z', 0);
575 bool KeyPressed(int key
, int mod
)
577 if (key
=='z' || key
=='u' || key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
)
579 if (key
=='r' && (mod
& KMOD_CTRL
))
582 HackKeyPress(key
, mod
);
585 return OptMenu::KeyPressed(key
, mod
);
587 virtual void Mouse(int x
, int y
, int dx
, int dy
, int buttons_pressed
, int buttons_released
, int buttons
)
589 if (buttons_pressed
==4)
595 OptMenu::Mouse(x
, y
, dx
, dy
, buttons_pressed
, buttons_released
, buttons
);
606 struct OptMenuTitle
: public OptMenu
608 OptMenuTitle(const char * t
) : OptMenu(t
)
616 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
617 // SDL_FillRect(screen, &a, SDL_MapRGB(screen->format, 10,25,25));
620 SDL_BlitSurface(titlePage
, &a
, screen
, &a
);
622 OptMenu::RenderTitle();
623 OptMenu::RenderOptions();
632 int x
= SCREEN_W
- r
.x
- r
.w
;// - FONT_SPACING;
633 int y
= SCREEN_H
- r
.y
- r
.h
+ FONT_SPACING
/4;// - FONT_SPACING;
636 r
.w
+=20; r2
.w
+=20; r
.h
+=20; r2
.h
+=20;
638 r
.h
= r2
.h
= SCREEN_H
;
640 r
.y
= r2
.y
- FONT_SPACING
- 2;
644 const char *ending
[] = {
646 "", "", "", "", "", "",
648 "", "", "*15,4", "", "",
650 "All Levels Cleared!",
652 "", "", "*5,7", "", "",
654 "Not a single green hexagon is left unbroken.",
656 "Truly, you are a master of hexagon hopping!",
658 "", "", "*9,10", "", "",
660 "", "Credits", "", "", "",
661 "<Design & Direction:", ">Tom Beaumont", "", "",
662 "<Programming:", ">Tom Beaumont", "", "",
663 "<Graphics:", ">Tom Beaumont", "", "",
664 "<Thanks to:", ">Kris Beaumont", "", "",
665 // "", "<Some useless facts...", "",
666 "<Tools and libraries used:", "", ">Photoshop LE", ">Inno Setup", ">Wings 3D", ">MSVC", ">SDL", "",
667 "<Fonts used:", "", ">Copperplate gothic bold", ">Verdana", "",
669 "", "", "*12,14", "", "",
671 "Thanks for playing!"
674 const char *ending2
[] = {
675 " Absolutely Amazing! ",
678 "", "", "*15,4", "", "",
680 "All Levels Mastered!!",
682 "", "", "*5,7", "", "",
684 "You crushed every last green hexagon with",
685 "breathtaking efficiency!",
687 "You truly are a grand master of hexagon hopping!",
690 const int endingLen
= sizeof(ending
)/sizeof(ending
[0]);
691 const int endingLen2
= sizeof(ending2
)/sizeof(ending2
[0]);
692 const int scrollMax
= SCREEN_H
+ (endingLen
+1) * FONT_SPACING
;
694 struct Ending
: public Menu
697 double x
,y
,xs
,ys
,xa
,ya
;
701 void Update(double td
)
703 if (type
==EMPTY
) return;
710 if (type
==TILE_LASER_HEAD
&& time
<0.3)
711 type
=TILE_FIRE_PARTICLE_1
;
712 if (type
==TILE_FIRE_PARTICLE_1
&& time
<0.1)
713 type
=TILE_FIRE_PARTICLE_2
;
715 // if (type==COLLAPSABLE || type==COLLAPSE_DOOR)
716 // for (int i=int((time)*40); i<int((time+td)*40); i++)
717 // new Particle(TILE_GREEN_FRAGMENT_1, x+32-rand()%63, y+20-rand()%40);
719 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT
)
720 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_1
, time
+=rand()%100*0.01;
721 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_1
)
722 xa
=0, ys
=-ys
/2, y
=SCREEN_H
, type
=TILE_GREEN_FRAGMENT_2
, time
+=rand()%100*0.01;
723 if (y
>SCREEN_H
&& type
==TILE_GREEN_FRAGMENT_2
)
730 for (int i
=0; i
<40; i
++)
731 new Particle(TILE_LASER_HEAD
, x
, y
);
732 for (int i
=0; i
<40; i
++)
733 new Particle(TILE_GREEN_FRAGMENT
+ rand() % 3, x
+32-rand()%63, y
+20-rand()%40);
735 if (type
==COLLAPSE_DOOR
)
746 if (type
==EMPTY
) return;
748 if (type
<0.05 && type
<15)
749 RenderTile(false, tileSolid
[type
] ? TILE_WHITE_WALL
: TILE_WHITE_TILE
, int(x
)+scrollX
, int(y
)+scrollY
);
751 RenderTile(false, type
, int(x
)+scrollX
, int(y
)+scrollY
);
754 Particle() : type(EMPTY
) {}
755 Particle(int t
, int _x
) : type(t
), x(_x
)
762 //x=rand() % SCREEN_W;
763 //y=rand() % SCREEN_H;
768 Particle(int t
, double _x
, double _y
) : type(t
)
772 double r
= (rand() % 2000) * PI
/ 1000;
773 double d
= rand() % 50 + 250;
777 time
= 1 + (rand() & 255) /255.0;
778 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
780 xa
=-xs
/time
; ya
=-ys
/time
;
781 if (t
==TILE_WATER_PARTICLE
|| t
==TILE_GREEN_FRAGMENT
|| t
==TILE_GREEN_FRAGMENT_1
)
782 ya
+= 500, ya
/=2, xa
/=2, xs
/=2, ys
/=2;
784 ~Particle() { type
= EMPTY
; }
785 void* operator new(size_t sz
);
793 static Ending
* ending
;
795 Ending(bool _goodEnd
) : goodEnding(_goodEnd
)
797 memset(p
, 0, sizeof(p
));
806 SDL_Rect a
= {0,0,SCREEN_W
,SCREEN_H
};
807 SDL_FillRect(screen
, &a
, SDL_MapRGB(screen
->format
, 10,25,25));
809 for (int i
=0; i
<sizeof(p
)/sizeof(p
[0]); i
++)
814 int xr
= SCREEN_W
*4/5;
815 int y
= SCREEN_H
- int(scroll
);
816 for (int i
=0; i
<endingLen
; i
++)
818 if (y
>-FONT_SPACING
*2 && y
<SCREEN_H
+FONT_SPACING
)
820 const char * xx
= (i
<endingLen2
&& goodEnding
) ? ending2
[i
] : ::ending
[i
];
822 Print(xl
, y
+FONT_SPACING
, xx
+1);
827 RenderTile(false, atoi(xx
+1), (xl
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
828 RenderTile(false, atoi(strchr(xx
, ',')+1), (xr
+x
)/2+scrollX
, y
+FONT_SPACING
/2+scrollY
);
831 PrintC(false, x
, y
, xx
);
835 if (scroll
> scrollMax
+ FONT_SPACING
*10)
836 PrintC(true, x
, SCREEN_H
/2-FONT_SPACING
/2, "The End");
841 bool KeyPressed(int key
, int mod
)
843 if (key
=='r' && (mod
& KMOD_CTRL
))
846 memset(p
, 0, sizeof(p
));
849 return Menu::KeyPressed(key
, mod
);
853 void Update(double td
)
860 if (keyState
[SDLK_LSHIFT
])
863 t
= MAX(-td
*5, -time
);
866 double s
= scroll
= time
* 50;
867 // if (scroll > scrollMax)
868 // scroll = fmod(scroll, scrollMax);
869 // scroll = 0, time = 0;
871 if (old
>4 && time
> 4)
873 if (scroll
< scrollMax
+ FONT_SPACING
*17)
875 for (int i
=int( old
/2.5); i
<int(time
/2.5); i
++)
877 int xs
= (rand()%SCREEN_W
* 6 + 1) / 8;
878 for (int j
=rand()%3+1; j
; j
--)
879 new Particle(rand()&1 ? COLLAPSABLE
: COLLAPSE_DOOR
, xs
+j
*64);
882 if (scroll
> scrollMax
+ FONT_SPACING
*27)
889 Ending
* Ending::ending
= 0;
890 void* Ending::Particle::operator new(size_t sz
)
892 static int start
= 0;
893 const int max
= sizeof(ending
->p
)/sizeof(ending
->p
[0]);
894 for (int i
=0; i
<max
; i
++)
897 if (start
==max
) start
=0;
898 if (ending
->p
[start
].type
==EMPTY
)
899 return &ending
->p
[start
];
901 return &ending
->p
[rand() % max
];
904 struct TitleMenu
: public OptMenuTitle
906 TitleMenu() : OptMenuTitle("")
912 for (int i
=0; i
<MAX_GAMESLOT
; i
++)
916 FILE* f
= file_open(tmp
, "rb");
919 p
.LoadSave(f
, false);
922 if (p
.general
.completionPercentage
==100 && p
.general
.masteredPercentage
==100)
923 sprintf(optionSlotName
[i
], "Continue game %d (All Clear!)", i
+1, p
.general
.completionPercentage
, p
.general
.masteredPercentage
);
924 else if (p
.general
.completionPercentage
==100)
925 sprintf(optionSlotName
[i
], "Continue game %d (%d%% + %d%%)", i
+1, p
.general
.completionPercentage
, p
.general
.masteredPercentage
);
927 sprintf(optionSlotName
[i
], "Continue game %d (%d%% complete)", i
+1, p
.general
.completionPercentage
);
929 opt
[num_opt
++] = OPT_GAMESLOT_0
+ i
;
933 // sprintf(optionSlotName[i], "Start new game (slot %d)", i+1);
934 // opt[num_opt++] = OPT_GAMESLOT_0 + i;
942 if (num_opt
< MAX_GAMESLOT
)
943 opt
[num_opt
++] = OPT_GAMESLOT_NEW
;
945 opt
[num_opt
++] = OPT_OPTIONS
;
947 opt
[num_opt
++] = OPT_END
;
948 opt
[num_opt
++] = OPT_END2
;
950 opt
[num_opt
++] = OPT_QUIT
;
955 r2
.y
-=FONT_SPACING
*2;
958 r
.y
+=FONT_SPACING
+FONT_SPACING
/2, r2
.y
+=FONT_SPACING
+FONT_SPACING
/2;
961 bool KeyPressed(int key
, int mod
);
964 struct QuitConfirmMenu
: public OptMenuTitle
966 QuitConfirmMenu() : OptMenuTitle("Quit: Are you sure?")
968 opt
[num_opt
++] = OPT_QUIT_CONFIRM
;
969 opt
[select
=num_opt
++] = OPT_QUIT_CANCEL
;
972 r
.y
+= FONT_SPACING
*1;
973 r2
.y
+= FONT_SPACING
*2;
978 struct DeleteConfirmMenu
: public OptMenuTitle
982 DeleteConfirmMenu(int _num
) : OptMenuTitle(&tmp
[0]), num(_num
)
986 sprintf(tmp
, "Really delete game %d?", num
+1);
987 opt
[num_opt
++] = OPT_DELETE_CONFIRM
;
988 opt
[select
=num_opt
++] = OPT_DELETE_CANCEL
;
991 r
.y
+= FONT_SPACING
*1;
992 r2
.y
+= FONT_SPACING
*2;
996 if (select
<0 || select
>=num_opt
)
998 if (opt
[select
] == OPT_DELETE_CONFIRM
)
1000 GetSlotName(num
, tmp
);
1009 bool TitleMenu::KeyPressed(int key
, int mod
)
1011 if (key
==SDLK_DELETE
|| key
==SDLK_BACKSPACE
|| key
==SDLK_F2
)
1013 if (select
<0 || select
>=num_opt
|| opt
[select
]<OPT_GAMESLOT_0
|| opt
[select
]>OPT_GAMESLOT_LAST
)
1015 int i
= opt
[select
] - OPT_GAMESLOT_0
;
1017 new DeleteConfirmMenu(i
);
1021 return OptMenu::KeyPressed(key
, mod
);
1024 struct PauseMenu
: public OptMenu
1026 PauseMenu(bool isMap
, bool allowGotoMap
, int allowEnd
, int allowEnd2
) : OptMenu("Paused")
1028 opt
[num_opt
++] = OPT_RESUME
;
1030 opt
[num_opt
++] = OPT_RESTART
;
1031 opt
[num_opt
++] = OPT_OPTIONS
;
1032 opt
[num_opt
++] = OPT_HELP
;
1033 if (allowEnd
|| allowEnd2
)
1034 opt
[num_opt
++] = allowEnd2
? OPT_END2
: OPT_END
;
1035 opt
[num_opt
++] = (isMap
|| !allowGotoMap
) ? OPT_QUIT_MENU_CONFIRM
: OPT_GOTO_MAP
;
1038 virtual bool KeyPressed(int key
, int mod
)
1040 if (key
=='p' || key
==SDLK_PAUSE
)
1045 return Menu::KeyPressed(key
, mod
);
1050 struct OptionMenu
: public OptMenuTitle
1053 OptionMenu(bool _title
) : OptMenuTitle("Options"), title(_title
)
1055 opt
[num_opt
++] = OPT_FULLSCREEN
;
1057 opt
[num_opt
++] = OPT_BACK
;
1061 OptMenuTitle::Init(), renderBG
=false;
1062 r
.y
+= FONT_SPACING
;
1063 r2
.y
+= FONT_SPACING
*2;
1066 OptMenu::Init(), renderBG
=true;
1071 OptMenuTitle::Render();
1077 void RenderFade(double time
, int dir
, int seed
);
1079 struct Fader
: public Menu
1084 Fader(int _dir
, int _result
, double _speed
=1) : dir(_dir
), result(_result
), speed(_speed
)
1086 renderBG
= under
? under
->renderBG
: true;
1093 RenderFade(time
, dir
, (long)this);
1095 void Update(double timedelta
)
1097 Menu::Update(timedelta
* speed
);
1103 else if (time
>= 0.5)
1113 Pop(); // Remove old menu
1114 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
| KMOD_SHIFT
); // Reload map combination!
1118 Pop(); // Remove old menu
1119 new Fader(1, 0, speed
);
1121 if (result
==-5 || result
==-7)
1123 new Ending(result
==-7);
1124 new Fader(1, 0, speed
);
1130 void Ending::Cancel()
1132 new Fader(-1, -6, 0.3);
1136 void ToggleFullscreen();
1138 void OptMenu::Select()
1140 if (select
<0 || select
>=num_opt
)
1150 HackKeyPress('r', KMOD_CTRL
);
1154 case OPT_GOTO_MAP_CONTINUE
:
1156 HackKeyPress(SDLK_ESCAPE
, KMOD_CTRL
);
1160 new QuitConfirmMenu();
1163 case OPT_FULLSCREEN
:
1167 case OPT_QUIT_CONFIRM
:
1171 case OPT_QUIT_MENU_CONFIRM
:
1177 new OptionMenu(!activeMenu
->renderBG
);
1184 case OPT_QUIT_CANCEL
:
1190 new Fader(-1, -5, 0.3);
1194 new Fader(-1, -7, 0.3);
1199 HackKeyPress('z', 0);
1203 if (opt
[select
]>=OPT_GAMESLOT_0
&& opt
[select
]<=OPT_GAMESLOT_LAST
1204 || opt
[select
]==OPT_GAMESLOT_NEW
&& freeSlot
>=0)
1206 if (opt
[select
]==OPT_GAMESLOT_NEW
)
1207 GetSlotName(freeSlot
, currentSlot
);
1209 GetSlotName(opt
[select
]-OPT_GAMESLOT_0
, currentSlot
);