game.cc

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2000-2004  The Exult Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #  include <config.h>
00022 #endif
00023 
00024 #ifndef ALPHA_LINUX_CXX
00025 #  include <cstdlib>
00026 #  include <cstring>
00027 #  include <unistd.h>
00028 #endif
00029 #include "menulist.h"
00030 #include "Audio.h"
00031 #include "Configuration.h"
00032 #include "databuf.h"
00033 #include "exult.h"
00034 #include "exult_flx.h"
00035 #include "files/U7file.h"
00036 #include "files/utils.h"
00037 #include "flic/playfli.h"
00038 #include "font.h"
00039 #include "game.h"
00040 #include "bggame.h"
00041 #include "sigame.h"
00042 #include "devgame.h"
00043 #include "gamewin.h"
00044 #include "keys.h"
00045 #include "mouse.h"
00046 #include "palette.h"
00047 #include "shapeid.h"
00048 
00049 #ifndef UNDER_CE
00050 using std::cout;
00051 using std::endl;
00052 using std::ifstream;
00053 using std::strcmp;
00054 using std::strcpy;
00055 using std::strncmp;
00056 using std::string;
00057 #endif
00058 
00059 bool Game::new_game_flag = false;
00060 bool Game::editing_flag = false;
00061 Game *game = 0;
00062 Exult_Game Game::game_type = BLACK_GATE;
00063 bool Game::expansion = false;
00064 
00065 static char av_name[17] = "";
00066 static int av_sex = -1;
00067 static int av_skin = -1;
00068 
00069 std::string Game::gametitle;
00070 
00071 unsigned int Game::ticks = 0;
00072 
00073 Game::Game() : menushapes()
00074 {
00075   try {       // Okay to fail if development game.
00076     menushapes.load(MAINSHP_FLX);
00077   } catch (const exult_exception &e) {
00078     if (!is_editing())
00079       throw e;
00080   }
00081   jive = false;
00082   gwin = Game_window::get_instance();
00083   win = gwin->get_win();
00084   ibuf = win->get_ib8();
00085   topx = (gwin->get_width()-320)/2;
00086   topy = (gwin->get_height()-200)/2;
00087   centerx = gwin->get_width()/2;
00088   centery = gwin->get_height()/2;
00089 }
00090 
00091 Game::~Game()
00092 {
00093 }
00094 
00095 Game *Game::create_game(Exult_Game mygame, const char *title)
00096 {
00097   switch(mygame) {
00098   case EXULT_DEVEL_GAME:
00099     assert(title != 0);
00100     gametitle = title;
00101     game_type = mygame;
00102     break;
00103   case SERPENT_ISLE:
00104     gametitle = "serpentisle";
00105     break;
00106   case BLACK_GATE:
00107   default:
00108     gametitle = "blackgate";
00109     break;
00110   }
00111 
00112   // See if map-editing.
00113   string d("config/disk/game/" + gametitle + "/editing");
00114   config->value(d.c_str(), editing_flag, false);
00115 
00116   // Make aliases to the current game's paths.
00117   string system_path_tag(gametitle);
00118   to_uppercase(system_path_tag);
00119   clone_system_path("<STATIC>", "<" + system_path_tag + "_STATIC>");
00120   clone_system_path("<GAMEDAT>", "<" + system_path_tag + "_GAMEDAT>");
00121   clone_system_path("<SAVEGAME>", "<" + system_path_tag + "_SAVEGAME>");
00122   if (is_system_path_defined("<" + system_path_tag + "_PATCH>"))
00123     clone_system_path("<PATCH>", "<" + system_path_tag + "_PATCH>");
00124   else
00125     clear_system_path("<PATCH>");
00126 
00127   U7mkdir("<SAVEGAME>", 0755); // make sure savegame directory exists
00128 
00129   // Discover the game we are running (BG, SI, ...)
00130   // We do this, because we don't really trust config :-)
00131   if (game_type != EXULT_DEVEL_GAME) {
00132     char *static_identity = Game_window::get_game_identity(
00133                 INITGAME);
00134 
00135     if (!strcmp(static_identity," ULTIMA7")) {
00136       game_type = BLACK_GATE;
00137       expansion = false;
00138     } else if (!strcmp(static_identity, "FORGE")) {
00139       game_type = BLACK_GATE;
00140       expansion = true;
00141     } else if (!strcmp(static_identity, "SERPENT ISLE")) {
00142       game_type = SERPENT_ISLE;
00143       expansion = false;
00144     } else if (!strcmp(static_identity, "SILVER SEED")) {
00145       game_type = SERPENT_ISLE;
00146       expansion = true;
00147     }
00148     delete[] static_identity;
00149   }
00150   switch(game_type) {
00151   case BLACK_GATE:
00152     cout << "Starting a BLACK GATE game" << endl;
00153     game = new BG_Game();
00154     break;
00155   case SERPENT_ISLE:
00156     cout << "Starting a SERPENT ISLE game" << endl;
00157     game = new SI_Game();
00158     break;
00159   case EXULT_DEVEL_GAME:
00160     cout << "Starting '" << gametitle << "' game" << endl;
00161     game = new DEV_Game();
00162     break;
00163   default:
00164     game = 0;
00165   }
00166 
00167   std::cout << "Game path settings:" << std::endl;
00168   std::cout << "Static  : " << get_system_path("<STATIC>") << std::endl;
00169   std::cout << "Gamedat : " << get_system_path("<GAMEDAT>") << std::endl;
00170   std::cout << "Savegame: " << get_system_path("<SAVEGAME>") << std::endl;
00171   if (is_system_path_defined("<PATCH>"))
00172     std::cout << "Patch   : " << get_system_path("<PATCH>") << std::endl;
00173   else
00174     std::cout << "Patch   : none" << std::endl;
00175   std::cout << std::endl;
00176 
00177   // This should probably go elsewhere
00178   Audio *audio = Audio::get_ptr();
00179 
00180   if (audio) {
00181     MyMidiPlayer *midi = audio->get_midi();
00182     if (midi) midi->load_patches();
00183   }
00184 
00185   return game;
00186 }
00187 
00188 
00189 void Game::play_flic(const char *archive, int index) 
00190 {
00191   char *fli_buf;
00192   size_t len;
00193   U7object flic(archive, index);
00194   fli_buf = flic.retrieve(len);
00195   playfli fli(fli_buf);
00196   fli.play(win);
00197   delete [] fli_buf;
00198 }
00199 
00200 void Game::play_audio(const char *archive, int index) 
00201 {
00202   U7object speech(archive, index);
00203   // FIXME: should use a DataBuffer
00204   speech.retrieve("speech.voc");
00205   Audio::get_ptr()->playfile("speech.voc", false);
00206 }
00207 
00208 void Game::play_midi(int track,bool repeat)
00209 {
00210   if (game_type == BLACK_GATE) Audio::get_ptr()->start_music(track,repeat,1);
00211   else if (game_type == SERPENT_ISLE) Audio::get_ptr()->start_music(track,repeat,2);
00212 }
00213 
00214 void Game::add_shape(const char *name, int shapenum) 
00215 {
00216   shapes[name] = shapenum;
00217 }
00218 
00219 int Game::get_shape(const char *name)
00220 {
00221   return shapes[name];
00222 }
00223 
00224 void Game::add_resource(const char *name, const char *str, int num) 
00225 {
00226   resources[name].str = str;
00227   resources[name].num = num;
00228 }
00229 
00230 str_int_pair Game::get_resource(const char *name)
00231 {
00232   return resources[name];
00233 }
00234 
00235 
00236 bool Game::show_menu(bool skip)
00237 {
00238   int menuy = topy+120;
00239           // Brand-new game in development?
00240   if (skip || (is_editing() && !U7exists(MAINSHP_FLX)))
00241     {
00242     bool first = !U7exists(IDENTITY);
00243     if (first)
00244       set_avname("Newbie");
00245     if (!gwin->init_gamedat(first))
00246       return false;
00247     return true;
00248     }
00249   ExultDataSource mouse_data(MAINSHP_FLX, 19);
00250   menu_mouse = new Mouse(gwin, mouse_data);
00251   
00252   top_menu();
00253   MenuList *menu = 0;
00254 
00255     
00256   int menuchoices[] = { 0x04, 0x05, 0x08, 0x06, 0x11, 0x12, 0x07 };
00257   int num_choices = sizeof(menuchoices)/sizeof(int);
00258   int *menuentries = new int[num_choices];
00259   
00260   Vga_file exult_flx("<DATA>/exult.flx");
00261   char npc_name[16];
00262   snprintf(npc_name, 16, "Exult");
00263   bool play = false;
00264   bool fadeout = true;
00265   bool exitmenu = false;
00266   
00267   do {
00268     int entries = 0;
00269     if(!menu) {
00270       entries = 0;
00271       menu = new MenuList();  
00272       int offset = 0;
00273       for(int i=0; i<num_choices; i++) {
00274         if((i!=4 && i!=5) || (i==4 && U7exists("<SAVEGAME>/quotes.flg")) || (i==5 && U7exists("<SAVEGAME>/endgame.flg"))) {
00275           menu->add_entry(new MenuEntry(menushapes.get_shape(menuchoices[i],1),
00276                   menushapes.get_shape(menuchoices[i],0),
00277                   centerx, menuy+offset));
00278           offset += menushapes.get_shape(menuchoices[i],1)->get_ybelow() + 3;
00279           menuentries[entries++]=i;
00280         }
00281       }
00282       menu->set_selection(2);
00283     }
00284   
00285     bool created = false;
00286     int choice = menu->handle_events(gwin, menu_mouse);
00287     switch(choice<0?choice:menuentries[choice]) {
00288     case -1: // Exit
00289       pal->fade_out(c_fade_out_time);
00290       Audio::get_ptr()->stop_music();
00291       throw quit_exception();
00292     case 0: // Intro
00293       pal->fade_out(c_fade_out_time);
00294       play_intro();
00295       gwin->clear_screen(true);
00296       top_menu();
00297       break;
00298     case 2: // Journey Onwards
00299       created = gwin->init_gamedat(false);
00300       if(!created) {
00301         show_journey_failed();
00302         top_menu();
00303         menu->set_selection(1);
00304         break;
00305       }
00306       exitmenu = true;
00307       fadeout = true;
00308       play = true;
00309       break;
00310     case 1: // New Game
00311       if(!created) {
00312         if(new_game(menushapes))
00313           exitmenu = true;
00314         else
00315           break;
00316       } else
00317         exitmenu = true;
00318       fadeout = false;
00319       play = true;
00320       break;
00321     case 3: // Credits
00322       pal->fade_out(c_fade_out_time);
00323       show_credits();
00324       delete menu;
00325       menu = 0;
00326       top_menu();
00327       break;
00328     case 4: // Quotes
00329       pal->fade_out(c_fade_out_time);
00330       show_quotes();
00331       top_menu();
00332       break;
00333     case 5: // End Game
00334       pal->fade_out(c_fade_out_time);
00335       end_game(true);
00336       top_menu();
00337       break;
00338     case 6: // Return to Menu
00339       play = false;
00340       exitmenu = true;
00341       fadeout = true;
00342       break;
00343     default:
00344       break;
00345     }
00346   } while(!exitmenu);
00347 
00348   if (fadeout) {
00349     pal->fade_out(c_fade_out_time);
00350     gwin->clear_screen(true);
00351   }
00352   delete menu;
00353   delete[] menuentries;
00354   Audio::get_ptr()->stop_music();
00355   delete menu_mouse;
00356   return play;
00357 }
00358   
00359 void Game::journey_failed_text()
00360 {
00361   Font *font = fontManager.get_font("MENU_FONT");
00362   font->center_text(ibuf, centerx, centery+30,  "You must start a new game first.");
00363   pal->fade_in(50);
00364   while (!wait_delay(10))
00365     ;
00366   pal->fade_out(50);
00367 }
00368   
00369 const char *Game::get_avname ()
00370 {
00371   if (av_name[0])
00372     return av_name;
00373   else
00374     return NULL;
00375 }
00376 
00377 int Game::get_avsex ()
00378 {
00379   return av_sex;
00380 }
00381 int Game::get_avskin ()
00382 {
00383   return av_skin;
00384 }
00385 
00386 // Assume safe
00387 void Game::set_avname (char *name)
00388 {
00389   strcpy (av_name, name);
00390 }
00391 
00392 void Game::set_avsex (int sex)
00393 {
00394   av_sex = sex;
00395 }
00396 
00397 void Game::set_avskin (int skin)
00398 {
00399   av_skin = skin;
00400 }
00401 
00402 void Game::clear_avname ()
00403 {
00404   av_name[0] = 0;
00405   new_game_flag = false;
00406 }
00407 
00408 void Game::clear_avsex ()
00409 {
00410   av_sex = -1;
00411 }
00412 
00413 void Game::clear_avskin ()
00414 {
00415   av_skin = -1;
00416 }
00417 
00418 
00419 // wait ms milliseconds, while cycling colours startcol to startcol+ncol-1
00420 // return 0 if time passed completly, 1 if user pressed any key or mouse button,
00421 // and 2 if user pressed Return/Enter
00422 int wait_delay(int ms, int startcol, int ncol)
00423 {
00424   SDL_Event event;
00425   int delay;
00426   int loops;
00427   bool mouse_down = false;
00428 
00429   int loopinterval = (ncol == 0) ? 50 : 10;
00430   if (!ms) ms = 1;
00431   if(ms <= 2*loopinterval) {
00432     delay = ms;
00433     loops = 1;
00434   } else {
00435     delay = loopinterval;
00436     loops = ms/delay;
00437   }
00438 
00439   for(int i=0; i<loops; i++) {
00440     unsigned long ticks1 = SDL_GetTicks();
00441           // this may be a bit risky... How fast can events be generated?
00442     while(SDL_PollEvent(&event)) {
00443       switch (event.type) {
00444       case SDL_KEYDOWN:
00445         switch (event.key.keysym.sym) {
00446         case SDLK_RSHIFT: case SDLK_LSHIFT:
00447         case SDLK_RCTRL: case SDLK_LCTRL:
00448         case SDLK_RALT: case SDLK_LALT:
00449         case SDLK_RMETA: case SDLK_LMETA:
00450         case SDLK_RSUPER: case SDLK_LSUPER:
00451         case SDLK_NUMLOCK: case SDLK_CAPSLOCK:
00452         case SDLK_SCROLLOCK:
00453           break;
00454         case SDLK_s:
00455           if ((event.key.keysym.mod&KMOD_ALT) &&
00456               (event.key.keysym.mod&KMOD_CTRL))
00457             make_screenshot(true);
00458           break;
00459         case SDLK_RETURN:
00460         case SDLK_KP_ENTER:
00461           return 2;
00462           break;
00463         default:
00464           return 1;
00465         }
00466         break;
00467       case SDL_MOUSEBUTTONDOWN:
00468         mouse_down = true;
00469         break;
00470       case SDL_MOUSEBUTTONUP:
00471         //if (mouse_down)
00472           return 1;
00473         break;
00474       default:
00475         break;
00476       }
00477     }
00478     if (ncol > 0) {
00479       Game_window::get_instance()->get_win()
00480         ->rotate_colors(startcol, ncol, 1);
00481       if (ms > 250)
00482         Game_window::get_instance()->get_win()->show();
00483     }
00484     unsigned long ticks2 = SDL_GetTicks();
00485     if (ticks2 - ticks1 > delay)
00486       i+= (ticks2 - ticks1) / delay - 1;
00487     else
00488       SDL_Delay(delay - (ticks2 - ticks1));
00489   }
00490   
00491   return 0;
00492 }

Generated on Mon Jul 9 14:42:45 2007 for ExultEngine by  doxygen 1.5.1