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

src/player.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 // player.c
00022 
00023 #include "crogue.h"
00024 #include "export.h"
00025 
00026 static void distribute_attributes(void);
00027 
00028 static sint mod_from_attribute(uint attr, sint mindistance, sint divisor);
00029 
00030 void follow_connection(void);
00031 static void plr_walk(sshort x, sshort y);
00032 static void plr_run(sshort x, sshort y);
00033 void plr_moveto(ushort x, ushort y, sshort displace_monst);
00034 static void plr_attack( int monstid );
00035 void char_info(void);
00036 void plr_search(void);
00037 static void manip_door(int open);
00038 
00039 //{{{
00041 int plr_attack_monster_roll(int monstid, int modifier)
00042 {
00043     return calculate_hit(w->plr.level*2 + modifier, MDESC(monstid)->dv);
00044 }
00045 //}}}
00046 
00047 //{{{
00052 static void playerclassname(int n, char *buf)
00053 {
00054     strcpy( buf, (char*)deref_file_ptr(w->playerclasses[n].name) );
00055 }
00056 //}}}
00057 //{{{
00067 static sint mod_from_attribute(uint attr, sint mindistance, sint divisor)
00068 {
00069     sint v = w->plr.extrinsic[attr];
00070     
00071     v -= 10;
00072     
00073     if(v>0)
00074     {
00075         v -= mindistance;
00076         if(v<0)
00077             v=0;
00078     }
00079     if(v<0)
00080     {
00081         v += mindistance;
00082         if(v>0)
00083             v=0;
00084     }
00085     
00086     v /= divisor;
00087     
00088     return v;
00089 }
00090 //}}}
00091 //{{{
00093 void init_player(uint is_tutorial)
00094 {
00095     const struct classdesc *plr_class;
00096     int i;
00097     
00098     if(is_tutorial)
00099     {
00100         w->plr.class = w->desc.tutorialclass;
00101     } else {
00102         display_title_screen();
00103         // Pick player class
00104         do {
00105 #ifdef USE_CURSES
00106             w->plr.class = UI_Menu_Pick( class_menu_rect, w->desc.numplayerclasses, &playerclassname, 0 );
00107 #else
00108             w->plr.class = UI_Menu_Pick( class_menu_rect, w->desc.numplayerclasses, &playerclassname, 0 );
00109 #endif
00110         } while(w->plr.class==-1);
00111         
00112     }
00113     plr_class = &w->playerclasses[w->plr.class];
00114     
00115     init_inventory();
00116     
00117     // Set up statistics and timers
00118     for(i=0; i<NUM_STATS; i++)
00119         w->plr.intrinsic[i] = 0;
00120     
00121     distribute_attributes();
00122     init_timers();
00123     
00124     w->plr.intrinsic[STAT_LIGHTRADIUS] = 1;
00125     w->plr.extrinsic[STAT_LIGHTRADIUS] = -1;
00126     w->plr.intrinsic[STAT_SPEED] = 10;
00127     w->plr.intrinsic[STAT_DIGESTION] = 12;
00128     
00129     w->plr.hps = w->plr.hps_max = w->plr.intrinsic[STAT_TOUGHNESS] +
00130                                   w->plr.intrinsic[STAT_WILLPOWER]/3;
00131     w->plr.hps_max_mod = 0;
00132     w->plr.pps_max_mod = 0;
00133     w->plr.pps = w->plr.pps_max = w->plr.intrinsic[STAT_MANA];
00134     w->plr.partialhps = w->plr.partialpps = 0;
00135     w->plr.level = 1;
00136     w->plr.xp = 0;
00137     w->plr.satiation = 12000l;
00138     w->plr.debt = 0;
00139     w->plr.facing = w->plr.facing_forced = -1;
00140     w->plr.velocity = 0;
00141     
00142     w->plr.score = 0;
00143     
00144     update_player();
00145     init_skills();
00146     update_player();
00147 }
00148 //}}}
00149 //{{{
00160 static void distribute_attributes(void)
00161 {
00162     int i, stat, points_remaining, points_chunk;
00163     
00164     for(i=0; i<NUM_BASE_STATS; i++)
00165         w->plr.intrinsic[i] = w->playerclasses[w->plr.class].base_stat[i];
00166     
00167     points_remaining = w->playerclasses[w->plr.class].free_points;
00168     while(points_remaining>0)
00169     {
00170         do
00171         {
00172             stat = RANGE(NUM_BASE_STATS-1, 0);
00173         } while(w->playerclasses[w->plr.class].max_stat[stat] <= w->plr.intrinsic[stat]);
00174         
00175         if(points_remaining>5)
00176             points_chunk = 3;
00177         else
00178             points_chunk = 1;
00179         w->plr.intrinsic[stat] += points_chunk;
00180         points_remaining -= points_chunk;
00181     }
00182     for(i=0; i<NUM_BASE_STATS; i++)
00183         w->plr.maximum[i] = w->plr.intrinsic[i];
00184 }
00185 //}}}
00186 //{{{
00187 void apply_stat_mod_desc(sint *target, const stat_mod_desc *s, schar plus)
00188 {
00189     if(!target)
00190         target = &w->plr.extrinsic[s->stat];
00191     
00192     switch(s->type)
00193     {
00194         case STATMOD_ADD:
00195             *target += s->amount;
00196             break;
00197         case STATMOD_ADDPLUS:
00198             *target += s->amount + plus;
00199             break;
00200         case STATMOD_OR:
00201             *target |= s->amount;
00202             break;
00203         case STATMOD_SET:
00204             *target = s->amount;
00205             break;
00206     }
00207 
00208 }
00209 //}}}
00210 //{{{
00212 void update_player(void)
00213 {
00214     int i;
00215     int old_lightradius = w->plr.extrinsic[STAT_LIGHTRADIUS];
00216     item* item;
00217     
00218     for(i=0; i<NUM_STATS; i++)
00219         w->plr.extrinsic[i] = w->plr.intrinsic[i];
00220     
00221     for(i=0; i<PLRINVSIZE; i++)
00222     {
00223         item = &INVENTORY(i);
00224         if(!item->type) continue;
00225         if(!(item->flags & ITEMFLAG_EQUIPPED)) continue;
00226         
00227         apply_all_item_properties(item, PROPERTY_WORN_STAT_EFFECT);
00228     }
00229     apply_timers();
00230     for(i=0; i<PLRINVSIZE; i++)
00231     {
00232         item = &INVENTORY(i);
00233         if(!item->type) continue;
00234         apply_all_item_properties(item, PROPERTY_CARRIED_EFFECT);
00235     }
00236     
00237     w->plr.extrinsic[STAT_DV]         += mod_from_attribute(STAT_DEXTERITY, 0, 2);
00238     w->plr.extrinsic[STAT_PV]         += mod_from_attribute(STAT_TOUGHNESS, 3, 6);
00239     w->plr.extrinsic[STAT_SPEED]      += mod_from_attribute(STAT_DEXTERITY, 3, 3);
00240     w->plr.extrinsic[STAT_TOHIT]      += w->plr.extrinsic[STAT_STRENGTH]/4;
00241     w->plr.extrinsic[STAT_TOHIT]      += weapon_skill_attack();
00242     w->plr.extrinsic[STAT_MISSILE_TOHIT] += mod_from_attribute(STAT_DEXTERITY, 2, 2);
00243     w->plr.extrinsic[STAT_DAMAGE_MAX] += w->plr.extrinsic[STAT_STRENGTH]/4
00244                                       + mod_from_attribute(STAT_STRENGTH, 5, 3);
00245     w->plr.extrinsic[STAT_DAMAGE_MAX] += weapon_skill_damage();
00246     w->plr.extrinsic[STAT_MISSILEDAM_MAX] += w->plr.extrinsic[STAT_DEXTERITY]/4;
00247     w->plr.extrinsic[STAT_DAMAGE_MIN] += weapon_skill_damage()
00248                                       + mod_from_attribute(STAT_STRENGTH, 5, 4);
00249     
00250     if(w->plr.extrinsic[STAT_LIGHTRADIUS] > 0) {
00251                                    // Ordinarily this would never be <= zero,
00252                                    // but grues can make things *really* dark
00253         w->plr.extrinsic[STAT_LIGHTRADIUS]*=w->plr.extrinsic[STAT_LIGHTRADIUS];
00254         w->plr.extrinsic[STAT_LIGHTRADIUS]++;
00255     } else
00256         w->plr.extrinsic[STAT_LIGHTRADIUS] = 0;
00257     
00258     w->plr.hps_max = w->plr.extrinsic[STAT_TOUGHNESS]
00259                      + w->plr.extrinsic[STAT_WILLPOWER] / 3
00260                      + max(1, (4 + mod_from_attribute(STAT_TOUGHNESS, 0, 2))) * (w->plr.level - 1)
00261                      + max(0, (2 + mod_from_attribute(STAT_WILLPOWER, 0, 3))) * (w->plr.level - 1)
00262                      + w->plr.hps_max_mod;
00263     w->plr.pps_max = w->plr.extrinsic[STAT_MANA]
00264                      + max(0, (3 + mod_from_attribute(STAT_MANA, 0, 2))) * (w->plr.level - 1)
00265                      + max(0, mod_from_attribute(STAT_WILLPOWER, 0, 3)) * (w->plr.level - 1)
00266                      + w->plr.pps_max_mod;
00267     if(w->plr.pps_max < 0) w->plr.pps_max = 0;
00268     if(w->plr.hps_max < 1) w->plr.hps_max = 1;
00269     
00270     if(w->plr.extrinsic[STAT_LIGHTRADIUS] != old_lightradius
00271        && old_lightradius != -1)
00272         calc_light();
00273 }
00274 //}}}
00275 //{{{
00277 void enter_map(void)
00278 {
00279     w->interrupt = 1;
00280     UI_TF_PlaceCamera(w->plr.x, w->plr.y);
00281     calc_light();
00282     call_genericfunc(MAPDESC_CURRENT.enterfunction);
00283     full_redraw();
00284 }
00285 //}}}
00286 //{{{
00288 void follow_connection(void)
00289 {
00290     const spec_descriptor *connection;
00291     tile *t = &w->t[w->plr.y][w->plr.x];
00292     int source_level;
00293     filelink target_level_link;
00294     const mapdesc *target_level;
00295     
00296     if( TILEDESC(*t).is_connection==0 ) {
00297         message(gettext("You can't go up or down from here."));
00298         return;
00299     }
00300     
00301     connection = &MAPSPEC(t->special);
00302     target_level_link = connection->ext.lvl.destmap;
00303     target_level = deref_file_ptr(connection->ext.lvl.destmap);
00304     
00305     if( target_level->flags & MAPFLAG_OUTSIDE )
00306     {
00307         if(prompt(gettext("Leave the dungeon?")))
00308             end_game(gettext("Left the dungeon"));
00309         else
00310             return;
00311     }
00312     
00313     gather_wandering_monsters();
00314     w->t[w->plr.y][w->plr.x].flags &= ~TFLAG_OCCUPIED;
00315     
00316     save_level();
00317     
00318     source_level = w->level;
00319     w->maxlevel = max(w->maxlevel, w->level);
00320     w->current_map_link = target_level_link;
00321     w->current_map = target_level;
00322     w->level = target_level->mapindex;
00323     if( !load_level(source_level, connection->ext.lvl.destcoord) )
00324     {
00325         gen_map(source_level, connection->ext.lvl.destcoord );
00326     }
00327     
00328     enter_map();
00329     
00330     if( !(target_level->flags & MAPFLAG_NOMONST) ) {
00331         place_wandering_monsters();
00332     }
00333     timepass(1);
00334 }
00335 //}}}
00336 //{{{
00338 void plr_move(void)
00339 {
00340     int move;
00341     
00342     if(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_PARALYZED)
00343     {
00344         timepass(1);
00345         return;
00346     }
00347     
00348     move = read_char();
00349     
00350     if(move==KEY_ACT_MENU)
00351         move = actions_menu();
00352     
00353     switch(move) {
00354         
00355         case KEY_NOP:
00356             break;
00357         
00359         
00360         case KEY_SOUTHWEST:     plr_walk(-1,  1);  break;
00361         case KEY_SOUTH:         plr_walk( 0,  1);  break;
00362         case KEY_SOUTHEAST:     plr_walk( 1,  1);  break;
00363         case KEY_WEST:          plr_walk(-1,  0);  break;
00364         case KEY_EAST:          plr_walk( 1,  0);  break;
00365         case KEY_NORTHWEST:     plr_walk(-1, -1);  break;
00366         case KEY_NORTH:         plr_walk( 0, -1);  break;
00367         case KEY_NORTHEAST:     plr_walk( 1, -1);  break;
00368         
00369         case KEY_RUN_SOUTHWEST: plr_run( -1,  1);  break;
00370         case KEY_RUN_SOUTH:     plr_run(  0,  1);  break;
00371         case KEY_RUN_SOUTHEAST: plr_run(  1,  1);  break;
00372         case KEY_RUN_WEST:      plr_run( -1,  0);  break;
00373         case KEY_RUN_EAST:      plr_run(  1,  0);  break;
00374         case KEY_RUN_NORTHWEST: plr_run( -1, -1);  break;
00375         case KEY_RUN_NORTH:     plr_run(  0, -1);  break;
00376         case KEY_RUN_NORTHEAST: plr_run(  1, -1);  break;
00377         
00378         case KEY_WAIT:
00379             timepass(1);
00380             break;
00381         
00382         case KEY_STAIR: // Use stair
00383             follow_connection();
00384             break;
00385         
00387 
00388         case KEY_INVENTORY: // Show inventory
00389             if(!count_inventory())
00390                 message(gettext("You are empty-handed."));
00391             else
00392                 pick_item(filter_none);
00393             break;
00394         
00395         case KEY_WEAR:  // Wear an item
00396             wear_item();
00397             break;
00398         
00399         case KEY_WEAR_MULTIPLE:
00400             wear_multiple();
00401             break;
00402             
00403         case KEY_TAKEOFF:   // Take off
00404             takeoff_item();
00405             break;
00406             
00407         case KEY_TAKEOFF_MULTIPLE:
00408             takeoff_multiple();
00409             break;
00410             
00411         case KEY_DROP:  // Drop an item
00412             drop_item();
00413             break;
00414         
00415         case KEY_DROP_MULTIPLE:
00416             drop_multiple();
00417             break;
00418                 
00419         case KEY_PICKUP:    // Pick up an item
00420             // Prompt if more than 1 item
00421             pickup(count_items(w->plr.x, w->plr.y) > 1);
00422             break;
00423         
00424         case KEY_CAST:
00425             cast_spell();
00426             break;
00427             
00428         case KEY_USE:   // Use an item
00429             use_item();
00430             break;
00431         
00432         case KEY_THROW:
00433             throw_item_from_menu();
00434             break;
00435             
00436         case KEY_FIRE:
00437             throw_readied_item();
00438             break;
00439         
00440         case KEY_HOTKEY_ITEM:
00441             hotkey_item();
00442             break;
00443         
00445         
00446         case KEY_MESSAGE_HISTORY:
00447             UI_MF_history();
00448             break;
00449             
00450         case KEY_DISCOVERIES:
00451             list_discoveries();
00452             break;
00453         
00454         case KEY_SEARCH:    // Search
00455             plr_search();
00456             break;
00457         
00458         case KEY_ESC:   // ESC - quit
00459             if( prompt(gettext("Really quit?")) )
00460             {
00461                 if(prompt(gettext("Save this game?")))
00462                 {
00463                     save_game();
00464                     quit();
00465                 }
00466                 else
00467                 {
00468                     end_game(gettext("Quit"));
00469                 }
00470             }
00471             break;
00472         
00473         case KEY_SAVEGAME:  // On
00474             #ifdef IS_CALCULATOR // Fast boss-button response
00475             GrayOff();
00476             LCD_restore(saved_screen);
00477             #endif
00478             save_game();
00479             quit();
00480             break;
00481         
00482         case KEY_HELPMENU:
00483             help();
00484             full_redraw();
00485             break;
00486         case KEY_STATS:
00487             char_info();
00488             break;
00489         case KEY_ABOUT:
00490             message(gettext("CalcRogue by Jim Babcock, 2002. This program is postcardware. If you enjoy it, send the author a postcard at 16 Sweeney Ridge Rd, Bedford, MA, USA, ZIP code 01730"));
00491             break;
00492         
00493         case KEY_CLOSEDOOR: // Close door
00494             manip_door(0);
00495             break;
00496         case KEY_OPENDOOR:  // Open door
00497             manip_door(1);
00498             break;
00499         
00500 #       ifdef KEY_SCROLLING
00501             case KEY_SCROLL_RIGHT:
00502                 UI_TF_Scroll(8, 0);
00503                 break;
00504             case KEY_SCROLL_DOWN:
00505                 UI_TF_Scroll(0, 8);
00506                 break;
00507             case KEY_SCROLL_UP:
00508                 UI_TF_Scroll(0, -8);
00509                 break;
00510             case KEY_SCROLL_LEFT:
00511                 UI_TF_Scroll(-8, 0);
00512                 break;
00513 #       endif
00514         
00515         case KEY_REDRAW:
00516             Graph_ClrScr();
00517             draw_all_tiles();
00518             full_redraw();
00519             break;
00520         
00521         case KEY_OPTIONS_MENU:
00522             options_menu();
00523             init_layout();
00524             UI_TF_MoveCamera(w->plr.x, w->plr.y);
00525             Graph_ClrScr();
00526             full_redraw();
00527             break;
00528             
00530         
00531         case KEY_KICK:  // Kick
00532             break;
00533         
00535         #ifdef ALLOWDEBUG
00536             case KEY_DEBUG:
00537                 debug();
00538                 break;
00539         #endif
00540     
00541         default:   // Message the keycode of any unrecognized key pressed
00542             #ifndef USE_CURSES // ... but not in curses, since some versions send 
00543                                // keystrokes for meta-keys and such
00544                 #ifdef ALLOWDEBUG
00545                     if(w->debug_mode)
00546                         message(gettext("Unrecognized key code: %i"), move);
00547                     else
00548                         message(gettext("Invalid command."));
00549                 #else
00550                     message(gettext("Invalid command."));
00551                 #endif
00552             #endif
00553             break;
00554     }
00555     return;
00556 }
00557 //}}}
00558 //{{{
00560 void place_player_randomly(void)
00561 {
00562     int x, y;
00563     
00564     do
00565     {
00566         x = RANGE(MAPSIZE_X-1, 0);
00567         y = RANGE(MAPSIZE_Y-1, 0);
00568     } while( !(w->tiledescs[w->t[y][x].type].passable) ||
00569              w->t[y][x].flags & TFLAG_OCCUPIED );
00570     
00571     plr_moveto(x, y, -1);
00572 }
00573 //}}}
00574 //{{{
00576 static void plr_walk(sshort x, sshort y)
00577 {
00578     int d;
00579     int velmod = 0;
00580     if( w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_ENTANGLED ) {
00581         message(gettext("You are stuck in the webs!"));
00582         timepass(1);
00583         return;
00584     }
00585     if( w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_CONFUSED ) {
00586         message(gettext("You are confused."));
00587         d = RANGE(7,0);
00588         x = dir[d][0];
00589         y = dir[d][1];
00590     }
00591     if( w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_SLIPPERY )
00592     {
00593         if( 2*delta_facing(player_facing(), facing(x, y))
00594              *delta_facing(player_facing(), facing(x, y))
00595              *(w->plr.velocity+1)
00596             + RANGE(8,0)
00597             > 3*w->plr.extrinsic[STAT_DEXTERITY] )
00598         {
00599             message(gettext("You slip and fall!"));
00600             w->plr.velocity = 0;
00601             w->plr.facing = facing(x, y);
00602             timepass(1);
00603             return;
00604         }
00605     }
00606     if(w->plr.facing == facing(x,y))
00607         velmod = 1;
00608     else if(delta_facing(player_facing(), facing(x,y)) > 2)
00609         w->plr.velocity = 0;
00610     w->plr.facing = facing(x, y);
00611     
00612     x += w->plr.x;
00613     y += w->plr.y;
00614     
00615     if( w->t[y][x].flags & TFLAG_OCCUPIED && (w->plr.x != x || w->plr.y != y) )
00616     {
00617         int target = monstbytile(x, y);
00618         if(monst_is_pet(target))
00619         {
00620             if(TILEDESC(w->t[y][x]).passable)
00621             {
00622                 plr_moveto(x, y, target);
00623                 timepass(1);
00624             }
00625             return;
00626         }
00627         else if(monst_is_peaceful(target)
00628                 && !(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_CONFUSED)) {
00629             if(!prompt( retprintf(gettext("Really attack the %s?"), monstname(target)) ))
00630                 return;
00631         }
00632         plr_attack( monstbytile(x, y) );
00633         timepass(1);
00634         return;
00635     }
00636     
00637     if( TILEDESC(w->t[y][x]).passable )
00638         plr_moveto(x, y, -1);
00639     else if( !isNull(TILEDESC(w->t[y][x]).step_function) )
00640         call_stepfunc( TILEDESC(w->t[y][x]).step_function, x, y);
00641     else if(w->t[y][x].type==TILE_CDOOR) {
00642         w->interrupt = 1;
00643         w->t[y][x].type = TILE_ODOOR;
00644         draw_tile(x, y);
00645         calc_light();
00646     } else {
00647         w->interrupt = 1;
00648         if(!(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_CONFUSED))
00649             return;
00650     }
00651     
00652     w->plr.velocity += velmod + 1;
00653     timepass(1);
00654 }
00655 //}}}
00656 //{{{
00663 static void plr_run(sshort x, sshort y)
00664 {
00665     if( w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_ENTANGLED ) {
00666         message(gettext("You are stuck in the webs!"));
00667         timepass(1);
00668         return;
00669     }
00670     w->interrupt = 0;
00671 #ifdef IS_CALCULATOR
00672     short scratch;
00673 #endif
00674     
00675     do
00676     {
00677         plr_walk(x, y);
00678 #ifdef IS_CALCULATOR
00679         if(OSqinquire(&scratch, kbd_queue()))
00680             break;
00681 #endif
00682     }
00683     while(!w->interrupt);
00684 }
00685 //}}}
00686 //{{{
00688 static void plr_attack( int monstid )
00689 {
00690     sint damage;
00691     
00692     if(monst_attack_type(MTRIGGER_PREEMPT, monstid, 1))
00693         return;
00694     
00695     monst_anger(monstid);
00696     damage = nrandom(w->plr.extrinsic[STAT_DAMAGE_MAX], w->plr.extrinsic[STAT_DAMAGE_MIN]);
00697 #ifdef DEBUG_BALANCE
00698     if(w->debug_mode)
00699         message("(%i,%i)v[%i,%i]{%i/%i}",
00700             w->plr.extrinsic[STAT_TOHIT] + w->plr.level*2, damage,
00701             MDESC(monstid)->dv, MDESC(monstid)->pv,
00702             w->m[monstid].hps, MDESC(monstid)->hps_max);
00703 #endif
00704     if( plr_attack_monster_roll(monstid, w->plr.extrinsic[STAT_TOHIT]) )
00705     {
00706         message(gettext("You hit the %s."), monstname(monstid));
00707         
00708         monst_takedamage(monstid, damage, 1);
00709     } else {
00710         message(gettext("You miss the %s."), monstname(monstid));
00711     }
00712     award_mark();
00713 }
00714 //}}}
00715 //{{{
00717 void plr_takedamage(sint amt, const char *cause_of_death)
00718 {
00719     amt = max( amt - w->plr.extrinsic[STAT_PV], max(amt/4, 1) );
00720     if(amt==0) return;
00721     w->plr.hps -= amt;
00722     w->interrupt = 1;
00723     
00724     // If no hit points, die.
00725     if(w->plr.hps <= 0) // Game over.
00726     {
00727         if(!(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_NUMB))
00728         {
00729             die(cause_of_death);
00730         }
00731     }
00732 }
00733 //}}}
00734 //{{{
00736 static const char* statmsg[3][5] = {
00737     {
00738         gettext("You feel weaker."),
00739         gettext("You feel clumsy."),
00740         gettext("You feel sickly."),
00741         gettext("You feel tired."),
00742         gettext("You feel naive."),
00743     },
00744     {
00745         gettext("You feel stronger."),
00746         gettext("Your coordination improves."),
00747         gettext("You feel tougher."),
00748         gettext("You feel powerful."),
00749         gettext("You feel skeptical."),
00750     },
00751     {
00752         gettext("You feel your strength returning."),
00753         gettext("You feel less clumsy."),
00754         gettext("You feel restored to health."),
00755         gettext("You feel restored."),
00756         gettext("You feel less naive."),
00757     }
00758   };
00759 //}}}
00760 //{{{
00762 void plr_mod_stat(sint which, sint amt)
00763 {
00764     message(statmsg[amt>0][which]);
00765     
00766     if( amt <= 0 ) {
00767         if(w->plr.intrinsic[which] > -amt)
00768             w->plr.intrinsic[which] += amt;
00769         else
00770             w->plr.intrinsic[which] = 1;
00771     } else {
00772         w->plr.intrinsic[which] += amt;
00773         if(w->plr.maximum[which] < w->plr.intrinsic[which])
00774             w->plr.maximum[which] = w->plr.intrinsic[which];
00775     }
00776     
00777     update_player();
00778 }
00779 //}}}
00780 //{{{
00782 short plr_restore_stat(short which, short amt)
00783 {
00784     if(w->plr.intrinsic[which] >= w->plr.maximum[which])
00785         return 0;
00786     message(statmsg[2][which]);
00787     w->plr.intrinsic[which] += amt;
00788     if(w->plr.intrinsic[which] > w->plr.maximum[which])
00789         w->plr.intrinsic[which] = w->plr.maximum[which];
00790     update_player();
00791     return 1;
00792 }
00793 //}}}
00794 //{{{
00799 void plr_moveto(ushort x, ushort y, sshort displace_monst)
00800 {
00801     int was_in_shop=0;
00802     int old_x = w->plr.x, old_y = w->plr.y;
00803     
00804     if(displace_monst >= 0)
00805     {
00806         w->m[displace_monst].x = old_x;
00807         w->m[displace_monst].y = old_y;
00808     } else {
00809         w->t[old_y][old_x].flags &= ~TFLAG_OCCUPIED;
00810     }
00811     
00812     if(w->t[old_y][old_x].type == TILE_SHOPFLOOR)
00813         was_in_shop = 1;
00814     
00815     w->plr.x = x;
00816     w->plr.y = y;
00817     draw_tile(old_x, old_y);    // Redraw the tile the player stepped off of
00818     w->t[w->plr.y][w->plr.x].flags |= TFLAG_OCCUPIED | TFLAG_LIT | TFLAG_EXPLORED;
00819     UI_TF_MoveCamera(w->plr.x, w->plr.y);
00820     draw_tile(w->plr.x, w->plr.y);  // Redraw the tile the player stepped onto
00821     calc_light();
00822     
00823     if(!was_in_shop && w->t[y][x].type == TILE_SHOPFLOOR)
00824     {
00825         message(gettext("You enter %s."), deref_file_ptr(w->shopdescs[w->t[y][x].special].name));
00826     }
00827 
00828     if(count_items(x, y) > 0)
00829         item_step();
00830     
00831     call_stepfunc( TILEDESC(w->t[y][x]).step_function, x, y);
00832 }
00833 //}}}
00834 //{{{
00836 static void manip_door(int open)
00837 {
00838     int x=0, y=0;
00839     int xi, yi, n=0;
00840     direction d;
00841     int success=0;
00842     
00843     for(yi=w->plr.y-1; yi<=w->plr.y+1; yi++)
00844     for(xi=w->plr.x-1; xi<=w->plr.x+1; xi++)
00845     {
00846         if(w->t[yi][xi].type == TILE_ODOOR || w->t[yi][xi].type == TILE_CDOOR)
00847         {
00848             n++;
00849             x = xi;
00850             y = yi;
00851         }
00852     }
00853     
00854     if(n != 1)
00855     {
00856         prompt_dir(gettext("In what direction?"), &d);
00857         x = w->plr.x + d.x;
00858         y = w->plr.y + d.y;
00859     }
00860     
00861     if( open ) {
00862         if( w->t[y][x].type == TILE_CDOOR ) {
00863             w->t[y][x].type = TILE_ODOOR;
00864             success=1;
00865         }
00866     } else {
00867         if( w->t[y][x].type == TILE_ODOOR ) {
00868             if(monstbytile(x, y) != -1 || count_items(x, y) > 0)
00869                 message(gettext("The door is blocked."));
00870             else
00871                 w->t[y][x].type = TILE_CDOOR;
00872             success=1;
00873         }
00874     }
00875     calc_light();
00876     
00877     if( !success )
00878         message(gettext("You see no door there."));
00879     else
00880     {
00881         draw_tile(x, y);
00882         timepass(1);
00883     }
00884 }
00885 //}}}
00886 //{{{
00888 void plr_search(void)
00889 {
00890     int x, y;
00891     
00892     timepass(1);
00893     
00894     for(y=w->plr.y-1; y<=w->plr.y+1; y++)
00895         for(x=w->plr.x-1; x<=w->plr.x+1; x++)
00896         {
00897             if(w->t[y][x].type == TILE_SDOOR && RANGE(1,0)==0)  // Found a secret door
00898             {
00899                 w->t[y][x].type = TILE_CDOOR;
00900                 message(gettext("You found a secret door!"));
00901                 draw_tile(x, y);
00902                 awardXP(5);
00903             }
00904             if(w->t[y][x].flags & TFLAG_HIDETRAP && RANGE(1,0)==0)  // Found a trap
00905             {
00906                 w->t[y][x].flags &= ~TFLAG_HIDETRAP;
00907                 message(gettext("You found a trap!"));
00908                 draw_tile(x, y);
00909                 awardXP(10);
00910             }
00911         }
00912 }
00913 //}}}
00914 //{{{
00921 void awardXP(uint amt)
00922 {
00923     ulong xpneeded;
00924     
00925     w->plr.xp += amt;
00926     
00927     // If sufficient experience, gain a level.
00928     xpneeded = (25L*(w->plr.level+2L)*w->plr.level);
00929     
00930     if(w->plr.xp > xpneeded) {
00931         message(gettext("You gained a level!"));
00932         w->plr.level++;
00933         w->plr.xp = 0;
00934         update_player();
00935     }
00936     
00937     w->plr.score += amt;
00938 }
00939 //}}}
00940 //{{{
00942 void char_info(void)
00943 {
00944     char outbuf[2048];
00945     Graph_ClrScr();
00946     sprintf(
00947         outbuf,
00948         gettext("Level %i %s\n"
00949         "\n"
00950         "Strength\t%i\t (%i)\n"
00951         "Dexterity\t%i\t (%i)\n"
00952         "Toughness\t%i\t (%i)\n"
00953         "Mana\t%i\t (%i)\n"
00954         "Willpower\t%i\t (%i)\n"
00955         "\n"
00956         "Speed %i\n"
00957         "DV %i(%i)\n"
00958         "PV %i(%i)\n"
00959         "Damage %i-%i\n"
00960         "\n"
00961         "Weapon skills\n"),
00962         (int)w->plr.level,                (const char*)deref_file_ptr(w->playerclasses[w->plr.class].name),
00963         (int)w->plr.intrinsic[STAT_STRENGTH],   (int)w->plr.extrinsic[STAT_STRENGTH],
00964         (int)w->plr.intrinsic[STAT_DEXTERITY],  (int)w->plr.extrinsic[STAT_DEXTERITY],
00965         (int)w->plr.intrinsic[STAT_TOUGHNESS],  (int)w->plr.extrinsic[STAT_TOUGHNESS],
00966         (int)w->plr.intrinsic[STAT_MANA],       (int)w->plr.extrinsic[STAT_MANA],
00967         (int)w->plr.intrinsic[STAT_WILLPOWER],  (int)w->plr.extrinsic[STAT_WILLPOWER],
00968         (int)w->plr.extrinsic[STAT_SPEED],
00969         (int)w->plr.extrinsic[STAT_DV],         (int)w->plr.intrinsic[STAT_DV],
00970         (int)w->plr.extrinsic[STAT_PV],         (int)w->plr.intrinsic[STAT_PV],
00971         (int)w->plr.extrinsic[STAT_DAMAGE_MIN], (int)w->plr.extrinsic[STAT_DAMAGE_MAX]
00972     );
00973     print_skills(outbuf);
00974     
00975     setTabStops(player_screen_tabs);
00976 #ifdef IS_CALCULATOR
00977     SetFont(OPTION_FONT_SMALL);
00978 #endif
00979     draw_string(outbuf, NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 1);
00980     read_char();
00981     full_redraw();
00982 }
00983 //}}}
00984 

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