/** * Perform the basic "disarm" command * * Assume there is no monster blocking the destination * * Returns true if repeated commands may continue */ static bool do_cmd_disarm_aux(int y, int x) { int skill, power, chance; struct trap *trap = cave->squares[y][x].trap; bool more = false; /* Verify legality */ if (!do_cmd_disarm_test(y, x)) return (false); /* Choose first player trap */ while (trap) { if (trf_has(trap->flags, TRF_TRAP)) break; trap = trap->next; } if (!trap) return false; /* Get the base disarming skill */ if (trf_has(trap->flags, TRF_MAGICAL)) skill = player->state.skills[SKILL_DISARM_MAGIC]; else skill = player->state.skills[SKILL_DISARM_PHYS]; /* Penalize some conditions */ if (player->timed[TMD_BLIND] || no_light() || player->timed[TMD_CONFUSED] || player->timed[TMD_IMAGE]) skill = skill / 10; /* Extract trap power */ power = cave->depth / 5; /* Extract the percentage success */ chance = skill - power; /* Always have a small chance of success */ if (chance < 2) chance = 2; /* Two chances - one to disarm, one not to set the trap off */ if (randint0(100) < chance) { msgt(MSG_DISARM, "You have disarmed the %s.", trap->kind->name); player_exp_gain(player, power); /* Trap is gone */ square_forget(cave, y, x); square_destroy_trap(cave, y, x); } else if (randint0(100) < chance) { event_signal(EVENT_INPUT_FLUSH); msg("You failed to disarm the %s.", trap->kind->name); /* Player can try again */ more = true; } else { msg("You set off the %s!", trap->kind->name); hit_trap(y, x); } /* Result */ return (more); }
/* Destroy Doors (and traps) */ static void project_feature_handler_KILL_DOOR(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Destroy all doors and traps */ if (square_isplayertrap(cave, y, x) || square_isdoor(cave, y, x)) { /* Check line of sight */ if (square_isview(cave, y, x)) { /* Message */ msg("There is a bright flash of light!"); context->obvious = true; /* Visibility change */ if (square_isdoor(cave, y, x)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Forget the door */ square_forget(cave, y, x); } /* Destroy the feature */ if (square_isdoor(cave, y, x)) square_destroy_door(cave, y, x); else square_destroy_trap(cave, y, x); } }
/** * This routine will "darken" all grids in the set passed in. * * In addition, some of these grids will be "unmarked". * * This routine is used (only) by "light_room()" */ static void cave_unlight(struct point_set *ps) { int i; /* Apply flag changes */ for (i = 0; i < ps->n; i++) { int y = ps->pts[i].y; int x = ps->pts[i].x; /* Darken the grid */ if (!square_isbright(cave, y, x)) { sqinfo_off(cave->squares[y][x].info, SQUARE_GLOW); } /* Hack -- Forget "boring" grids */ if (square_isfloor(cave, y, x)) square_forget(cave, y, x); } /* Process the grids */ for (i = 0; i < ps->n; i++) { int y = ps->pts[i].y; int x = ps->pts[i].x; /* Redraw the grid */ square_light_spot(cave, y, x); } }
/** * Light or Darken the town */ void cave_illuminate(struct chunk *c, bool daytime) { int y, x, i; /* Apply light or darkness */ for (y = 0; y < c->height; y++) { for (x = 0; x < c->width; x++) { int d; bool light = false; /* Skip grids with no surrounding floors or stairs */ for (d = 0; d < 9; d++) { /* Extract adjacent (legal) location */ int yy = y + ddy_ddd[d]; int xx = x + ddx_ddd[d]; /* Paranoia */ if (!square_in_bounds_fully(c, yy, xx)) continue; /* Test */ if (square_isfloor(c, yy, xx) || square_isstairs(c, yy, xx)) light = true; } if (!light) continue; /* Only interesting grids at night */ if (daytime || !square_isfloor(c, y, x)) { sqinfo_on(c->squares[y][x].info, SQUARE_GLOW); square_memorize(c, y, x); } else if (!square_isbright(c, y, x)) { sqinfo_off(c->squares[y][x].info, SQUARE_GLOW); square_forget(c, y, x); } } } /* Light shop doorways */ for (y = 0; y < c->height; y++) { for (x = 0; x < c->width; x++) { if (!square_isshop(c, y, x)) continue; for (i = 0; i < 8; i++) { int yy = y + ddy_ddd[i]; int xx = x + ddx_ddd[i]; sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW); square_memorize(c, yy, xx); } } } /* Fully update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw map, monster list */ player->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST); }
/** * Light up the dungeon using "claravoyance" * * This function "illuminates" every grid in the dungeon, memorizes all * "objects" (or notes the existence of an object "if" full is true), * and memorizes all grids as with magic mapping. */ void wiz_light(struct chunk *c, struct player *p, bool full) { int i, y, x; /* Scan all grids */ for (y = 1; y < c->height - 1; y++) { for (x = 1; x < c->width - 1; x++) { /* Process all non-walls */ if (!square_seemslikewall(c, y, x)) { if (!square_in_bounds_fully(c, y, x)) continue; /* Scan all neighbors */ for (i = 0; i < 9; i++) { int yy = y + ddy_ddd[i]; int xx = x + ddx_ddd[i]; /* Perma-light the grid */ sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW); /* Memorize normal features */ if (!square_isfloor(c, yy, xx) || square_isvisibletrap(c, yy, xx)) { square_memorize(c, yy, xx); square_mark(c, yy, xx); } } } /* Memorize objects */ if (full) { square_know_pile(c, y, x); } else { square_sense_pile(c, y, x); } /* Forget unprocessed, unknown grids in the mapping area */ if (!square_ismark(c, y, x) && square_isnotknown(c, y, x)) square_forget(c, y, x); } } /* Unmark grids */ for (y = 1; y < c->height - 1; y++) { for (x = 1; x < c->width - 1; x++) { if (!square_in_bounds(c, y, x)) continue; square_unmark(c, y, x); } } /* Fully update the visuals */ p->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw whole map, monster list */ p->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST); }
/** * Tunnel through wall. Assumes valid location. * * Note that it is impossible to "extend" rooms past their * outer walls (which are actually part of the room). * * Attempting to do so will produce floor grids which are not part * of the room, and whose "illumination" status do not change with * the rest of the room. */ static bool twall(int y, int x) { /* Paranoia -- Require a wall or door or some such */ if (!(square_isdiggable(cave, y, x) || square_iscloseddoor(cave, y, x))) return (false); /* Sound */ sound(MSG_DIG); /* Forget the wall */ square_forget(cave, y, x); /* Remove the feature */ square_tunnel_wall(cave, y, x); /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Fully update the flow */ player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW); /* Result */ return (true); }
/** * Try to break a glyph. */ static bool process_monster_glyph(struct chunk *c, struct monster *mon, int nx, int ny) { assert(square_iswarded(c, ny, nx)); /* Break the ward */ if (randint1(z_info->glyph_hardness) < mon->race->level) { /* Describe observable breakage */ if (square_isseen(c, ny, nx)) { msg("The rune of protection is broken!"); /* Forget the rune */ square_forget(c, ny, nx); } /* Break the rune */ square_remove_ward(c, ny, nx); return true; } /* Unbroken ward - can't move */ return false; }
/* Destroy walls (and doors) */ static void project_feature_handler_KILL_WALL(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Non-walls (etc) */ if (square_ispassable(cave, y, x)) return; /* Permanent walls */ if (square_isperm(cave, y, x)) return; /* Different treatment for different walls */ if (square_iswall(cave, y, x) && !square_hasgoldvein(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The wall turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); } else if (square_iswall(cave, y, x) && square_hasgoldvein(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The vein turns into mud!"); msg("You have found something!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); /* Place some gold */ place_gold(cave, y, x, player->depth, ORIGIN_FLOOR); } else if (square_ismagma(cave, y, x) || square_isquartz(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The vein turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); } else if (square_isrubble(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The rubble turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the rubble */ square_destroy_rubble(cave, y, x); /* Hack -- place an object */ if (randint0(100) < 10){ if (square_isseen(cave, y, x)) { msg("There was something buried in the rubble!"); context->obvious = true; } place_object(cave, y, x, player->depth, false, false, ORIGIN_RUBBLE, 0); } } else if (square_isdoor(cave, y, x)) { /* Hack -- special message */ if (square_isseen(cave, y, x)) { msg("The door turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the feature */ square_destroy_door(cave, y, x); } /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Fully update the flow */ player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW); }
/** * Perform the basic "disarm" command * * Assume there is no monster blocking the destination * * Returns true if repeated commands may continue */ static bool do_cmd_disarm_aux(int y, int x) { int i, j, power; struct trap *trap = cave->squares[y][x].trap; bool more = false; /* Verify legality */ if (!do_cmd_disarm_test(y, x)) return (false); /* Choose first player trap */ while (trap) { if (trf_has(trap->flags, TRF_TRAP)) break; trap = trap->next; } if (!trap) return false; /* Get the "disarm" factor */ i = player->state.skills[SKILL_DISARM]; /* Penalize some conditions */ if (player->timed[TMD_BLIND] || no_light()) i = i / 10; if (player->timed[TMD_CONFUSED] || player->timed[TMD_IMAGE]) i = i / 10; /* XXX XXX XXX Variable power? */ /* Extract trap "power" */ power = 5; /* Extract the difficulty */ j = i - power; /* Always have a small chance of success */ if (j < 2) j = 2; /* Success */ if (randint0(100) < j) { /* Message */ msgt(MSG_DISARM, "You have disarmed the %s.", trap->kind->name); /* Reward */ player_exp_gain(player, power); /* Forget the trap */ square_forget(cave, y, x); /* Remove the trap */ square_destroy_trap(cave, y, x); } else if ((i > 5) && (randint1(i) > 5)) { /* Failure -- Keep trying */ event_signal(EVENT_INPUT_FLUSH); msg("You failed to disarm the %s.", trap->kind->name); more = true; } else { /* Failure -- Set off the trap */ msg("You set off the %s!", trap->kind->name); hit_trap(y, x); } /* Result */ return (more); }
/** * Hit a trap. */ extern void hit_trap(int y, int x) { bool ident = false; struct trap *trap; struct effect *effect; /* Count the hidden traps here */ int num = num_traps(cave, y, x, -1); /* The player is safe from all traps */ if (player_is_trapsafe(player)) return; /* Oops. We've walked right into trouble. */ if (num == 1) msg("You stumble upon a trap!"); else if (num > 1) msg("You stumble upon some traps!"); /* Look at the traps in this grid */ for (trap = square_trap(cave, y, x); trap; trap = trap->next) { int flag; bool saved = false; /* Require that trap be capable of affecting the character */ if (!trf_has(trap->kind->flags, TRF_TRAP)) continue; if (trap->timeout) continue; /* Disturb the player */ disturb(player, 0); /* Give a message */ if (trap->kind->msg) msg(trap->kind->msg); /* Test for save due to flag */ for (flag = of_next(trap->kind->save_flags, FLAG_START); flag != FLAG_END; flag = of_next(trap->kind->save_flags, flag + 1)) if (player_of_has(player, flag)) { saved = true; equip_learn_flag(player, flag); } /* Test for save due to armor */ if (trf_has(trap->kind->flags, TRF_SAVE_ARMOR) && !trap_check_hit(125)) saved = true; /* Test for save due to saving throw */ if (trf_has(trap->kind->flags, TRF_SAVE_THROW) && (randint0(100) < player->state.skills[SKILL_SAVE])) saved = true; /* Save, or fire off the trap */ if (saved) { if (trap->kind->msg_good) msg(trap->kind->msg_good); } else { if (trap->kind->msg_bad) msg(trap->kind->msg_bad); effect = trap->kind->effect; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); /* Do any extra effects */ if (trap->kind->effect_xtra && one_in_(2)) { if (trap->kind->msg_xtra) msg(trap->kind->msg_xtra); effect = trap->kind->effect_xtra; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); } } /* Some traps drop you a dungeon level */ if (trf_has(trap->kind->flags, TRF_DOWN)) dungeon_change_level(player, dungeon_get_next_level(player->depth, 1)); /* Some traps drop you onto them */ if (trf_has(trap->kind->flags, TRF_PIT)) monster_swap(player->py, player->px, trap->fy, trap->fx); /* Some traps disappear after activating, all have a chance to */ if (trf_has(trap->kind->flags, TRF_ONETIME) || one_in_(3)) { square_destroy_trap(cave, y, x); square_forget(cave, y, x); } /* Trap may have gone */ if (!square_trap(cave, y, x)) break; /* Trap becomes visible (always XXX) */ trf_on(trap->flags, TRF_VISIBLE); square_memorize(cave, y, x); } /* Verify traps (remove marker if appropriate) */ (void)square_verify_trap(cave, y, x, 0); }