/** * Make a new trap of the given type. Return true if successful. * * We choose a player trap at random if the index is not legal. This means that * things which are not player traps must be picked by passing a valid index. * * This should be the only function that places traps in the dungeon * except the savefile loading code. */ void place_trap(struct chunk *c, int y, int x, int t_idx, int trap_level) { struct trap *new_trap; /* We've been called with an illegal index; choose a random trap */ if ((t_idx <= 0) || (t_idx >= z_info->trap_max)) { /* Require the correct terrain */ if (!square_player_trap_allowed(c, y, x)) return; t_idx = pick_trap(c->squares[y][x].feat, trap_level); } /* Failure */ if (t_idx < 0) return; /* Allocate a new trap for this grid (at the front of the list) */ new_trap = mem_zalloc(sizeof(*new_trap)); new_trap->next = square_trap(c, y, x); c->squares[y][x].trap = new_trap; /* Set the details */ new_trap->t_idx = t_idx; new_trap->kind = &trap_info[t_idx]; new_trap->fy = y; new_trap->fx = x; trf_copy(new_trap->flags, trap_info[t_idx].flags); /* Toggle on the trap marker */ sqinfo_on(c->squares[y][x].info, SQUARE_TRAP); /* Redraw the grid */ square_light_spot(c, y, x); }
/** * Determine if a trap actually exists in this square. * * Called with vis = 0 to accept any trap, = 1 to accept only visible * traps, and = -1 to accept only invisible traps. * * Clear the SQUARE_TRAP flag if none exist. */ static bool square_verify_trap(struct chunk *c, int y, int x, int vis) { struct trap *trap = square_trap(c, y, x); bool trap_exists = false; /* Scan the square trap list */ while (trap) { /* Accept any trap */ if (!vis) return true; /* Accept traps that match visibility requirements */ if ((vis == 1) && trf_has(trap->flags, TRF_VISIBLE)) return true; if ((vis == -1) && !trf_has(trap->flags, TRF_VISIBLE)) return true; /* Note that a trap does exist */ trap_exists = true; } /* No traps in this location. */ if (!trap_exists) { /* No traps */ sqinfo_off(c->squares[y][x].info, SQUARE_TRAP); /* Take note */ square_note_spot(c, y, x); } /* Report failure */ return false; }
/** * Free memory for all traps on a grid */ void square_free_trap(struct chunk *c, int y, int x) { struct trap *next, *trap = square_trap(c, y, x); while (trap) { next = trap->next; mem_free(trap); trap = next; } }
/** * Reveal some of the player traps in a square */ bool square_reveal_trap(struct chunk *c, int y, int x, bool always, bool domsg) { int found_trap = 0; struct trap *trap = square_trap(c, y, x); /* Check there is a player trap */ if (!square_isplayertrap(c, y, x)) return false; /* Scan the grid */ while (trap) { /* Skip non-player traps */ if (!trf_has(trap->flags, TRF_TRAP)) { trap = trap->next; continue; } /* Skip traps the player doesn't notice */ if (!always && player->state.skills[SKILL_SEARCH] < trap->power) { trap = trap->next; continue; } /* Trap is invisible */ if (!trf_has(trap->flags, TRF_VISIBLE)) { /* See the trap */ trf_on(trap->flags, TRF_VISIBLE); square_memorize(c, y, x); /* We found a trap */ found_trap++; } trap = trap->next; } /* We found at least one trap */ if (found_trap) { /* We want to talk about it */ if (domsg) { if (found_trap == 1) msg("You have found a trap."); else msg("You have found %d traps.", found_trap); } /* Memorize */ square_memorize(c, y, x); /* Redraw */ square_light_spot(c, y, x); } /* Return true if we found any traps */ return (found_trap != 0); }
/** * Reveal some of the player traps in a square */ bool square_reveal_trap(struct chunk *c, int y, int x, int chance, bool domsg) { int found_trap = 0; struct trap *trap = square_trap(c, y, x); /* Check there is a player trap */ if (!square_isplayertrap(c, y, x)) return false; /* Scan the grid */ while (trap) { /* Skip non-player traps */ if (!trf_has(trap->flags, TRF_TRAP)) { trap = trap->next; continue; } /* Trap is invisible */ if (!trf_has(trap->flags, TRF_VISIBLE)) { /* See the trap */ trf_on(trap->flags, TRF_VISIBLE); square_memorize(c, y, x); /* We found a trap */ found_trap++; /* If chance is < 100, check for further looking */ if ((chance < 100) && (randint1(100) > chance)) break; } trap = trap->next; } /* We found at least one trap */ if (found_trap) { /* We want to talk about it */ if (domsg) { if (found_trap == 1) msg("You have found a trap."); else msg("You have found %d traps.", found_trap); } /* Memorize */ square_memorize(c, y, x); /* Redraw */ square_light_spot(c, y, x); } /* Return true if we found any traps */ return (found_trap != 0); }
/** * Hit a trap. */ extern void hit_trap(int y, int x) { bool ident; struct trap *trap; struct effect *effect; /* Count the hidden traps here */ int num = num_traps(cave, y, x, -1); /* 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) { /* Require that trap be capable of affecting the character */ if (!trf_has(trap->kind->flags, TRF_TRAP)) continue; /* Disturb the player */ disturb(player, 0); /* Fire off the trap */ effect = trap->kind->effect; effect_do(effect, NULL, &ident, false, 0, 0, 0); /* 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); }
/** * Is there a trap with a given flag in this square? */ bool square_trap_flag(struct chunk *c, int y, int x, int flag) { struct trap *trap = square_trap(c, y, x); /* First, check the trap marker */ if (!square_istrap(c, y, x)) return false; /* Scan the square trap list */ while (trap) { /* We found a trap with the right flag */ if (trf_has(trap->flags, flag)) return true; trap = trap->next; } /* Report failure */ return false; }
/** * Is there a specific kind of trap in this square? */ bool square_trap_specific(struct chunk *c, int y, int x, int t_idx) { struct trap *trap = square_trap(c, y, x); /* First, check the trap marker */ if (!square_istrap(c, y, x)) return false; /* Scan the square trap list */ while (trap) { /* We found a trap of the right kind */ if (trap->t_idx == t_idx) return true; trap = trap->next; } /* Report failure */ return false; }
/** * Lock a closed door to a given power */ void square_set_door_lock(struct chunk *c, int y, int x, int power) { struct trap_kind *lock = lookup_trap("door lock"); struct trap *trap; /* Verify it's a closed door */ if (!square_iscloseddoor(c, y, x)) return; /* If there's no lock there, add one */ if (!square_trap_specific(c, y, x, lock->tidx)) place_trap(c, y, x, lock->tidx, 0); /* Set the power (of all locks - there should be only one) */ trap = square_trap(c, y, x); while (trap) { if (trap->kind == lock) trap->xtra = power; trap = trap->next; } }
/** * Return the power of the lock on a door */ int square_door_power(struct chunk *c, int y, int x) { struct trap_kind *lock = lookup_trap("door lock"); struct trap *trap; /* Verify it's a closed door */ if (!square_iscloseddoor(c, y, x)) return 0; /* Is there a lock there? */ if (!square_trap_specific(c, y, x, lock->tidx)) return 0; /* Get the power and return it */ trap = square_trap(c, y, x); while (trap) { if (trap->kind == lock) return trap->xtra; trap = trap->next; } return 0; }
/** * Count the number of player traps in this location. * * Called with vis = 0 to accept any trap, = 1 to accept only visible * traps, and = -1 to accept only invisible traps. */ int num_traps(struct chunk *c, int y, int x, int vis) { int num = 0; struct trap *trap; /* Look at the traps in this grid */ for (trap = square_trap(c, y, x); trap; trap = trap->next) { /* Require that trap be capable of affecting the character */ if (!trf_has(trap->kind->flags, TRF_TRAP)) continue; /* Require correct visibility */ if (vis >= 1) { if (trf_has(trap->flags, TRF_VISIBLE)) num++; } else if (vis <= -1) { if (!trf_has(trap->flags, TRF_VISIBLE)) num++; } else { num++; } } /* Return the number of traps */ return (num); }
/** * 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); }