00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
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
00252
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:
00383 follow_connection();
00384 break;
00385
00387
00388 case KEY_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:
00396 wear_item();
00397 break;
00398
00399 case KEY_WEAR_MULTIPLE:
00400 wear_multiple();
00401 break;
00402
00403 case KEY_TAKEOFF:
00404 takeoff_item();
00405 break;
00406
00407 case KEY_TAKEOFF_MULTIPLE:
00408 takeoff_multiple();
00409 break;
00410
00411 case KEY_DROP:
00412 drop_item();
00413 break;
00414
00415 case KEY_DROP_MULTIPLE:
00416 drop_multiple();
00417 break;
00418
00419 case KEY_PICKUP:
00420
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:
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:
00455 plr_search();
00456 break;
00457
00458 case KEY_ESC:
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:
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:
00494 manip_door(0);
00495 break;
00496 case KEY_OPENDOOR:
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:
00532 break;
00533
00535 #ifdef ALLOWDEBUG
00536 case KEY_DEBUG:
00537 debug();
00538 break;
00539 #endif
00540
00541 default:
00542 #ifndef USE_CURSES // ... but not in curses, since some versions send
00543
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
00725 if(w->plr.hps <= 0)
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);
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);
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)
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)
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
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