diff options
Diffstat (limited to 'crawl-ref/source/misc.cc')
-rw-r--r-- | crawl-ref/source/misc.cc | 1358 |
1 files changed, 10 insertions, 1348 deletions
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 3811cb6a61..4b3a6a8f4a 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -35,48 +35,42 @@ #endif #include "externs.h" +#include "misc.h" #include "abyss.h" #include "branch.h" -#include "chardump.h" -#include "cloud.h" #include "clua.h" +#include "cloud.h" #include "delay.h" #include "dgnevent.h" -#include "fight.h" +#include "direct.h" +#include "dungeon.h" #include "files.h" #include "food.h" -#include "hiscores.h" #include "it_use2.h" -#include "items.h" #include "itemprop.h" +#include "items.h" #include "lev-pand.h" -#include "macro.h" -#include "makeitem.h" -#include "mapmark.h" -#include "monplace.h" +#include "message.h" #include "mon-util.h" #include "monstuff.h" -#include "mstuff2.h" -#include "notes.h" #include "ouch.h" -#include "overmap.h" +#include "place.h" #include "player.h" #include "religion.h" #include "shopping.h" #include "skills.h" #include "skills2.h" #include "spells3.h" -#include "spl-cast.h" +#include "stash.h" #include "stuff.h" +#include "terrain.h" #include "transfor.h" +#include "traps.h" #include "travel.h" #include "tutorial.h" #include "view.h" -bool scramble(void); -static void dart_trap(bool trap_known, int trapped, bolt &pbolt, bool poison); - // void place_chunks(int mcls, unsigned char rot_status, unsigned char chx, // unsigned char chy, unsigned char ch_col) void turn_corpse_into_chunks( item_def &item ) @@ -151,246 +145,6 @@ void turn_corpse_into_chunks( item_def &item ) } } // end place_chunks() -bool grid_is_wall( dungeon_feature_type grid ) -{ - return (grid == DNGN_ROCK_WALL - || grid == DNGN_STONE_WALL - || grid == DNGN_METAL_WALL - || grid == DNGN_GREEN_CRYSTAL_WALL - || grid == DNGN_WAX_WALL - || grid == DNGN_PERMAROCK_WALL); -} - -bool grid_is_stone_stair(dungeon_feature_type grid) -{ - switch (grid) - { - case DNGN_STONE_STAIRS_UP_I: - case DNGN_STONE_STAIRS_UP_II: - case DNGN_STONE_STAIRS_UP_III: - case DNGN_STONE_STAIRS_DOWN_I: - case DNGN_STONE_STAIRS_DOWN_II: - case DNGN_STONE_STAIRS_DOWN_III: - return (true); - default: - return (false); - } -} - -bool grid_is_rock_stair(dungeon_feature_type grid) -{ - switch (grid) - { - case DNGN_ROCK_STAIRS_UP: - case DNGN_ROCK_STAIRS_DOWN: - return (true); - default: - return (false); - } -} - -bool grid_sealable_portal(dungeon_feature_type grid) -{ - switch (grid) - { - case DNGN_ENTER_HELL: - case DNGN_ENTER_ABYSS: - case DNGN_ENTER_PANDEMONIUM: - case DNGN_ENTER_LABYRINTH: - case DNGN_ENTER_PORTAL_VAULT: - return (true); - default: - return (false); - } -} - -bool grid_is_portal(dungeon_feature_type grid) -{ - return (grid == DNGN_ENTER_PORTAL_VAULT || grid == DNGN_EXIT_PORTAL_VAULT); -} - -command_type grid_stair_direction(dungeon_feature_type grid) -{ - switch (grid) - { - case DNGN_STONE_STAIRS_UP_I: - case DNGN_STONE_STAIRS_UP_II: - case DNGN_STONE_STAIRS_UP_III: - case DNGN_ROCK_STAIRS_UP: - case DNGN_RETURN_FROM_ORCISH_MINES: - case DNGN_RETURN_FROM_HIVE: - case DNGN_RETURN_FROM_LAIR: - case DNGN_RETURN_FROM_SLIME_PITS: - case DNGN_RETURN_FROM_VAULTS: - case DNGN_RETURN_FROM_CRYPT: - case DNGN_RETURN_FROM_HALL_OF_BLADES: - case DNGN_RETURN_FROM_ZOT: - case DNGN_RETURN_FROM_TEMPLE: - case DNGN_RETURN_FROM_SNAKE_PIT: - case DNGN_RETURN_FROM_ELVEN_HALLS: - case DNGN_RETURN_FROM_TOMB: - case DNGN_RETURN_FROM_SWAMP: - case DNGN_RETURN_FROM_SHOALS: - case DNGN_RETURN_RESERVED_2: - case DNGN_RETURN_RESERVED_3: - case DNGN_RETURN_RESERVED_4: - case DNGN_ENTER_SHOP: - case DNGN_EXIT_HELL: - case DNGN_EXIT_PORTAL_VAULT: - return (CMD_GO_UPSTAIRS); - - case DNGN_ENTER_PORTAL_VAULT: - case DNGN_ENTER_HELL: - case DNGN_ENTER_LABYRINTH: - case DNGN_STONE_STAIRS_DOWN_I: - case DNGN_STONE_STAIRS_DOWN_II: - case DNGN_STONE_STAIRS_DOWN_III: - case DNGN_ROCK_STAIRS_DOWN: - case DNGN_ENTER_DIS: - case DNGN_ENTER_GEHENNA: - case DNGN_ENTER_COCYTUS: - case DNGN_ENTER_TARTARUS: - case DNGN_ENTER_ABYSS: - case DNGN_EXIT_ABYSS: - case DNGN_ENTER_PANDEMONIUM: - case DNGN_EXIT_PANDEMONIUM: - case DNGN_TRANSIT_PANDEMONIUM: - case DNGN_ENTER_ORCISH_MINES: - case DNGN_ENTER_HIVE: - case DNGN_ENTER_LAIR: - case DNGN_ENTER_SLIME_PITS: - case DNGN_ENTER_VAULTS: - case DNGN_ENTER_CRYPT: - case DNGN_ENTER_HALL_OF_BLADES: - case DNGN_ENTER_ZOT: - case DNGN_ENTER_TEMPLE: - case DNGN_ENTER_SNAKE_PIT: - case DNGN_ENTER_ELVEN_HALLS: - case DNGN_ENTER_TOMB: - case DNGN_ENTER_SWAMP: - case DNGN_ENTER_SHOALS: - case DNGN_ENTER_RESERVED_2: - case DNGN_ENTER_RESERVED_3: - case DNGN_ENTER_RESERVED_4: - return (CMD_GO_DOWNSTAIRS); - - default: - return (CMD_NO_CMD); - } -} - -bool grid_is_opaque( dungeon_feature_type grid ) -{ - return (grid < DNGN_MINSEE && grid != DNGN_ORCISH_IDOL); -} - -bool grid_is_solid( dungeon_feature_type grid ) -{ - return (grid < DNGN_MINMOVE); -} - -bool grid_is_solid( int x, int y ) -{ - return (grid_is_solid(grd[x][y])); -} - -bool grid_is_solid(const coord_def &c) -{ - return (grid_is_solid(grd(c))); -} - -bool grid_is_trap(dungeon_feature_type grid) -{ - return (grid == DNGN_TRAP_MECHANICAL || grid == DNGN_TRAP_MAGICAL - || grid == DNGN_TRAP_III); -} - -bool grid_is_water( dungeon_feature_type grid ) -{ - return (grid == DNGN_SHALLOW_WATER || grid == DNGN_DEEP_WATER); -} - -bool grid_is_watery( dungeon_feature_type grid ) -{ - return (grid_is_water(grid) || grid == DNGN_BLUE_FOUNTAIN); -} - -bool grid_destroys_items( dungeon_feature_type grid ) -{ - return (grid == DNGN_LAVA || grid == DNGN_DEEP_WATER); -} - -// returns 0 if grid is not an altar, else it returns the GOD_* type -god_type grid_altar_god( dungeon_feature_type grid ) -{ - if (grid >= DNGN_ALTAR_ZIN && grid <= DNGN_ALTAR_BEOGH) - return (static_cast<god_type>( grid - DNGN_ALTAR_ZIN + 1 )); - - return (GOD_NO_GOD); -} - -// returns DNGN_FLOOR for non-gods, otherwise returns the altar for -// the god. -dungeon_feature_type altar_for_god( god_type god ) -{ - if (god == GOD_NO_GOD || god >= NUM_GODS) - return (DNGN_FLOOR); // Yeah, lame. Tell me about it. - - return static_cast<dungeon_feature_type>(DNGN_ALTAR_ZIN + god - 1); -} - -bool grid_is_branch_stairs( dungeon_feature_type grid ) -{ - return ((grid >= DNGN_ENTER_ORCISH_MINES && grid <= DNGN_ENTER_RESERVED_4) - || (grid >= DNGN_ENTER_DIS && grid <= DNGN_ENTER_TARTARUS)); -} - -int grid_secret_door_appearance( int gx, int gy ) -{ - int ret = DNGN_FLOOR; - - for (int dx = -1; dx <= 1; dx++) - { - for (int dy = -1; dy <= 1; dy++) - { - // only considering orthogonal grids - if ((abs(dx) + abs(dy)) % 2 == 0) - continue; - - const dungeon_feature_type targ = grd[gx + dx][gy + dy]; - - if (!grid_is_wall( targ )) - continue; - - if (ret == DNGN_FLOOR) - ret = targ; - else if (ret != targ) - ret = ((ret < targ) ? ret : targ); - } - } - - return ((ret == DNGN_FLOOR) ? DNGN_ROCK_WALL - : ret); -} - -const char *grid_item_destruction_message( dungeon_feature_type grid ) -{ - return grid == DNGN_DEEP_WATER? "You hear a splash." - : grid == DNGN_LAVA ? "You hear a sizzling splash." - : "You hear a crunching noise."; -} - -// Returns true if exits from this type of level involve going upstairs. -bool level_type_exits_up(level_area_type type) -{ - return (type == LEVEL_LABYRINTH || type == LEVEL_PORTAL_VAULT); -} - -bool level_type_exits_down(level_area_type type) -{ - return (type == LEVEL_PANDEMONIUM || type == LEVEL_ABYSS); -} - void search_around( bool only_adjacent ) { int i; @@ -454,181 +208,6 @@ void search_around( bool only_adjacent ) return; } // end search_around() -static coord_def dgn_find_nearest_square( - const coord_def &pos, - bool (*acceptable)(const coord_def &), - bool (*traversable)(const coord_def &) = NULL) -{ - memset(travel_point_distance, 0, sizeof(travel_distance_grid_t)); - - std::list<coord_def> points[2]; - int iter = 0; - points[iter].push_back(pos); - - while (!points[iter].empty()) - { - for (std::list<coord_def>::iterator i = points[iter].begin(); - i != points[iter].end(); ++i) - { - const coord_def &p = *i; - - if (p != pos && acceptable(p)) - return (p); - - travel_point_distance[p.x][p.y] = 1; - for (int yi = -1; yi <= 1; ++yi) - { - for (int xi = -1; xi <= 1; ++xi) - { - if (!xi && !yi) - continue; - - const coord_def np = p + coord_def(xi, yi); - if (!in_bounds(np) || travel_point_distance[np.x][np.y]) - continue; - - if (traversable && !traversable(np)) - continue; - - points[!iter].push_back(np); - } - } - } - - points[iter].clear(); - iter = !iter; - } - - coord_def unfound; - return (unfound); -} - -static bool item_safe_square(const coord_def &pos) -{ - const dungeon_feature_type feat = grd(pos); - return (is_traversable(feat) && !grid_destroys_items(feat)); -} - -// Moves an item on the floor to the nearest adjacent floor-space. -static bool dgn_shift_item(const coord_def &pos, item_def &item) -{ - const coord_def np = dgn_find_nearest_square(pos, item_safe_square); - if (in_bounds(np) && np != pos) - { - int index = item.index(); - move_item_to_grid(&index, np.x, np.y); - return (true); - } - return (false); -} - -static bool is_critical_feature(dungeon_feature_type feat) -{ - return (grid_stair_direction(feat) != CMD_NO_CMD - || grid_altar_god(feat) != GOD_NO_GOD); -} - -static bool is_feature_shift_target(const coord_def &pos) -{ - return (grd(pos) == DNGN_FLOOR && !dungeon_events.has_listeners_at(pos)); -} - -static bool dgn_shift_feature(const coord_def &pos) -{ - const dungeon_feature_type dfeat = grd(pos); - if (!is_critical_feature(dfeat) && !env.markers.find(pos, MAT_ANY)) - return (false); - - const coord_def dest = - dgn_find_nearest_square(pos, is_feature_shift_target); - if (in_bounds(dest) && dest != pos) - { - grd(dest) = dfeat; - - if (dfeat == DNGN_ENTER_SHOP) - { - if (shop_struct *s = get_shop(pos.x, pos.y)) - { - s->x = dest.x; - s->y = dest.y; - } - } - env.markers.move(pos, dest); - dungeon_events.move_listeners(pos, dest); - } - return (true); -} - -static void dgn_check_terrain_items(const coord_def &pos, bool preserve_items) -{ - const dungeon_feature_type grid = grd(pos); - if (grid_is_solid(grid) || grid_destroys_items(grid)) - { - int item = igrd(pos); - bool did_destroy = false; - while (item != NON_ITEM) - { - const int curr = item; - item = mitm[item].link; - - // Game-critical item. - if (preserve_items || item_is_critical(mitm[curr])) - dgn_shift_item(pos, mitm[curr]); - else - { - destroy_item(curr); - did_destroy = true; - } - } - if (did_destroy && player_can_hear(pos)) - mprf(MSGCH_SOUND, grid_item_destruction_message(grid)); - } -} - -static void dgn_check_terrain_monsters(const coord_def &pos) -{ - const int mindex = mgrd(pos); - if (mindex != NON_MONSTER) - { - monsters *mons = &menv[mindex]; - if (grid_is_solid(grd(pos))) - monster_teleport(mons, true, false); - else - mons_check_pool(mons, KILL_MISC, -1); - } -} - -void dungeon_terrain_changed(const coord_def &pos, - dungeon_feature_type nfeat, - bool affect_player, - bool preserve_features, - bool preserve_items) -{ - if (nfeat != DNGN_UNSEEN) - { - if (preserve_features) - dgn_shift_feature(pos); - unnotice_feature(level_pos(level_id::current(), pos)); - grd(pos) = nfeat; - env.grid_colours(pos) = BLACK; - if (is_notable_terrain(nfeat) && see_grid(pos)) - seen_notable_thing(nfeat, pos.x, pos.y); - } - - dgn_check_terrain_items(pos, preserve_items); - if (affect_player && pos == you.pos()) - { - if (!grid_is_solid(grd(pos))) - { - if (!you.flies()) - move_player_to_grid(pos.x, pos.y, false, true, false); - } - else - you_teleport_now(true, false); - } - dgn_check_terrain_monsters(pos); -} - void in_a_cloud() { int cl = env.cgrid[you.x_pos][you.y_pos]; @@ -817,133 +396,6 @@ void curare_hits_player(int agent, int degree) } } -// returns the number of a net on a given square -// if trapped only stationary ones are counted -// otherwise the first net found is returned -int get_trapping_net(int x, int y, bool trapped) -{ - int net, next; - - for (net = igrd[x][y]; net != NON_ITEM; net = next) - { - next = mitm[net].link; - - if (mitm[net].base_type == OBJ_MISSILES - && mitm[net].sub_type == MI_THROWING_NET - && (!trapped || item_is_stationary(mitm[net]))) - { - return (net); - } - } - return (NON_ITEM); -} - -// if there are more than one net on this square -// split off one of them for checking/setting values -static void maybe_split_nets(item_def &item, int x, int y) -{ - if (item.quantity == 1) - { - set_item_stationary(item); - return; - } - - item_def it; - - it.base_type = item.base_type; - it.sub_type = item.sub_type; - it.plus = item.plus; - it.plus2 = item.plus2; - it.flags = item.flags; - it.special = item.special; - it.quantity = --item.quantity; - item_colour(it); - - item.quantity = 1; - set_item_stationary(item); - - copy_item_to_grid( it, x, y ); -} - -void mark_net_trapping(int x, int y) -{ - int net = get_trapping_net(x,y); - if (net == NON_ITEM) - { - net = get_trapping_net(x,y, false); - if (net != NON_ITEM) - maybe_split_nets(mitm[net], x, y); - } -} - -void monster_caught_in_net(monsters *mon, bolt &pbolt) -{ - if (mon->body_size(PSIZE_BODY) >= SIZE_GIANT) - return; - - if (mons_is_insubstantial(mon->type)) - { - if (mons_near(mon) && player_monster_visible(mon)) - mprf("The net passes right through %s!", mon->name(DESC_NOCAP_THE).c_str()); - return; - } - - const monsters* mons = static_cast<const monsters*>(mon); - bool mon_flies = mons->flies(); - if (mon_flies && !mons_is_confused(mons)) - { - simple_monster_message(mon, " darts out from under the net!"); - return; - } - - if (mons->type == MONS_OOZE || mons->type == MONS_PULSATING_LUMP) - { - simple_monster_message(mon, " oozes right through the net!"); - return; - } - - if (!mons_is_caught(mon) && mon->add_ench(ENCH_HELD)) - { - if (mons_near(mon) && !player_monster_visible(mon)) - mpr("Something gets caught in the net!"); - else - simple_monster_message(mon, " is caught in the net!"); - - if (mon_flies) - { - simple_monster_message(mon, " falls like a stone!"); - mons_check_pool(mon, pbolt.killer(), pbolt.beam_source); - } - } -} - -void player_caught_in_net() -{ - if (you.body_size(PSIZE_BODY) >= SIZE_GIANT) - return; - - if (you.flies() && !you.confused()) - { - mpr("You dart out from under the net!"); - return; - } - - if (!you.attribute[ATTR_HELD]) - { - you.attribute[ATTR_HELD] = 10; - mpr("You become entangled in the net!"); - - // I guess levitation works differently, keeping both you - // and the net hovering above the floor - if (you.flies()) - { - mpr("You fall like a stone!"); - fall_into_a_pool(you.x_pos, you.y_pos, false, grd[you.x_pos][you.y_pos]); - } - } - -} - void merfolk_start_swimming(void) { if (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE) @@ -1619,449 +1071,6 @@ void new_level(void) #endif } -static void dart_trap(bool trap_known, int trapped, bolt &pbolt, bool poison) -{ - int damage_taken = 0; - int trap_hit, your_dodge; - - if (one_chance_in(5) || (trap_known && !one_chance_in(4))) - { - mprf( "You avoid triggering a%s trap.", pbolt.name.c_str() ); - return; - } - - if (you.equip[EQ_SHIELD] != -1 && one_chance_in(3)) - exercise( SK_SHIELDS, 1 ); - - std::string msg = "A" + pbolt.name + " shoots out and "; - - if (random2( 20 + 5 * you.shield_blocks * you.shield_blocks ) - < player_shield_class()) - { - you.shield_blocks++; - msg += "hits your shield."; - mpr(msg.c_str()); - } - else - { - // note that this uses full ( not random2limit(foo,40) ) - // player_evasion. - trap_hit = (20 + (you.your_level * 2)) * random2(200) / 100; - - your_dodge = player_evasion() + random2(you.dex) / 3 - - 2 + (you.duration[DUR_REPEL_MISSILES] * 10); - - if (trap_hit >= your_dodge && you.duration[DUR_DEFLECT_MISSILES] == 0) - { - msg += "hits you!"; - mpr(msg.c_str()); - - if (poison && random2(100) < 50 - (3 * player_AC()) / 2 - && !player_res_poison()) - { - poison_player( 1 + random2(3) ); - } - - damage_taken = roll_dice( pbolt.damage ); - damage_taken -= random2( player_AC() + 1 ); - - if (damage_taken > 0) - ouch( damage_taken, 0, KILLED_BY_TRAP, pbolt.name.c_str() ); - } - else - { - msg += "misses you."; - mpr(msg.c_str()); - } - - if (player_light_armour(true) && coinflip()) - exercise( SK_DODGING, 1 ); - } - - pbolt.target_x = you.x_pos; - pbolt.target_y = you.y_pos; - - if (coinflip()) - itrap( pbolt, trapped ); -} // end dart_trap() - -// -// itrap takes location from target_x, target_y of bolt strcture. -// - -void itrap( struct bolt &pbolt, int trapped ) -{ - object_class_type base_type = OBJ_MISSILES; - int sub_type = MI_DART; - - switch (env.trap[trapped].type) - { - case TRAP_DART: - base_type = OBJ_MISSILES; - sub_type = MI_DART; - break; - case TRAP_ARROW: - base_type = OBJ_MISSILES; - sub_type = MI_ARROW; - break; - case TRAP_BOLT: - base_type = OBJ_MISSILES; - sub_type = MI_BOLT; - break; - case TRAP_SPEAR: - base_type = OBJ_WEAPONS; - sub_type = WPN_SPEAR; - break; - case TRAP_AXE: - base_type = OBJ_WEAPONS; - sub_type = WPN_HAND_AXE; - break; - case TRAP_NEEDLE: - base_type = OBJ_MISSILES; - sub_type = MI_NEEDLE; - break; - case TRAP_NET: - base_type = OBJ_MISSILES; - sub_type = MI_THROWING_NET; - break; - default: - return; - } - - trap_item( base_type, sub_type, pbolt.target_x, pbolt.target_y ); - - return; -} // end itrap() - -void handle_traps(char trt, int i, bool trap_known) -{ - struct bolt beam; - - switch (trt) - { - case TRAP_DART: - beam.name = " dart"; - beam.damage = dice_def( 1, 4 + (you.your_level / 2) ); - dart_trap(trap_known, i, beam, false); - break; - - case TRAP_NEEDLE: - beam.name = " needle"; - beam.damage = dice_def( 1, 0 ); - dart_trap(trap_known, i, beam, true); - break; - - case TRAP_ARROW: - beam.name = "n arrow"; - beam.damage = dice_def( 1, 7 + you.your_level ); - dart_trap(trap_known, i, beam, false); - break; - - case TRAP_BOLT: - beam.name = " bolt"; - beam.damage = dice_def( 1, 13 + you.your_level ); - dart_trap(trap_known, i, beam, false); - break; - - case TRAP_SPEAR: - beam.name = " spear"; - beam.damage = dice_def( 1, 10 + you.your_level ); - dart_trap(trap_known, i, beam, false); - break; - - case TRAP_AXE: - beam.name = "n axe"; - beam.damage = dice_def( 1, 15 + you.your_level ); - dart_trap(trap_known, i, beam, false); - break; - - case TRAP_TELEPORT: - mpr("You enter a teleport trap!"); - - if (scan_randarts(RAP_PREVENT_TELEPORTATION)) - mpr("You feel a weird sense of stasis."); - else - you_teleport_now( true ); - break; - - case TRAP_AMNESIA: - mpr("You feel momentarily disoriented."); - if (!wearing_amulet(AMU_CLARITY)) - forget_map(random2avg(100, 2)); - break; - - case TRAP_BLADE: - if (trap_known && one_chance_in(3)) - mpr("You avoid triggering a blade trap."); - else if (random2limit(player_evasion(), 40) - + (random2(you.dex) / 3) + (trap_known ? 3 : 0) > 8) - { - mpr("A huge blade swings just past you!"); - } - else - { - mpr("A huge blade swings out and slices into you!"); - ouch( (you.your_level * 2) + random2avg(29, 2) - - random2(1 + player_AC()), 0, KILLED_BY_TRAP, " blade" ); - } - break; - - case TRAP_NET: - - if (trap_known && one_chance_in(3)) - mpr("A net swings high above you."); - else - { - if (random2limit(player_evasion(), 40) - + (random2(you.dex) / 3) + (trap_known ? 3 : 0) > 12) - { - mpr("A net drops to the ground!"); - } - else - { - mpr("A large net falls onto you!"); - player_caught_in_net(); - } - - trap_item( OBJ_MISSILES, MI_THROWING_NET, env.trap[i].x, env.trap[i].y ); - if (you.attribute[ATTR_HELD]) - mark_net_trapping(you.x_pos, you.y_pos); - - grd[env.trap[i].x][env.trap[i].y] = DNGN_FLOOR; - env.trap[i].type = TRAP_UNASSIGNED; - } - break; - - case TRAP_ZOT: - default: - mpr((trap_known) ? "You enter the Zot trap." - : "Oh no! You have blundered into a Zot trap!"); - miscast_effect( SPTYP_RANDOM, random2(30) + you.your_level, - 75 + random2(100), 3, "a Zot trap" ); - break; - } - learned_something_new(TUT_SEEN_TRAP, you.x_pos, you.y_pos); -} // end handle_traps() - -void disarm_trap( struct dist &disa ) -{ - if (you.duration[DUR_BERSERKER]) - { - canned_msg(MSG_TOO_BERSERK); - return; - } - - int i, j; - - for (i = 0; i < MAX_TRAPS; i++) - { - if (env.trap[i].x == you.x_pos + disa.dx - && env.trap[i].y == you.y_pos + disa.dy) - { - break; - } - - if (i == MAX_TRAPS - 1) - { - mpr("Error - couldn't find that trap."); - return; - } - } - - if (trap_category(env.trap[i].type) == DNGN_TRAP_MAGICAL) - { - mpr("You can't disarm that trap."); - return; - } - - if (random2(you.skills[SK_TRAPS_DOORS] + 2) <= random2(you.your_level + 5)) - { - mpr("You failed to disarm the trap."); - - you.turn_is_over = true; - - if (random2(you.dex) > 5 + random2(5 + you.your_level)) - exercise(SK_TRAPS_DOORS, 1 + random2(you.your_level / 5)); - else - { - if (env.trap[i].type == TRAP_NET && - (env.trap[i].x != you.x_pos || env.trap[i].y != you.y_pos)) - { - if (coinflip()) - return; - - mpr("You stumble into the trap!"); - move_player_to_grid( env.trap[i].x, env.trap[i].y, true, false, true); - } - else - handle_traps(env.trap[i].type, i, false); - - if (coinflip()) - exercise(SK_TRAPS_DOORS, 1); - } - - return; - } - - mpr("You have disarmed the trap."); - - struct bolt beam; - - beam.target_x = you.x_pos + disa.dx; - beam.target_y = you.y_pos + disa.dy; - - if (env.trap[i].type == TRAP_NET) - trap_item( OBJ_MISSILES, MI_THROWING_NET, beam.target_x, beam.target_y ); - else if (env.trap[i].type != TRAP_BLADE - && trap_category(env.trap[i].type) == DNGN_TRAP_MECHANICAL) - { - const int num_to_make = 10 + random2(you.skills[SK_TRAPS_DOORS]); - for (j = 0; j < num_to_make; j++) - { - // places items (eg darts), which will automatically stack - itrap(beam, i); - } - } - - grd[you.x_pos + disa.dx][you.y_pos + disa.dy] = DNGN_FLOOR; - env.trap[i].type = TRAP_UNASSIGNED; - you.turn_is_over = true; - - // reduced from 5 + random2(5) - exercise(SK_TRAPS_DOORS, 1 + random2(5) + (you.your_level / 5)); -} // end disarm_trap() - -// attempts to take a net off a given monster -// Do not expect gratitude for this! -// ---------------------------------- -void remove_net_from(monsters *mon) -{ - you.turn_is_over = true; - - int net = get_trapping_net(mon->x, mon->y); - - if (net == NON_ITEM) - { - mon->del_ench(ENCH_HELD, true); - return; - } - - // factor in whether monster is paralysed or invisible - int paralys = 0; - if (mons_is_paralysed(mon)) // makes this easier - paralys = random2(5); - - int invis = 0; - if (!player_monster_visible(mon)) // makes this harder - invis = 3 + random2(5); - - bool net_destroyed = false; - if ( random2(you.skills[SK_TRAPS_DOORS] + 2) + paralys - <= random2( 2*mon->body_size(PSIZE_BODY) + 3 ) + invis) - { - if (one_chance_in(you.skills[SK_TRAPS_DOORS] + you.dex/2)) - { - mitm[net].plus--; - mpr("You tear at the net."); - if (mitm[net].plus < -7) - { - mpr("Whoops! The net comes apart in your hands!"); - mon->del_ench(ENCH_HELD, true); - destroy_item(net); - net_destroyed = true; - } - } - - if (!net_destroyed) - { - if (player_monster_visible(mon)) - { - mprf("You fail to remove the net from %s.", - mon->name(DESC_NOCAP_THE).c_str()); - } - else - mpr("You fail to remove the net."); - } - - if (random2(you.dex) > 5 + random2( 2*mon->body_size(PSIZE_BODY) )) - exercise(SK_TRAPS_DOORS, 1 + random2(mon->body_size(PSIZE_BODY)/2)); - return; - } - - mon->del_ench(ENCH_HELD, true); - remove_item_stationary(mitm[net]); - - if (player_monster_visible(mon)) - mprf("You free %s.", mon->name(DESC_NOCAP_THE).c_str()); - else - mpr("You loosen the net."); - -} - -void free_self_from_net(bool damage_net) -{ - int net = get_trapping_net(you.x_pos, you.y_pos); - - if (net == NON_ITEM) // really shouldn't happen! - { - you.attribute[ATTR_HELD] = 0; - return; - } - int hold = mitm[net].plus; - - if (damage_net) - { - mpr("You struggle against the net."); - int damage = 1; - - // extra damage for cutting weapons - if (you.equip[EQ_WEAPON] != -1 - && can_cut_meat(you.inv[you.equip[EQ_WEAPON]])) - { - damage++; - } - - if (you.body_size(PSIZE_BODY) > SIZE_MEDIUM) - damage++; - - if (hold < 0 && !one_chance_in(-hold/2)) - damage++; - - if (you.duration[DUR_BERSERKER]) - damage *= 2; - - mitm[net].plus -= damage; - - if (mitm[net].plus < -7) - { - mpr("You rip the net and break free!"); - dec_mitm_item_quantity( net, 1 ); - - you.attribute[ATTR_HELD] = 0; - return; - } - } - else // you try to escape - { - mpr("You struggle to escape from the net."); - you.attribute[ATTR_HELD]--; - - if (you.body_size(PSIZE_BODY) < SIZE_MEDIUM) - you.attribute[ATTR_HELD]--; - - if (hold < 0 && !one_chance_in(-hold/2)) - you.attribute[ATTR_HELD]--; - - if (you.attribute[ATTR_HELD] <= 0) - { - mpr("You break free from the net!"); - you.attribute[ATTR_HELD] = 0; - remove_item_stationary(mitm[net]); - return; - } - } -} - std::string weird_writing() { int temp_rand; // for probability determinations {dlb} @@ -2121,114 +1130,6 @@ std::string weird_writing() return result; } -// returns true if we manage to scramble free. -bool fall_into_a_pool( int entry_x, int entry_y, bool allow_shift, - unsigned char terrain ) -{ - bool escape = false; - FixedVector< char, 2 > empty; - - if (you.species == SP_MERFOLK && terrain == DNGN_DEEP_WATER) - { - // These can happen when we enter deep water directly -- bwr - merfolk_start_swimming(); - return (false); - } - - // sanity check - if (terrain != DNGN_LAVA && beogh_water_walk()) - return (false); - - mprf("You fall into the %s!", - (terrain == DNGN_LAVA) ? "lava" : - (terrain == DNGN_DEEP_WATER) ? "water" - : "programming rift"); - - more(); - mesclr(); - - if (terrain == DNGN_LAVA) - { - const int resist = player_res_fire(); - - if (resist <= 0) - { - mpr( "The lava burns you to a cinder!" ); - ouch( INSTANT_DEATH, 0, KILLED_BY_LAVA ); - } - else - { - // should boost # of bangs per damage in the future {dlb} - mpr( "The lava burns you!" ); - ouch( (10 + roll_dice(2,50)) / resist, 0, KILLED_BY_LAVA ); - } - - expose_player_to_element( BEAM_LAVA, 14 ); - } - - // a distinction between stepping and falling from you.duration[DUR_LEVITATION] - // prevents stepping into a thin stream of lava to get to the other side. - if (scramble()) - { - if (allow_shift) - { - if (empty_surrounds( you.x_pos, you.y_pos, DNGN_FLOOR, 1, - false, empty )) - { - escape = true; - } - else - { - escape = false; - } - } - else - { - // back out the way we came in, if possible - if (grid_distance( you.x_pos, you.y_pos, entry_x, entry_y ) == 1 - && (entry_x != empty[0] || entry_y != empty[1]) - && mgrd[entry_x][entry_y] == NON_MONSTER) - { - escape = true; - empty[0] = entry_x; - empty[1] = entry_y; - } - else // zero or two or more squares away, with no way back - { - escape = false; - } - } - } - else - { - mpr("You try to escape, but your burden drags you down!"); - } - - if (escape) - { - const coord_def pos(empty[0], empty[1]); - if (in_bounds(pos) && !is_grid_dangerous(grd(pos))) - { - mpr("You manage to scramble free!"); - move_player_to_grid( empty[0], empty[1], false, false, true ); - - if (terrain == DNGN_LAVA) - expose_player_to_element( BEAM_LAVA, 14 ); - - return (true); - } - } - - mpr("You drown..."); - - if (terrain == DNGN_LAVA) - ouch( INSTANT_DEATH, 0, KILLED_BY_LAVA ); - else if (terrain == DNGN_DEEP_WATER) - ouch( INSTANT_DEATH, 0, KILLED_BY_WATER ); - - return (false); -} // end fall_into_a_pool() - bool scramble(void) { int max_carry = carrying_capacity(); @@ -2316,101 +1217,6 @@ bool go_berserk(bool intentional) return true; } // end go_berserk() -bool trap_item(object_class_type base_type, char sub_type, - char beam_x, char beam_y) -{ - item_def item; - - item.base_type = base_type; - item.sub_type = sub_type; - item.plus = 0; - item.plus2 = 0; - item.flags = 0; - item.special = 0; - item.quantity = 1; - - if (base_type == OBJ_MISSILES) - { - if (sub_type == MI_NEEDLE) - set_item_ego_type( item, OBJ_MISSILES, SPMSL_POISONED ); - else - set_item_ego_type( item, OBJ_MISSILES, SPMSL_NORMAL ); - } - else - { - set_item_ego_type( item, OBJ_WEAPONS, SPWPN_NORMAL ); - } - - item_colour(item); - - if (igrd[beam_x][beam_y] != NON_ITEM) - { - if (items_stack( item, mitm[ igrd[beam_x][beam_y] ] )) - { - inc_mitm_item_quantity( igrd[beam_x][beam_y], 1 ); - return (false); - } - - // don't want to go overboard here. Will only generate up to three - // separate trap items, or less if there are other items present. - if (mitm[ igrd[beam_x][beam_y] ].link != NON_ITEM - && (item.base_type != OBJ_MISSILES || item.sub_type != MI_THROWING_NET)) - { - if (mitm[ mitm[ igrd[beam_x][beam_y] ].link ].link != NON_ITEM) - return (false); - } - } // end of if igrd != NON_ITEM - - return (!copy_item_to_grid( item, beam_x, beam_y, 1 )); -} // end trap_item() - -// returns appropriate trap symbol for a given trap type {dlb} -dungeon_feature_type trap_category(trap_type type) -{ - switch (type) - { - case TRAP_TELEPORT: - case TRAP_AMNESIA: - case TRAP_ZOT: - return (DNGN_TRAP_MAGICAL); - - case TRAP_DART: - case TRAP_ARROW: - case TRAP_SPEAR: - case TRAP_AXE: - case TRAP_BLADE: - case TRAP_BOLT: - case TRAP_NEEDLE: - case TRAP_NET: - default: // what *would* be the default? {dlb} - return (DNGN_TRAP_MECHANICAL); - } -} // end trap_category() - -// returns index of the trap for a given (x,y) coordinate pair {dlb} -int trap_at_xy(int which_x, int which_y) -{ - - for (int which_trap = 0; which_trap < MAX_TRAPS; which_trap++) - { - if (env.trap[which_trap].x == which_x && - env.trap[which_trap].y == which_y && - env.trap[which_trap].type != TRAP_UNASSIGNED) - { - return (which_trap); - } - } - - // no idea how well this will be handled elsewhere: {dlb} - return (-1); -} // end trap_at_xy() - -trap_type trap_type_at_xy(int x, int y) -{ - const int idx = trap_at_xy(x, y); - return (idx == -1? NUM_TRAPS : env.trap[idx].type); -} - bool is_damaging_cloud(cloud_type type) { switch (type) @@ -2559,150 +1365,6 @@ bool i_feel_safe(bool announce, bool want_move) return true; } -// Do not attempt to use level_id if level_type != LEVEL_DUNGEON -std::string short_place_name(level_id id) -{ - return id.describe(); -} - -int place_branch(unsigned short place) -{ - const unsigned branch = (unsigned) ((place >> 8) & 0xFF); - const int lev = place & 0xFF; - return lev == 0xFF? -1 : (int) branch; -} - -int place_depth(unsigned short place) -{ - const int lev = place & 0xFF; - return lev == 0xFF? -1 : lev; -} - -unsigned short get_packed_place( branch_type branch, int subdepth, - level_area_type level_type ) -{ - unsigned short place = (unsigned short) - ( (static_cast<int>(branch) << 8) | (subdepth & 0xFF) ); - if (level_type != LEVEL_DUNGEON) - place = (unsigned short) ( (static_cast<int>(level_type) << 8) | 0xFF ); - return place; -} - -unsigned short get_packed_place() -{ - return get_packed_place( you.where_are_you, - subdungeon_depth(you.where_are_you, you.your_level), - you.level_type ); -} - -bool single_level_branch( branch_type branch ) -{ - return - branch >= 0 && branch < NUM_BRANCHES - && branches[branch].depth == 1; -} - -std::string place_name( unsigned short place, bool long_name, - bool include_number ) -{ - - unsigned char branch = (unsigned char) ((place >> 8) & 0xFF); - int lev = place & 0xFF; - - std::string result; - if (lev == 0xFF) - { - switch (branch) - { - case LEVEL_ABYSS: - return ( long_name ? "The Abyss" : "Abyss" ); - case LEVEL_PANDEMONIUM: - return ( long_name ? "Pandemonium" : "Pan" ); - case LEVEL_LABYRINTH: - return ( long_name ? "a Labyrinth" : "Lab" ); - case LEVEL_PORTAL_VAULT: - return ( long_name ? "a Portal Chamber" : "Port" ); - default: - return ( long_name ? "Buggy Badlands" : "Bug" ); - } - } - - result = (long_name ? - branches[branch].longname : branches[branch].abbrevname); - - if ( include_number && branches[branch].depth != 1 ) - { - char buf[200]; - if ( long_name ) - { - // decapitalize 'the' - if ( result.find("The") == 0 ) - result[0] = 't'; - snprintf( buf, sizeof buf, "Level %d of %s", - lev, result.c_str() ); - } - else if (lev) - snprintf( buf, sizeof buf, "%s:%d", result.c_str(), lev ); - else - snprintf( buf, sizeof buf, "%s:$", result.c_str() ); - - result = buf; - } - return result; -} - -// Takes a packed 'place' and returns a compact stringified place name. -// XXX: This is done in several other places; a unified function to -// describe places would be nice. -std::string short_place_name(unsigned short place) -{ - return place_name( place, false, true ); -} - -// Prepositional form of branch level name. For example, "in the -// Abyss" or "on level 3 of the Main Dungeon". -std::string prep_branch_level_name(unsigned short packed_place) -{ - std::string place = place_name( packed_place, true, true ); - if (place.length() && place != "Pandemonium") - place[0] = tolower(place[0]); - return (place.find("level") == 0? - "on " + place - : "in " + place); -} - -// Use current branch and depth -std::string prep_branch_level_name() -{ - return prep_branch_level_name( get_packed_place() ); -} - -int absdungeon_depth(branch_type branch, int subdepth) -{ - if (branch >= BRANCH_VESTIBULE_OF_HELL && branch <= BRANCH_THE_PIT) - return subdepth + 27 - (branch == BRANCH_VESTIBULE_OF_HELL); - else - { - --subdepth; - while ( branch != BRANCH_MAIN_DUNGEON ) - { - subdepth += branches[branch].startdepth; - branch = branches[branch].parent_branch; - } - } - return subdepth; -} - -int subdungeon_depth(branch_type branch, int depth) -{ - return depth - absdungeon_depth(branch, 0); -} - -int player_branch_depth() -{ - return subdungeon_depth(you.where_are_you, you.your_level); -} - static const char *shop_types[] = { "weapon", "armour", |