Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

src/crogue.c

Go to the documentation of this file.
00001 /*
00002  * CalcRogue, a roguelike game for PCs, calculators and PDAs
00003  * Copyright (C) 2003 Jim Babcock
00004  * 
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018  */
00019 // crogue.c
00024 
00075 
00076 
00077 #include "crogue.h"
00078 #include "substdio.h"
00079 #include "export.h"
00080 
00081 #ifdef REGISTERVAR
00082 world *w_non_reg; // A place to back up 'w', because it won't survive in a
00083                   // register variable if an exception is thrown
00084 #else
00085 world *w;
00086 #endif
00087 
00088 static void cb_main_menu_choice(int n, char *buf);
00089 static void main_menu(void);
00090 
00091 //{{{
00092 void initialize(void)
00093 {
00094     int loadedfromfile = 0;
00095     
00096     sys_init();
00097     
00098     // Claim memory for main data struct
00099 #ifdef REGISTERVAR
00100     w_non_reg = NULL; // In case call fails, so cleanup will know
00101 #endif
00102     w = (world*)debug_calloc(1, sizeof(world));
00103 #ifdef REGISTERVAR
00104     w_non_reg = w;
00105 #endif
00106     
00107     lsrand(get_entropy());
00108     
00109     // Load saved game if possible
00110     loadedfromfile = restore_game();
00111     
00112     
00113     // If not loaded from saved game, initialize things
00114     if(!loadedfromfile) {
00115         sys_init_data_file();
00116         init_options();
00117         load_options();
00118 #       ifdef IS_CALCULATOR
00119         if(w->options[OPTION_GRAYSCALE] == OPTION_GRAY_ON)
00120             GrayOnThrow();
00121 #       endif
00122         display_title_screen();
00123         
00124         init_shuffle_tab();
00125         
00126         w->messagevis=0;
00127         w->time=0;
00128 #ifdef ALLOWDEBUG
00129         w->debug_mode = 0;
00130 #endif
00131         
00132         init_spells();
00133         init_discoveries();
00134     }
00135     else
00136     {
00137         UI_TF_Init( COORD(MAPSIZE_X,MAPSIZE_Y) );
00138 #ifdef IS_CALCULATOR
00139         if(w->options[OPTION_GRAYSCALE] == OPTION_GRAY_ON)
00140             GrayOnThrow();
00141 #endif
00142     }
00143     
00144     init_layout();
00145     
00146     if(!loadedfromfile)
00147         main_menu();
00148     
00149     UI_MF_clear();
00150     enter_map();
00151 }
00152 //}}}
00153 //{{{
00154 void resize_map_store(int size_x, int size_y)
00155 {
00156     tile *alloc_pos;
00157     int i;
00158     
00159     if(w->t && w->mapsize_x == size_x && w->mapsize_y == size_y)
00160         return;
00161     
00162     if(w->t) debug_free(w->t);
00163     w->mapsize_x = size_x;
00164     w->mapsize_y = size_y;
00165     w->t = debug_malloc( size_y*sizeof(tile*)
00166             + size_x*size_y*sizeof(tile) );
00167     alloc_pos = (tile*)((tile**)w->t + size_y);
00168     for(i=0; i<size_y; i++) {
00169         w->t[i] = alloc_pos;
00170         alloc_pos += size_x;
00171     }
00172     
00173     UI_TF_Init( COORD(size_x, size_y) );
00174 }
00175 //}}}
00176 
00177 //{{{
00178 static const char *main_menu_choices[] = {
00179     gettext("New game"),
00180     gettext("Help"),
00181     gettext("Tutorial"),
00182     gettext("High scores"),
00183     gettext("Options"),
00184     gettext("Quit")
00185     };
00186 static const int num_main_menu_choices = 6;
00187 //}}}
00188 //{{{
00189 static void cb_main_menu_choice(int n, char *buf)
00190 {
00191     strcpy(buf, main_menu_choices[n]);
00192 }
00193 //}}}
00194 //{{{
00195 static void main_menu(void)
00196 {
00197     int choice;
00198     
00199 restart:
00200     // Generic title screen method (overlay a menu on a background image, as on calc)
00201     display_title_screen();
00202     
00203     do {
00204         choice = UI_Menu_Pick( main_menu_rect, num_main_menu_choices, &cb_main_menu_choice, 0);
00205     } while(choice == -1);
00206     
00207     switch(choice)
00208     {
00209         case 0: // New game
00210             init_player(0);
00211             w->current_map_link = w->desc.mainmap;
00212             w->current_map = (mapdesc*)deref_file_ptr(w->current_map_link);
00213             w->maxlevel = w->level = w->current_map->mapindex;
00214             gen_map(0, COORD(0,0));
00215             break;
00216         case 1: // Help
00217             help();
00218             goto restart;
00219         case 2: // Tutorial
00220             init_player(1);
00221             w->current_map_link = w->desc.tutorialmap;
00222             w->current_map = (mapdesc*)deref_file_ptr(w->current_map_link);
00223             w->maxlevel = w->level = w->current_map->mapindex;
00224             gen_map(0, COORD(0,0));
00225             break;
00226         case 3: // High scores
00227             display_scores(-1);
00228             goto restart;
00229         case 4: // Options
00230             options_menu();
00231             goto restart;
00232         case 5: // Quit
00233             quit();
00234     }
00235 }
00236 //}}}
00237 
00238 //{{{
00239 void eventloop(void)
00240 {
00241     while(1)
00242     {
00243         plr_move();
00244         draw();
00245     }
00246 }
00247 //}}}
00248 
00249 //{{{
00250 void die(const char *cause_of_death)
00251 {
00252     message(gettext("You die..."));
00253     draw();
00254     while(read_char() != KEY_ACKNOWLEDGE);
00255     
00256     end_game(cause_of_death);
00257 }
00258 //}}}
00259 //{{{
00260 void end_game(const char *cause_of_death)
00261 {
00262     award_item_points();
00263     
00264 #ifdef ALLOWDEBUG
00265     if(w->debug_mode)
00266     {
00267         message( gettext(
00268             "Since you used debug features, your game will not be scored."));
00269         read_char();
00270     } else
00271 #endif
00272     {
00273         award_high_score(w->plr.score, cause_of_death);
00274         display_scores(w->plr.score);
00275     }
00276     
00277     cleanup_save();
00278     quit();
00279 }
00280 //}}}
00281 
00282 //{{{
00283 void quit(void)
00284 {
00285 #ifdef IS_CALCULATOR
00286     ER_success();
00287 #endif
00288     cleanup();
00289     exit(0);
00290 }
00291 //}}}
00292 //{{{
00293 void cleanup(void)
00294 {
00295     sys_cleanup();
00296     
00297     if(w) {
00298         if(w->t)                  debug_free(w->t);
00299         if(w->plr.spellknowledge) debug_free(w->plr.spellknowledge);
00300         if(w->shuffletranslation) debug_free(w->shuffletranslation);
00301         if(w->itemids)            debug_free(w->itemids);
00302         cleanup_items();
00303         debug_free(w);
00304     }
00305     UI_TF_Deinit();
00306     
00307     exit(0);
00308 }
00309 //}}}
00310 //{{{
00311 void timepass(ushort amt)
00312 {
00313     uint partialhpsperhp;
00314     uint partialppsperpp;
00315     uint i;
00316     
00317     
00318     // Apply draining
00319     if(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_DRAIN)
00320     {
00321         if(w->plr.pps > 0)
00322         {
00323             message(gettext("You feel the Amulet sucking your energy away."));
00324             w->plr.pps--;
00325         }
00326         else
00327         {
00328             message(gettext("You feel the Amulet sucking your life away."));
00329             plr_takedamage(1, gettext("Killed by the Amulet of Yendor"));
00330         }
00331     } else {
00332         // Regenerate hit points
00333         partialhpsperhp = 150+10*w->plr.level;
00334         w->plr.partialhps += (w->plr.hps_max+10) * amt;
00335         w->plr.hps += w->plr.partialhps / partialhpsperhp;
00336         w->plr.hps += w->plr.extrinsic[STAT_REGEN];
00337         w->plr.partialhps -= (w->plr.partialhps/partialhpsperhp)*partialhpsperhp;
00338         if( w->plr.hps > w->plr.hps_max )
00339             w->plr.hps = w->plr.hps_max;
00340         
00341         // Regenerate power points
00342         partialppsperpp = 155+10*w->plr.level;
00343         w->plr.partialpps += (w->plr.pps_max+w->plr.extrinsic[STAT_MANA]) * amt;
00344         w->plr.pps += w->plr.partialpps / partialppsperpp;
00345         w->plr.partialpps -= (w->plr.partialpps/partialppsperpp)*partialppsperpp;
00346         if( w->plr.pps > w->plr.pps_max )
00347             w->plr.pps = w->plr.pps_max;
00348     }
00349     
00350     // Drain torch fuel
00351     if(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_TIMER)
00352     {
00353         for(i=0; i<PLRINVSIZE; i++)
00354         {
00355             if(ITEMDESC(INVENTORY(i)).flags)
00356             {
00357                 if(get_item_property(&INVENTORY(i), PROPERTY_BURN))
00358                 {
00359                     call_usefunc(get_item_property(&INVENTORY(i),
00360                         PROPERTY_BURN)->function, i );
00361                 }
00362             }
00363 /*          if(ITEMDESC(INVENTORY(i)).flags & ITEMFLAG_FUELED && INVENTORY(i).flags & ITEMFLAG_EQUIPPED)
00364             {
00365                 INVENTORY(i).stacksize--;
00366                 if(INVENTORY(i).stacksize == 0)
00367                 {
00368                     message(gettext("Your %s burns out."), shortitemname(&INVENTORY(i)));
00369                     INVENTORY(i).type = 0;
00370                     update_player();
00371                 }
00372             }*/
00373         }
00374     }
00375     
00376     if(remove_expired_timers())
00377         update_player();
00378     
00379     w->plr.satiation -= w->plr.extrinsic[STAT_DIGESTION] * amt;
00380     if(w->plr.satiation <= -600) {
00381         message(gettext("You are starving!"));
00382         plr_takedamage(w->plr.satiation/-600, gettext("Starved to death."));    // FIXME: PV shouldn't affect this
00383                                                 // FIXME: should scale with number of turns spend
00384     }
00385     
00386     // Run monster AI
00387     for(i=0; i<MONSTERS_MAX; i++)
00388     {
00389         if(!isNull(w->m[i].type))
00390         {
00391             w->m[i].energy += MDESC(i)->speed * amt;
00392             
00393             while(w->m[i].energy >= w->plr.extrinsic[STAT_SPEED] && !isNull(w->m[i].type))
00394             {
00395                 monstmove(i);
00396                 w->m[i].energy -= w->plr.extrinsic[STAT_SPEED];
00397             }
00398         }
00399     }
00400     
00401     // Add monsters randomly with time
00402     // (1 in 70 chance per turn)
00403     for(i=0; i<amt; i++)
00404         if( !(MAPDESC_CURRENT.flags & MAPFLAG_NORANDMONST) && lrand()%70 == 0 )
00405         {
00406 #ifdef DEBUG_BALANCE
00407             if(w->debug_mode)
00408                 message(gettext("Added random monster."));
00409 #endif
00410             addrandommonst();
00411         }
00412     
00413     // Clear player force-facing
00414     w->plr.facing_forced = -1;
00415     if(w->plr.velocity > 0) w->plr.velocity --;
00416     
00417     w->time++;
00418 }
00419 //}}}
00420 
00421 

Generated on Thu May 20 13:12:09 2004 for CalcRogue by doxygen 1.3.6