Logo Search packages:      
Sourcecode: hex-a-hop version File versions  Download package

menus.h

/*
    Copyright (C) 2005-2007 Tom Beaumont

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/


struct Menu;
Menu* activeMenu = 0;
Menu* deadMenu = 0;

static void HackKeyPress(int key, int mod)
{
      int k = keyState[key];
      StateMakerBase::current->KeyPressed(key, mod);
      keyState[key] = k;
}

00031 struct Menu {
      bool renderBG;

      Menu() : under(activeMenu), time(0), renderBG(true) { activeMenu = this; }
      
      virtual ~Menu() { 
            if(this!=deadMenu) FATAL("this!=deadMenu"); 
            deadMenu=under; 
      }

      static void Pop()
      {
            if (!activeMenu) return;
            Menu* m = activeMenu;
            activeMenu = activeMenu->under;
            m->under = deadMenu;
            deadMenu = m;
      }

      virtual bool KeyPressed(int key, int mod)
      {
            if (key=='w' || key==SDLK_UP || key==SDLK_KP8 || key=='q' || key=='e' || key==SDLK_KP7 || key==SDLK_KP9)
                  Move(-1), noMouse=1;
            else if (key=='s' || key==SDLK_DOWN || key==SDLK_KP2 || key=='a' || key=='d' || key==SDLK_KP1 || key==SDLK_KP3)
                  Move(1), noMouse=1;
            else if (key==' ' || key==SDLK_RETURN)
            {
                  Select();
                  noMouse=1;
            }
            else if (key==SDLK_ESCAPE || key==SDLK_BACKSPACE || key==SDLK_KP_PERIOD || key==SDLK_DELETE)
                  Cancel();
            else
                  return false;
            return true;
      }
      virtual void Mouse(int x, int y, int dx, int dy, int buttons_pressed, int buttons_released, int buttons) 
      {
            if (buttons_pressed==4 || buttons_pressed==2)
                  Cancel();
      }
      
      virtual void Move(int dir) {}
      virtual void Select() {}
      virtual void Cancel() {}

      virtual void Update(double timedelta) {time+=timedelta;}
      virtual void Render() = 0;

      Menu * under;
      double time;
};

const char * hint[] = {
      
/*EMPTY*/
"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.",
/*NORMAL*/
0,
/*COLLAPSABLE*/
"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!", 
/*COLLAPSE_DOOR*/
"The coloured walls flatten themselves when there  are no matching coloured tiles remaining.",
/*TRAMPOLINE*/
"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!",
/*SPINNER*/
"A red spinner tile will rotate the pieces around  it when you step on it.",
/*WALL*/
0,
/*COLLAPSABLE2*/
"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...",
/*COLLAPSE_DOOR2*/
0,
/*GUN*/
"Yellow laser tiles fire when you step on them.    Shooting other laser tiles is more destructive.",
/*TRAP*/
"Ice is slippery!    Please be careful!!",
/*COLLAPSABLE3*/
0,
/*BUILDER*/
"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.",
/*SWITCH*/
0,
/*FLOATING_BALL*/
"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.",
/*LIFT_DOWN*/
"The blue lifts go up or down when you land on them.",
/*LIFT_UP*/
0,

0,0,0,0,
//Item 0 (21)
"The spiky anti-ice pickups turn icy tiles into blue ones.    They get used automatically when you land on ice.",
//Item 1 (22)
"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.",

0,0,

// Map (25)
"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.",

// Scoring (26)
"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?",

0,0,0,

// End of help (30)
"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!",

// First help page (31)
"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.",
};

00144 struct HintMessage : public Menu
{
      static int flags;

      const char * msg;
      char title[50];
      int numLines;
      int state;

      static bool FlagTile(int t, bool newStuff=true)
      {
            if (t==LIFT_UP) t=LIFT_DOWN;
            if (newStuff && (flags & (1<<t))) return false;
            if (!newStuff && !(flags & (1<<t))) return false;
            if (t>31) return false;
            if (!hint[t]) return false;

            flags |= 1<<t;
            new HintMessage(hint[t]);
            return true;
      }

      HintMessage(const char * m) { Init(m); }

      void Init(const char * m)
      {
            numLines = 1;
            state = 0; time = 0;
            memset(title, 0, sizeof(title));
            char * x = strstr(m, "|");
            if (!x)
            {
                  msg = m;
                  strcpy(title, "Info:");
            }
            else
            {
                  strncpy(title, m, x-m);
                  msg=x+1;
            }

            const char * s = m;
            while ((s=strstr(s, "  ")))
                  s+=2, numLines++;
      }

      virtual void Render()
      {
            int y = SCREEN_H/4 + int(SCREEN_H*MAX(1-time*5, 0)*3/4);
            if (state)
                  y = SCREEN_H/4 + int(SCREEN_H*(-time*5)*3/4);

            Render(0, y);
            
            if (!state && time>0.2)
                  Print(SCREEN_W*3/4, SCREEN_H-FONT_SPACING, "Press any key");
      }

      void Render(int x, int y)
      {
            SDL_Rect r2 = {x+TILE_W1, y, SCREEN_W-TILE_W1*2, numLines*FONT_SPACING+FONT_SPACING};
            SDL_Rect r = {r2.x-2, r2.y-2-FONT_SPACING, r2.w+4, r2.h+4+FONT_SPACING};
            SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 60,90,90));
            SDL_FillRect(screen, &r2, SDL_MapRGB(screen->format, 20,50,50));
            Print(r.x+FONT_SPACING/4, y-FONT_SPACING, title);
            PrintC(true, x+SCREEN_W/2, y+FONT_SPACING/2, msg);
      }

      virtual void Mouse(int x, int y, int dx, int dy, int buttons_pressed, int buttons_released, int buttons) 
      {
            if (buttons_pressed && state==0 && time>0.2)
                  state = 1, time=0;
      }

      bool KeyPressed(int key, int mod)
      {
            if (state==0 && time>0.2)
                  state = 1, time=0;
            return true;
      }

      virtual void Update(double timedelta)
      {
            Menu::Update(timedelta);
            if(state && time > 0.2)
                  Pop();
      }
};

int HintMessage::flags = 1<<31 | 1<<30;

00235 struct HintReview : public HintMessage
{
      int page;
      int page_dir;
      int page_count;
      int page_display;
      HintReview() : HintMessage(hint[31]), page(31), page_dir(0), page_display(0)
      {
            page_count=0;
            for (int i=0; i<32; i++)
                  if (flags & (1<<i))
                        page_count++;
      }

      void Cancel() { Pop(); }
      void Select() { Pop(); }


      virtual void Mouse(int x, int y, int dx, int dy, int buttons_pressed, int buttons_released, int buttons) 
      {
            if (buttons_pressed==1)
            {
                  if (y < SCREEN_H/4-FONT_SPACING+2)
                        Move(-1);
                  else if (y > SCREEN_H/4+FONT_SPACING*numLines+FONT_SPACING)
                        Move(1);
                  else
                        Cancel();
            }
            else
                  Menu::Mouse(x,y,dx,dy,buttons_pressed, buttons_released, buttons);      
      }

      bool KeyPressed(int key, int mod)
      {
            if (key==SDLK_LEFT)
                  Move(-1);
            else if (key==SDLK_RIGHT)
                  Move(1);
            else
                  return Menu::KeyPressed(key, mod);
            return true;
      }

      virtual void Render()
      {
            const double SPD = 10;

#ifdef EDIT
            sprintf (title, "Help (Page --)", page_display+1, page_count);
#else
            sprintf (title, "Help (Page %d/%d)", page_display+1, page_count);
#endif

            int y=SCREEN_H/4;
            if (state==0)
                  y = SCREEN_H/4+int(MAX(0, time*SPD)*-page_dir*SCREEN_H);
            if (state==1)
                  y = SCREEN_H/4+int(MAX(0, 1-time*SPD)*page_dir*SCREEN_H);

            //if (!noMouse)
            {
                  PrintC(false, SCREEN_W/2, y-FONT_SPACING*2, "^");
                  PrintC(false, SCREEN_W/2, y+FONT_SPACING*(numLines+1)+FONT_SPACING/2-2, "_");
            }

            HintMessage::Render(0,y);

            if (time > 1.0/SPD && page_dir && state==0)
            {
                  do {
                        page = (page+page_dir) & 31;
#ifdef EDIT
                        if (hint[page]) break;
#endif
                  } while (hint[page]==0 || !(flags&(1<<page)));
                  Init(hint[page]);

                  page_display = (page_display + page_count + page_dir) % page_count;

                  time = 0;
                  state=1;
            }
            if (time>1.0/SPD && state==1)
                  state=0, page_dir = 0;
      }
      virtual void Update(double timedelta)
      {
            Menu::Update(timedelta);
      }
      void Move(int dir)
      {
            if (page_dir)
                  return;
            time = 0;
            page_dir = dir;
            state = 0;
      }
};

#define MAX_GAMESLOT 4
enum option {
      OPT_GAMESLOT_0,
      OPT_GAMESLOT_LAST = OPT_GAMESLOT_0 + MAX_GAMESLOT - 1,
      OPT_RESUME,
      OPT_RESTART,
      OPT_GOTO_MAP,
      OPT_GOTO_MAP_CONTINUE,
      OPT_FULLSCREEN,
      OPT_OPTIONS,
      OPT_QUIT,
      OPT_QUIT_CONFIRM,
      OPT_QUIT_CANCEL,
      OPT_QUIT_MENU_CONFIRM,
      OPT_HELP,
      OPT_GAMESLOT_NEW,
      OPT_DELETE_CONFIRM,
      OPT_DELETE_CANCEL,
      OPT_UNDO,
      OPT_BACK,
      OPT_END, OPT_END2,
};

char optionSlotName[MAX_GAMESLOT][40] = {0};
char currentSlot[80] = "";
int freeSlot = -1;
char* GetSlotName(int i, char * t)
{
       sprintf(t, "save%d.dat", i+1);
       return t;
}

char * optionString[] = {
      optionSlotName[0],
      optionSlotName[1],
      optionSlotName[2],
      optionSlotName[3],
      "Resume",
      "Restart Level",
      "Return to Map",
      "Continue",
      "Toggle Fullscreen",
      "Options",
      "Quit",
      "Yes",
      "No",
      "Return to Title",
      "Help",
      "Start New Game",
      "Yes, really delete it!",
      "Don't do it!",
      "Undo Last Move",
      "OK",
      "View Credits Sequence", "View Credits Sequence",
};


00392 struct OptMenu : public Menu
{
      int select;
      int num_opt;
      int opt[10];
      bool left_align;
      const char * title;
      SDL_Rect r, r2;

      OptMenu(const char * t) : select(0), title(t)
      {
            left_align = false;
            num_opt = 0;
      }

      void Init()
      {
            r.w=SCREEN_W/2;
            r.x=(SCREEN_W-r.w)/2;
            r.y=SCREEN_H/3;
            
            r2 = r;
            
            const int SPACE = int(FONT_SPACING * 1.5);

            r2.h = SPACE*num_opt + FONT_SPACING/2;
            r.h = r2.h + (FONT_SPACING+2*2);
            r.y -= FONT_SPACING+2;
            r.w += 2*2;
            r.x -= 2;
      }

      void RenderOption(int o, const char * s)
      {
            int y = r2.y + FONT_SPACING/2 + int(FONT_SPACING * 1.5) * o;
            if (left_align)
            {
                  int x = r.x + font[' '].w;
                  int x1 = x + (font[' '].w + font['>'].w + FONT_X_SPACING*2) / 2;
                  if (select==o)
                  {
                        //x += int( sin(time*9)*2.5 );
                        //y += int( sin(time*9 + 1.5)*1.5 );
                        Print(x, y, "> %s", s);
                  }
                  else
                  {
                        Print(x1, y, "%s", s);
                  }
            }
            else
            {
                  int x = r.x + r.w/2;
                  if (select==o)
                  {
                        //x += int( sin(time*9)*2.5 );
                        //y += int( sin(time*9 + 1.5)*1.5 );
                        PrintC(false, x, y, "> %s <", s);
                  }
                  else
                  {
                        PrintC(false, x, y, "%s", s);
                  }
            }
      }
      
      void Move(int dir)
      {
            select += dir;
            if (select<0) select = num_opt-1;
            if (select>=num_opt) select = 0;
      }
      virtual void Mouse(int x, int y, int dx, int dy, int buttons_pressed, int buttons_released, int buttons) 
      {
            if (1)
            {
                  if (x<r2.x || y<r2.y || x>r2.x+r2.w || y>r2.y+r2.h)
                  {
                        if (buttons_pressed!=4 && buttons_pressed!=2)
                              return;
                  }
                  else
                  {
                        select = (y-r2.y-FONT_SPACING/3) / int(FONT_SPACING*1.5);
                        if (select<0) select = 0;
                        if (select>=num_opt) select = num_opt-1;
                  }
            }
            if (buttons_pressed==1)
                  Select();
            Menu::Mouse(x, y, dx, dy, buttons_pressed, buttons_released, buttons);
      }
      void Select();

      void Render()
      {
            RenderBG();
            RenderTitle();
            RenderOptions();
      }
      void RenderBG()
      {
            SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 60,90,90));
            SDL_FillRect(screen, &r2, SDL_MapRGB(screen->format, 20,50,50));
      }
      void RenderTitle()
      {
            int y = r2.y + FONT_SPACING / 2;
            if (left_align)
                  Print(r2.x+font[' '].w, r.y+4, title);
            else
                  PrintC(false, r2.x+r2.w/2, r.y+4, title);
      }
      void RenderOptions()
      {
            for (int i=0; i<num_opt; i++)
                  RenderOption(i, optionString[opt[i]]);
      }
      void Cancel()
      {
            Pop();
      }
};

00516 struct WinLoseScreen : public OptMenu
{
      bool win;
      int score, par, best_score;
      WinLoseScreen(bool _win, int _score=0, int _par=0, int _prev_score=0) : 
            score(_score),
            par(_par),
            best_score(_prev_score),
            win(_win),
            OptMenu(_win ? "Level Complete!" : "Emi can't swim...")
      {
            if (!win)
                  opt[num_opt++] = OPT_UNDO;
            if (!win)
                  opt[num_opt++] = OPT_RESTART;
            opt[num_opt++] = win ? OPT_GOTO_MAP_CONTINUE : OPT_GOTO_MAP;

            Init();

            if (win)
            {
                  r.h += FONT_SPACING * 3 + FONT_SPACING/2;
                  r2.h += FONT_SPACING * 3 + FONT_SPACING/2;
            }
      }

      void Render()
      {
            OptMenu::RenderBG();
            OptMenu::RenderTitle();

            if (win)
                  r2.y += FONT_SPACING * 3 + FONT_SPACING/2;
            
            OptMenu::RenderOptions();
            
            if (win)
                  r2.y -= FONT_SPACING * 3 + FONT_SPACING/2;

            if (win)
            {
                  int x = r.x+r.w/2;
                  int y = r2.y + FONT_SPACING/2;
                  if (score < best_score && score <= par)
                        PrintC(true, x, y, "New Best Score: %d  Par Score: %d  Par Beaten!", score, par);
                  else if (score < best_score)
                        PrintC(true, x, y, "New Best Score: %d  Par Score: %d", score, par);
                  else if (par && best_score)
                        PrintC(true, x, y, "Score: %d  Previous Best: %d  Par Score: %d", score, best_score, par);      
                  else
                        PrintC(true, x, y+FONT_SPACING/2, "Well Done!  Level Completed!");      
            }
      }

      static void Undo()
      {
            Pop();
            HackKeyPress('z', 0);
      }
      bool KeyPressed(int key, int mod)
      {
            if (key=='z' || key=='u' || key==SDLK_DELETE || key==SDLK_BACKSPACE)
                  return Undo(), true;
            if (key=='r' && (mod & KMOD_CTRL))
            {
                  Pop();
                  HackKeyPress(key, mod);
                  return true;
            }
            return OptMenu::KeyPressed(key, mod);
      }
      virtual void Mouse(int x, int y, int dx, int dy, int buttons_pressed, int buttons_released, int buttons) 
      {
            if (buttons_pressed==4)
            {
                  Undo();
                  return;
            }
            
            OptMenu::Mouse(x, y, dx, dy, buttons_pressed, buttons_released, buttons);
      }
      void Cancel()
      {
            if (win)
                  select=0, Select();
            else
                  Undo();
      }
};

00606 struct OptMenuTitle : public OptMenu
{
      OptMenuTitle(const char * t) : OptMenu(t)
      {
            renderBG = false;
            //left_align = true;
      }

      void Render()
      {
            SDL_Rect a = {0,0,SCREEN_W,SCREEN_H};
//          SDL_FillRect(screen, &a, SDL_MapRGB(screen->format, 10,25,25));

            
            SDL_BlitSurface(titlePage, &a, screen, &a);

            OptMenu::RenderTitle();
            OptMenu::RenderOptions();
      }

      void Init()
      {
            OptMenu::Init();

            int xw = SCREEN_W/6;
            r.w += xw; r2.w+=xw;
            int x = SCREEN_W - r.x - r.w;// - FONT_SPACING;
            int y = SCREEN_H - r.y - r.h + FONT_SPACING/4;// - FONT_SPACING;
            r.x += x; r2.x += x;
            r.y += y; r2.y += y;
            r.w+=20; r2.w+=20; r.h+=20; r2.h+=20;

            r.h = r2.h = SCREEN_H;
            r2.y = SCREEN_H/2;
            r.y = r2.y - FONT_SPACING - 2;
      }
};

const char *ending[] = {
      " Very Well Done! ",
      "", "", "", "", "", "",
      
      "", "", "*15,4", "", "", 
      
      "All Levels Cleared!",
      
      "", "", "*5,7", "", "", 
      
      "Not a single green hexagon is left unbroken.",
      "", 
      "Truly, you are a master of hexagon hopping!",
      
      "", "", "*9,10", "", "", 
      
      "", "Credits", "", "", "",
      "<Design & Direction:", ">Tom Beaumont", "", "",
      "<Programming:", ">Tom Beaumont", "", "",
      "<Graphics:", ">Tom Beaumont", "", "",
      "<Thanks to:", ">Kris Beaumont", "",  "",
//    "", "<Some useless facts...", "",
      "<Tools and libraries used:", "", ">Photoshop LE", ">Inno Setup", ">Wings 3D", ">MSVC", ">SDL", "", 
      "<Fonts used:", "", ">Copperplate gothic bold", ">Verdana", "", 

      "", "", "*12,14", "", "", 

      "Thanks for playing!"
};

const char *ending2[] = {
      " Absolutely Amazing! ",
      "", "", "", "", "", 
      
      "", "", "*15,4", "", "", 
      
      "All Levels Mastered!!",
      
      "", "", "*5,7", "", "", 
      
      "You crushed every last green hexagon with",
      "breathtaking efficiency!", 
      "",
      "You truly are a grand master of hexagon hopping!",
};

const int endingLen = sizeof(ending)/sizeof(ending[0]);
const int endingLen2 = sizeof(ending2)/sizeof(ending2[0]);
const int scrollMax = SCREEN_H + (endingLen+1) * FONT_SPACING;

00694 struct Ending : public Menu
{
00696       struct Particle{
            double x,y,xs,ys,xa,ya;
            double time;
            int type;

            void Update(double td)
            {
                  if (type==EMPTY) return;
                  
                  time -= td;
                  x += xs*td;
                  y += ys*td;
                  xs += xa*td;
                  ys += ya*td;
                  if (type==TILE_LASER_HEAD && time<0.3)
                        type=TILE_FIRE_PARTICLE_1;
                  if (type==TILE_FIRE_PARTICLE_1 && time<0.1)
                        type=TILE_FIRE_PARTICLE_2;

//                if (type==COLLAPSABLE || type==COLLAPSE_DOOR)
//                      for (int i=int((time)*40); i<int((time+td)*40); i++)
//                            new Particle(TILE_GREEN_FRAGMENT_1, x+32-rand()%63, y+20-rand()%40);

                  if (y>SCREEN_H && type==TILE_GREEN_FRAGMENT)
                        xa=0, ys=-ys/2, y=SCREEN_H, type=TILE_GREEN_FRAGMENT_1, time+=rand()%100*0.01;
                  if (y>SCREEN_H && type==TILE_GREEN_FRAGMENT_1)
                        xa=0, ys=-ys/2, y=SCREEN_H, type=TILE_GREEN_FRAGMENT_2, time+=rand()%100*0.01;
                  if (y>SCREEN_H && type==TILE_GREEN_FRAGMENT_2)
                        type = EMPTY;

                  if (time<=0)
                  {
                        if (type < 10)
                        {
                              for (int i=0; i<40; i++)
                                    new Particle(TILE_LASER_HEAD, x, y);
                              for (int i=0; i<40; i++)
                                    new Particle(TILE_GREEN_FRAGMENT + rand() % 3, x+32-rand()%63, y+20-rand()%40);
                        }
                        if (type==COLLAPSE_DOOR)
                        {
                              type = COLLAPSABLE;
                              time += 1;
                        }
                        else
                        {
                              type = EMPTY;
                        }
                  }
                  
                  if (type==EMPTY) return;

                  if (type<0.05 && type<15)
                        RenderTile(false, tileSolid[type] ? TILE_WHITE_WALL : TILE_WHITE_TILE, int(x)+scrollX, int(y)+scrollY);
                  else
                        RenderTile(false, type, int(x)+scrollX, int(y)+scrollY);
            }

            Particle() : type(EMPTY) {}
            Particle(int t, int _x) : type(t), x(_x)
            {
                  xa=ys=xs=0; ya=400;
                  //if (t==1)
                  {
                        xs = rand()%100-50;
                        ys=-400-rand()%200;
                        //x=rand() % SCREEN_W;
                        //y=rand() % SCREEN_H;
                        y = SCREEN_H+20;
                        time = ys/-ya;
                  }
            }
            Particle(int t, double _x, double _y) : type(t)
            {
                  x=_x; y=_y;
                  xa=0; ya=-100;
                  double r = (rand() % 2000) * PI / 1000;
                  double d = rand() % 50 + 250;
                  
                  xs = sin(r)*d;
                  ys = cos(r)*d;
                  time = 1 + (rand() & 255) /255.0;
                  if (t==TILE_WATER_PARTICLE || t==TILE_GREEN_FRAGMENT || t==TILE_GREEN_FRAGMENT_1)
                        time = 2;
                  xa=-xs/time; ya=-ys/time;
                  if (t==TILE_WATER_PARTICLE || t==TILE_GREEN_FRAGMENT || t==TILE_GREEN_FRAGMENT_1)
                        ya += 500, ya/=2, xa/=2, xs/=2, ys/=2;
            }
            ~Particle() { type = EMPTY; }
            void* operator new(size_t sz);
      };

      Particle p[1000];

      double scroll;
      double t;
      bool goodEnding;
      static Ending* ending;
      
      Ending(bool _goodEnd) : goodEnding(_goodEnd)
      {
            memset(p, 0, sizeof(p));
            ending = this;
            renderBG = false;
            scroll = 0;
            t=0;
      }
      
      void Render()
      {
            SDL_Rect a = {0,0,SCREEN_W,SCREEN_H};
            SDL_FillRect(screen, &a, SDL_MapRGB(screen->format, 10,25,25));

            for (int i=0; i<sizeof(p)/sizeof(p[0]); i++)
                  p[i].Update(t);

            int x = a.x + a.w/2;
            int xl = SCREEN_W/5;
            int xr = SCREEN_W*4/5;
            int y = SCREEN_H - int(scroll);
            for (int i=0; i<endingLen; i++)
            {
                  if (y>-FONT_SPACING*2 && y<SCREEN_H+FONT_SPACING)
                  {
                        const char * xx = (i<endingLen2 && goodEnding) ? ending2[i] : ::ending[i];
                        if (xx[0]=='<')
                              Print(xl, y+FONT_SPACING, xx+1);
                        else if (xx[0]=='>')
                              PrintR(xr, y, xx+1);
                        else if (xx[0]=='*')
                        {
                              RenderTile(false, atoi(xx+1), (xl+x)/2+scrollX, y+FONT_SPACING/2+scrollY);
                              RenderTile(false, atoi(strchr(xx, ',')+1), (xr+x)/2+scrollX, y+FONT_SPACING/2+scrollY);
                        }
                        else
                              PrintC(false, x, y, xx);
                  }
                  y+=FONT_SPACING;
            }
            if (scroll > scrollMax + FONT_SPACING*10)
                  PrintC(true, x, SCREEN_H/2-FONT_SPACING/2, "The End");
      }
      
      void Cancel();
      
      bool KeyPressed(int key, int mod)
      {
            if (key=='r' && (mod & KMOD_CTRL))
            {
                  time = 0;
                  memset(p, 0, sizeof(p));
            }
            else
                  return Menu::KeyPressed(key, mod);
            return true;
      }

      void Update(double td)
      {
            noMouse = 1;

            double old = time;

            t = td;
            if (keyState[SDLK_LSHIFT]) 
                  t = td*5;
            if (keyState['0']) 
                  t = MAX(-td*5, -time);

            Menu::Update(t);
            double s = scroll = time * 50;
//          if (scroll > scrollMax)
//          scroll = fmod(scroll, scrollMax);
//                scroll = 0, time = 0;

            if (old>4 && time > 4)
            {
                  if (scroll < scrollMax + FONT_SPACING*17)
                  {
                        for (int i=int( old/2.5); i<int(time/2.5); i++)
                        {
                              int xs = (rand()%SCREEN_W * 6 + 1) / 8;
                              for (int j=rand()%3+1; j; j--)
                                    new Particle(rand()&1 ? COLLAPSABLE : COLLAPSE_DOOR, xs+j*64);
                        }
                  }
                  if (scroll > scrollMax + FONT_SPACING*27)
                        Cancel();
            }

      }
};

Ending* Ending::ending = 0;
void* Ending::Particle::operator new(size_t sz)
{
      static int start = 0;
      const int max = sizeof(ending->p)/sizeof(ending->p[0]);
      for (int i=0; i<max; i++)
      {
            start++;
            if (start==max) start=0;
            if (ending->p[start].type==EMPTY)
                  return &ending->p[start];
      }
      return &ending->p[rand() % max];
}

00904 struct TitleMenu : public OptMenuTitle
{
      TitleMenu() : OptMenuTitle("")
      {
            //left_align = 1;

            SaveState p;
            freeSlot = -1;
            for (int i=0; i<MAX_GAMESLOT; i++)
            {
                  char tmp[80];
                  GetSlotName(i, tmp);
                  FILE* f = file_open(tmp, "rb");
                  if (f)
                  {
                        p.LoadSave(f, false);
                        fclose(f);

                        if (p.general.completionPercentage==100 && p.general.masteredPercentage==100)
                              sprintf(optionSlotName[i], "Continue game %d (All Clear!)", i+1, p.general.completionPercentage, p.general.masteredPercentage);
                        else if (p.general.completionPercentage==100)
                              sprintf(optionSlotName[i], "Continue game %d (%d%% + %d%%)", i+1, p.general.completionPercentage, p.general.masteredPercentage);
                        else
                              sprintf(optionSlotName[i], "Continue game %d (%d%% complete)", i+1, p.general.completionPercentage);
      
                        opt[num_opt++] = OPT_GAMESLOT_0 + i;
                  }
                  else
                  {
//                      sprintf(optionSlotName[i], "Start new game (slot %d)", i+1);
//                      opt[num_opt++] = OPT_GAMESLOT_0 + i;

                        if (freeSlot==-1)
                              freeSlot = i;
                  }
            }
            
            
            if (num_opt < MAX_GAMESLOT)
                  opt[num_opt++] = OPT_GAMESLOT_NEW;

            opt[num_opt++] = OPT_OPTIONS;
#ifdef EDIT
            opt[num_opt++] = OPT_END;
            opt[num_opt++] = OPT_END2;
#endif
            opt[num_opt++] = OPT_QUIT;

            Init();
#ifdef EDIT
            r.y-=FONT_SPACING*2;
            r2.y-=FONT_SPACING*2;
#else
            if (num_opt==3)
                  r.y+=FONT_SPACING+FONT_SPACING/2, r2.y+=FONT_SPACING+FONT_SPACING/2;
#endif
      }
      bool KeyPressed(int key, int mod);
};

00964 struct QuitConfirmMenu : public OptMenuTitle
{
      QuitConfirmMenu() : OptMenuTitle("Quit: Are you sure?")
      {
            opt[num_opt++] = OPT_QUIT_CONFIRM;
            opt[select=num_opt++] = OPT_QUIT_CANCEL;
            Init();

            r.y += FONT_SPACING*1;
            r2.y += FONT_SPACING*2;
      }

};

00978 struct DeleteConfirmMenu : public OptMenuTitle
{
      char tmp[80];
      int num;
      DeleteConfirmMenu(int _num) : OptMenuTitle(&tmp[0]), num(_num)
      {
            //left_align = 1;

            sprintf(tmp, "Really delete game %d?", num+1);
            opt[num_opt++] = OPT_DELETE_CONFIRM;
            opt[select=num_opt++] = OPT_DELETE_CANCEL;
            Init();

            r.y += FONT_SPACING*1;
            r2.y += FONT_SPACING*2;
      }
      void Select()
      {
            if (select<0 || select>=num_opt)
                  return;
            if (opt[select] == OPT_DELETE_CONFIRM)
            {
                  GetSlotName(num, tmp);
                  remove(tmp);
            }
            Pop();
            Pop();
            new TitleMenu();
      }
};

bool TitleMenu::KeyPressed(int key, int mod)
{
      if (key==SDLK_DELETE || key==SDLK_BACKSPACE || key==SDLK_F2)
      {
            if (select<0 || select>=num_opt || opt[select]<OPT_GAMESLOT_0 || opt[select]>OPT_GAMESLOT_LAST)
                  return true;
            int i = opt[select] - OPT_GAMESLOT_0;

            new DeleteConfirmMenu(i);

            return true;
      }
      return OptMenu::KeyPressed(key, mod);
}

01024 struct PauseMenu : public OptMenu
{
      PauseMenu(bool isMap, bool allowGotoMap, int allowEnd, int allowEnd2) : OptMenu("Paused")
      {
            opt[num_opt++] = OPT_RESUME;
            if (!isMap)
                  opt[num_opt++] = OPT_RESTART;
            opt[num_opt++] = OPT_OPTIONS;
            opt[num_opt++] = OPT_HELP;
            if (allowEnd || allowEnd2)
                  opt[num_opt++] = allowEnd2 ? OPT_END2 : OPT_END;
            opt[num_opt++] = (isMap || !allowGotoMap) ? OPT_QUIT_MENU_CONFIRM : OPT_GOTO_MAP;
            Init();
      }
      virtual bool KeyPressed(int key, int mod)
      {
            if (key=='p' || key==SDLK_PAUSE)
            {
                  Cancel();
                  return true;
            }
            return Menu::KeyPressed(key, mod);
      }
      
};

01050 struct OptionMenu : public OptMenuTitle
{
      bool title;
      OptionMenu(bool _title) : OptMenuTitle("Options"), title(_title)
      {
            opt[num_opt++] = OPT_FULLSCREEN;
            
            opt[num_opt++] = OPT_BACK;
            
            if (title)
            {
                  OptMenuTitle::Init(), renderBG=false;
                  r.y += FONT_SPACING;
                  r2.y += FONT_SPACING*2;
            }
            else
                  OptMenu::Init(), renderBG=true;
      }
      void Render()
      {
            if (title)
                  OptMenuTitle::Render();
            else
                  OptMenu::Render();
      }
};

void RenderFade(double time, int dir, int seed);

01079 struct Fader : public Menu
{
      int dir;
      double speed;
      int result;
      Fader(int _dir, int _result, double _speed=1) : dir(_dir), result(_result), speed(_speed)
      {
            renderBG = under ? under->renderBG : true;
      }
      void Render()
      {
            if (under)
                  under->Render();

            RenderFade(time, dir, (long)this);
      }
      void Update(double timedelta)
      {
            Menu::Update(timedelta * speed);
            if (result==-2)
            {
                  if (time > 0.7)
                        quitting = 1;
            }
            else if (time >= 0.5)
            {
                  Pop();
                  if (result==-1)
                  {
                        new TitleMenu();
                        new Fader(1, -3);
                  }
                  if (result==-4)
                  {
                        Pop();      // Remove old menu
                        HackKeyPress(SDLK_ESCAPE, KMOD_CTRL | KMOD_SHIFT);    // Reload map combination!
                  }
                  if (result==-6)
                  {
                        Pop();      // Remove old menu
                        new Fader(1, 0, speed);
                  }
                  if (result==-5 || result==-7)
                  {
                        new Ending(result==-7);
                        new Fader(1, 0, speed);
                  }
            }
      }
};

void Ending::Cancel()
{
      new Fader(-1, -6, 0.3);
//    Pop();
}

void ToggleFullscreen();

void OptMenu::Select()
{
      if (select<0 || select>=num_opt)
            return;
      switch(opt[select])
      {
            case OPT_RESUME:
                  Cancel();
                  break;

            case OPT_RESTART:
                  Cancel();
                  HackKeyPress('r', KMOD_CTRL);
                  break;

            case OPT_GOTO_MAP:
            case OPT_GOTO_MAP_CONTINUE:
                  Pop();
                  HackKeyPress(SDLK_ESCAPE, KMOD_CTRL);
                  break;

            case OPT_QUIT:
                  new QuitConfirmMenu();
                  break;

            case OPT_FULLSCREEN:
                  ToggleFullscreen();
                  break;

            case OPT_QUIT_CONFIRM:
                  new Fader(-1, -2);
                  break;

            case OPT_QUIT_MENU_CONFIRM:
                  Pop();
                  new Fader(-1, -1);
                  break;

            case OPT_OPTIONS:
                  new OptionMenu(!activeMenu->renderBG);
                  break;

            case OPT_HELP:
                  new HintReview();
                  break;

            case OPT_QUIT_CANCEL:
            case OPT_BACK:
                  Pop();
                  break;

            case OPT_END:
                  new Fader(-1, -5, 0.3);
                  break;

            case OPT_END2:
                  new Fader(-1, -7, 0.3);
                  break;

            case OPT_UNDO:
                  Pop();
                  HackKeyPress('z', 0);
                  break;

            default:
                  if (opt[select]>=OPT_GAMESLOT_0 && opt[select]<=OPT_GAMESLOT_LAST 
                        || opt[select]==OPT_GAMESLOT_NEW && freeSlot>=0)
                  {
                        if (opt[select]==OPT_GAMESLOT_NEW)
                              GetSlotName(freeSlot, currentSlot);
                        else
                              GetSlotName(opt[select]-OPT_GAMESLOT_0, currentSlot);
                        new Fader(-1, -4);
                  }
                  break;
      }
}

Generated by  Doxygen 1.6.0   Back to index