/** * 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; }
/** * 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); }
/** * Get the graphics of a listed trap. * * We should probably have better handling of stacked traps, but that can * wait until we do, in fact, have stacked traps under normal conditions. */ static void get_trap_graphics(struct chunk *c, grid_data *g, int *a, wchar_t *w) { /* Trap is visible */ if (trf_has(g->trap->flags, TRF_VISIBLE) || trf_has(g->trap->flags, TRF_RUNE)) { /* Get the graphics */ *a = trap_x_attr[g->lighting][g->trap->kind->tidx]; *w = trap_x_char[g->lighting][g->trap->kind->tidx]; } }
/** * 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 = c->squares[y][x].trap; /* 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); sqinfo_on(c->squares[y][x].info, SQUARE_MARK); /* 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 */ sqinfo_on(c->squares[y][x].info, SQUARE_MARK); /* Redraw */ square_light_spot(c, y, x); } /* Return TRUE if we found any traps */ return (found_trap != 0); }
/** * Get the graphics of a listed trap. * * We should probably have better handling of stacked traps, but that can * wait until we do, in fact, have stacked traps under normal conditions. * Return true if it's a web */ static bool get_trap_graphics(struct chunk *c, struct grid_data *g, int *a, wchar_t *w) { /* Trap is visible */ if (trf_has(g->trap->flags, TRF_VISIBLE) || trf_has(g->trap->flags, TRF_GLYPH) || trf_has(g->trap->flags, TRF_WEB)) { /* Get the graphics */ *a = trap_x_attr[g->lighting][g->trap->kind->tidx]; *w = trap_x_char[g->lighting][g->trap->kind->tidx]; } return trf_has(g->trap->flags, TRF_WEB); }
/** * Instantiate a player trap */ static int pick_trap(int feat, int trap_level) { int trap_index = 0; feature_type *f_ptr = &f_info[feat]; struct trap_kind *kind; bool trap_is_okay = FALSE; /* Paranoia */ if (!tf_has(f_ptr->flags, TF_TRAP)) return -1; /* Try to create a trap appropriate to the level. Make certain that at * least one trap type can be made on any possible level. -LM- */ while (!trap_is_okay) { /* Pick at random. */ trap_index = randint0(z_info->trap_max); /* Get this trap */ kind = &trap_info[trap_index]; /* Ensure that this is a player trap */ if (!kind->name) continue; if (!trf_has(kind->flags, TRF_TRAP)) continue; /* Require that trap_level not be too low */ if (kind->min_depth > trap_level) continue; /* Assume legal until proven otherwise. */ trap_is_okay = TRUE; /* Floor? */ if (tf_has(f_ptr->flags, TF_FLOOR) && !trf_has(kind->flags, TRF_FLOOR)) trap_is_okay = FALSE; /* Check legality of trapdoors. */ if (trf_has(kind->flags, TRF_DOWN)) { /* No trap doors on quest levels */ if (is_quest(player->depth)) trap_is_okay = FALSE; /* No trap doors on the deepest level */ if (player->depth >= z_info->max_depth - 1) trap_is_okay = FALSE; } } /* Return our chosen trap */ return (trap_index); }
/** * 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 = cave->squares[y][x].trap; 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, &ident, FALSE, 0, 0, 0); /* Trap becomes visible (always XXX) */ trf_on(trap->flags, TRF_VISIBLE); sqinfo_on(cave->squares[y][x].info, SQUARE_MARK); } /* Verify traps (remove marker if appropriate) */ (void)square_verify_trap(cave, y, x, 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 = c->squares[y][x].trap; 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); }
/** * Remove a trap */ static void remove_trap_aux(struct chunk *c, struct trap *trap, int y, int x, bool domsg) { /* We are deleting a rune */ if (trf_has(trap->flags, TRF_RUNE)) { if (domsg) msg("You have removed the %s.", trap->kind->name); } else if (domsg) /* We are disarming a trap */ msgt(MSG_DISARM, "You have disarmed the %s.", trap->kind->name); /* Wipe the trap */ mem_free(trap); }
/** * 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 = c->squares[y][x].trap; 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); /* No reason to mark this square, ... */ sqinfo_off(c->squares[y][x].info, SQUARE_MARK); /* ... unless certain conditions apply */ square_note_spot(c, y, x); } /* Report failure */ return FALSE; }
/** * 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 = c->squares[y][x].trap; /* 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; }
/** * Remove a trap */ static void remove_trap_aux(struct chunk *c, struct trap *trap, int y, int x, bool domsg) { /* Message if needed */ if (domsg) { /* We are deleting a rune */ if (trf_has(trap->flags, TRF_RUNE)) { if (c->mon_current < 0) { /* Removed by player */ msg("You have removed the %s.", trap->kind->name); } } else { /* We are disarming a trap */ msgt(MSG_DISARM, "You have disarmed the %s.", trap->kind->name); } } /* Wipe the trap */ mem_free(trap); }
/** * Instantiate a player trap */ static int pick_trap(struct chunk *c, int feat, int trap_level) { int i, pick; int *trap_probs = NULL; int trap_prob_max = 0; /* Paranoia */ if (!feat_is_trap_holding(feat)) return -1; /* No traps in town */ if (c->depth == 0) return -1; /* Get trap probabilities */ trap_probs = mem_zalloc(z_info->trap_max * sizeof(int)); for (i = 0; i < z_info->trap_max; i++) { /* Get this trap */ struct trap_kind *kind = &trap_info[i]; trap_probs[i] = trap_prob_max; /* Ensure that this is a valid player trap */ if (!kind->name) continue; if (!kind->rarity) continue; if (!trf_has(kind->flags, TRF_TRAP)) continue; /* Require that trap_level not be too low */ if (kind->min_depth > trap_level) continue; /* Floor? */ if (feat_is_floor(feat) && !trf_has(kind->flags, TRF_FLOOR)) continue; /* Check legality of trapdoors. */ if (trf_has(kind->flags, TRF_DOWN)) { /* No trap doors on quest levels */ if (is_quest(player->depth)) continue; /* No trap doors on the deepest level */ if (player->depth >= z_info->max_depth - 1) continue; /* No trap doors with persistent levels (for now) */ if (OPT(player, birth_levels_persist)) continue; } /* Trap is okay, store the cumulative probability */ trap_probs[i] += (100 / kind->rarity); trap_prob_max = trap_probs[i]; } /* No valid trap */ if (trap_prob_max == 0) { mem_free(trap_probs); return -1; } /* Pick at random. */ pick = randint0(trap_prob_max); for (i = 0; i < z_info->trap_max; i++) { if (pick < trap_probs[i]) { break; } } mem_free(trap_probs); /* Return our chosen trap */ return i < z_info->trap_max ? i : -1; }
/** * This function takes a grid location (x, y) and extracts information the * player is allowed to know about it, filling in the grid_data structure * passed in 'g'. * * The information filled in is as follows: * - g->f_idx is filled in with the terrain's feature type, or FEAT_NONE * if the player doesn't know anything about the grid. The function * makes use of the "mimic" field in terrain in order to allow one * feature to look like another (hiding secret doors, invisible traps, * etc). This will return the terrain type the player "Knows" about, * not necessarily the real terrain. * - g->m_idx is set to the monster index, or 0 if there is none (or the * player doesn't know it). * - g->first_kind is set to the object_kind of the first object in a grid * that the player knows about, or NULL for no objects. * - g->muliple_objects is TRUE if there is more than one object in the * grid that the player knows and cares about (to facilitate any special * floor stack symbol that might be used). * - g->in_view is TRUE if the player can currently see the grid - this can * be used to indicate field-of-view, such as through the OPT(view_bright_light) * option. * - g->lighting is set to indicate the lighting level for the grid: * LIGHTING_DARK for unlit grids, LIGHTING_LIT for inherently light * grids (lit rooms, etc), LIGHTING_TORCH for grids lit by the player's * light source, and LIGHTING_LOS for grids in the player's line of sight. * Note that lighting is always LIGHTING_LIT for known "interesting" grids * like walls. * - g->is_player is TRUE if the player is on the given grid. * - g->hallucinate is TRUE if the player is hallucinating something "strange" * for this grid - this should pick a random monster to show if the m_idx * is non-zero, and a random object if first_kind is non-zero. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * Terrain is remembered separately from objects and monsters, so can be * shown even when the player can't "see" it. This leads to things like * doors out of the player's view still change from closed to open and so on. * * TODO: * Hallucination is currently disabled (it was a display-level hack before, * and we need it to be a knowledge-level hack). The idea is that objects * may turn into different objects, monsters into different monsters, and * terrain may be objects, monsters, or stay the same. */ void map_info(unsigned y, unsigned x, grid_data *g) { object_type *obj; assert(x < (unsigned) cave->width); assert(y < (unsigned) cave->height); /* Default "clear" values, others will be set later where appropriate. */ g->first_kind = NULL; g->trap = NULL; g->multiple_objects = FALSE; g->lighting = LIGHTING_DARK; g->unseen_object = FALSE; g->unseen_money = FALSE; /* Use real feature (remove later) */ g->f_idx = cave->squares[y][x].feat; if (f_info[g->f_idx].mimic) g->f_idx = f_info[g->f_idx].mimic; g->in_view = (square_isseen(cave, y, x)) ? TRUE : FALSE; g->is_player = (cave->squares[y][x].mon < 0) ? TRUE : FALSE; g->m_idx = (g->is_player) ? 0 : cave->squares[y][x].mon; g->hallucinate = player->timed[TMD_IMAGE] ? TRUE : FALSE; g->trapborder = (square_isdedge(cave, y, x)) ? TRUE : FALSE; if (g->in_view) { g->lighting = LIGHTING_LOS; if (!square_isglow(cave, y, x) && OPT(view_yellow_light)) g->lighting = LIGHTING_TORCH; /* Remember seen feature */ cave_k->squares[y][x].feat = cave->squares[y][x].feat; } else if (!square_ismark(cave, y, x)) { g->f_idx = FEAT_NONE; //cave_k->squares[y][x].feat = FEAT_NONE; } else if (square_isglow(cave, y, x)) { g->lighting = LIGHTING_LIT; } /* Use known feature */ /* g->f_idx = cave_k->squares[y][x].feat; if (f_info[g->f_idx].mimic) g->f_idx = f_info[g->f_idx].mimic;*/ /* There is a trap in this square */ if (square_istrap(cave, y, x) && square_ismark(cave, y, x)) { struct trap *trap = cave->squares[y][x].trap; /* Scan the square trap list */ while (trap) { if (trf_has(trap->flags, TRF_TRAP) || trf_has(trap->flags, TRF_RUNE)) { /* Accept the trap */ g->trap = trap; break; } trap = trap->next; } } /* Objects */ for (obj = square_object(cave, y, x); obj; obj = obj->next) { if (obj->marked == MARK_AWARE) { /* Distinguish between unseen money and objects */ if (tval_is_money(obj)) { g->unseen_money = TRUE; } else { g->unseen_object = TRUE; } } else if (obj->marked == MARK_SEEN && !ignore_item_ok(obj)) { if (!g->first_kind) { g->first_kind = obj->kind; } else { g->multiple_objects = TRUE; break; } } } /* Monsters */ if (g->m_idx > 0) { /* If the monster isn't "visible", make sure we don't list it.*/ monster_type *m_ptr = cave_monster(cave, g->m_idx); if (!mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) g->m_idx = 0; } /* Rare random hallucination on non-outer walls */ if (g->hallucinate && g->m_idx == 0 && g->first_kind == 0) { if (one_in_(128) && (int) g->f_idx != FEAT_PERM) g->m_idx = 1; else if (one_in_(128) && (int) g->f_idx != FEAT_PERM) /* if hallucinating, we just need first_kind to not be NULL */ g->first_kind = k_info; else g->hallucinate = FALSE; } assert((int) g->f_idx <= FEAT_PASS_RUBBLE); if (!g->hallucinate) assert((int)g->m_idx < cave->mon_max); /* All other g fields are 'flags', mostly booleans. */ }
/** * 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); }
/** * 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); }
/** * This function takes a grid location (x, y) and extracts information the * player is allowed to know about it, filling in the grid_data structure * passed in 'g'. * * The information filled in is as follows: * - g->f_idx is filled in with the terrain's feature type, or FEAT_NONE * if the player doesn't know anything about the grid. The function * makes use of the "mimic" field in terrain in order to allow one * feature to look like another (hiding secret doors, invisible traps, * etc). This will return the terrain type the player "Knows" about, * not necessarily the real terrain. * - g->m_idx is set to the monster index, or 0 if there is none (or the * player doesn't know it). * - g->first_kind is set to the object_kind of the first object in a grid * that the player knows about, or NULL for no objects. * - g->muliple_objects is true if there is more than one object in the * grid that the player knows and cares about (to facilitate any special * floor stack symbol that might be used). * - g->in_view is true if the player can currently see the grid - this can * be used to indicate field-of-view, such as through the * OPT(player, view_bright_light) option. * - g->lighting is set to indicate the lighting level for the grid: * LIGHTING_DARK for unlit grids, LIGHTING_LIT for inherently light * grids (lit rooms, etc), LIGHTING_TORCH for grids lit by the player's * light source, and LIGHTING_LOS for grids in the player's line of sight. * Note that lighting is always LIGHTING_LIT for known "interesting" grids * like walls. * - g->is_player is true if the player is on the given grid. * - g->hallucinate is true if the player is hallucinating something "strange" * for this grid - this should pick a random monster to show if the m_idx * is non-zero, and a random object if first_kind is non-zero. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * Terrain is remembered separately from objects and monsters, so can be * shown even when the player can't "see" it. This leads to things like * doors out of the player's view still change from closed to open and so on. * * TODO: * Hallucination is currently disabled (it was a display-level hack before, * and we need it to be a knowledge-level hack). The idea is that objects * may turn into different objects, monsters into different monsters, and * terrain may be objects, monsters, or stay the same. */ void map_info(unsigned y, unsigned x, struct grid_data *g) { struct object *obj; assert(x < (unsigned) cave->width); assert(y < (unsigned) cave->height); /* Default "clear" values, others will be set later where appropriate. */ g->first_kind = NULL; g->trap = NULL; g->multiple_objects = false; g->lighting = LIGHTING_DARK; g->unseen_object = false; g->unseen_money = false; /* Use real feature (remove later) */ g->f_idx = cave->squares[y][x].feat; if (f_info[g->f_idx].mimic) g->f_idx = lookup_feat(f_info[g->f_idx].mimic); g->in_view = (square_isseen(cave, y, x)) ? true : false; g->is_player = (cave->squares[y][x].mon < 0) ? true : false; g->m_idx = (g->is_player) ? 0 : cave->squares[y][x].mon; g->hallucinate = player->timed[TMD_IMAGE] ? true : false; if (g->in_view) { g->lighting = LIGHTING_LOS; if (!square_isglow(cave, y, x) && OPT(player, view_yellow_light)) g->lighting = LIGHTING_TORCH; /* Remember seen feature */ square_memorize(cave, y, x); } else if (!square_isknown(cave, y, x)) { g->f_idx = FEAT_NONE; } else if (square_isglow(cave, y, x)) { g->lighting = LIGHTING_LIT; } /* Use known feature */ g->f_idx = player->cave->squares[y][x].feat; if (f_info[g->f_idx].mimic) g->f_idx = lookup_feat(f_info[g->f_idx].mimic); /* There is a trap in this square */ if (square_istrap(cave, y, x) && square_isknown(cave, y, x)) { struct trap *trap = cave->squares[y][x].trap; /* Scan the square trap list */ while (trap) { if (trf_has(trap->flags, TRF_TRAP) || trf_has(trap->flags, TRF_RUNE)) { /* Accept the trap - only if not disabled, maybe we need * a special graphic for this */ if (!trap->timeout) { g->trap = trap; break; } } trap = trap->next; } } /* Objects */ for (obj = square_object(player->cave, y, x); obj; obj = obj->next) { if (obj->kind == unknown_gold_kind) { g->unseen_money = true; } else if (obj->kind == unknown_item_kind) { g->unseen_object = true; } else if (ignore_known_item_ok(obj)) { /* Item stays hidden */ } else if (!g->first_kind) { g->first_kind = obj->kind; } else { g->multiple_objects = true; break; } } /* Monsters */ if (g->m_idx > 0) { /* If the monster isn't "visible", make sure we don't list it.*/ struct monster *mon = cave_monster(cave, g->m_idx); if (!monster_is_visible(mon)) g->m_idx = 0; } /* Rare random hallucination on non-outer walls */ if (g->hallucinate && g->m_idx == 0 && g->first_kind == 0) { if (one_in_(128) && (int) g->f_idx != FEAT_PERM) g->m_idx = 1; else if (one_in_(128) && (int) g->f_idx != FEAT_PERM) /* if hallucinating, we just need first_kind to not be NULL */ g->first_kind = k_info; else g->hallucinate = false; } assert((int) g->f_idx <= FEAT_PASS_RUBBLE); if (!g->hallucinate) assert((int)g->m_idx < cave->mon_max); /* All other g fields are 'flags', mostly booleans. */ }