/* * Determine if a given grid may be "walked" */ static bool do_cmd_walk_test(int y, int x) { int m_idx = cave->m_idx[y][x]; /* Allow attack on visible monsters if unafraid */ if ((m_idx > 0) && (cave_monster(cave, m_idx)->ml) && !is_mimicking(m_idx)) { /* Handle player fear */ if(check_state(p_ptr, OF_AFRAID, p_ptr->state.flags)) { /* Extract monster name (or "it") */ char m_name[80]; const monster_type *m_ptr; m_ptr = cave_monster(cave, m_idx); monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name); /* Nope */ return (FALSE); } return (TRUE); } /* If we don't know the grid, allow attempts to walk into it */ if (!(cave->info[y][x] & CAVE_MARK)) return TRUE; /* Require open space */ if (!cave_floor_bold(y, x)) { /* Rubble */ if (cave->feat[y][x] == FEAT_RUBBLE) msgt(MSG_HITWALL, "There is a pile of rubble in the way!"); /* Door */ else if (cave->feat[y][x] < FEAT_SECRET) return TRUE; /* Wall */ else msgt(MSG_HITWALL, "There is a wall in the way!"); /* Cancel repeat */ disturb(p_ptr, 0, 0); /* Nope */ return (FALSE); } /* Okay */ return (TRUE); }
/** * Determine if a given grid may be "walked" */ static bool do_cmd_walk_test(int y, int x) { int m_idx = cave->squares[y][x].mon; struct monster *mon = cave_monster(cave, m_idx); /* Allow attack on visible monsters if unafraid */ if (m_idx > 0 && mflag_has(mon->mflag, MFLAG_VISIBLE) && !is_mimicking(mon)) { /* Handle player fear */ if (player_of_has(player, OF_AFRAID)) { /* Extract monster name (or "it") */ char m_name[80]; monster_desc(m_name, sizeof(m_name), mon, MDESC_DEFAULT); /* Message */ msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name); /* Nope */ return (false); } return (true); } /* If we don't know the grid, allow attempts to walk into it */ if (!square_isknown(cave, y, x)) return true; /* Require open space */ if (!square_ispassable(cave, y, x)) { if (square_isrubble(cave, y, x)) /* Rubble */ msgt(MSG_HITWALL, "There is a pile of rubble in the way!"); else if (square_iscloseddoor(cave, y, x)) /* Door */ return true; else if (square_isbright(cave, y, x)) /* Lava */ msgt(MSG_HITWALL, "The heat of the lava turns you away!"); else /* Wall */ msgt(MSG_HITWALL, "There is a wall in the way!"); /* Cancel repeat */ disturb(player, 0); /* Nope */ return (false); } /* Okay */ return (true); }
/** * Try to push past / kill another monster. Returns true on success. */ static bool process_monster_try_push(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny) { struct monster *mon1 = square_monster(c, ny, nx); struct monster_lore *lore = get_lore(mon->race); /* Kill weaker monsters */ int kill_ok = rf_has(mon->race->flags, RF_KILL_BODY); /* Move weaker monsters if they can swap places */ /* (not in a wall) */ int move_ok = (rf_has(mon->race->flags, RF_MOVE_BODY) && square_ispassable(c, mon->fy, mon->fx)); if (compare_monsters(mon, mon1) > 0) { /* Learn about pushing and shoving */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { rf_on(lore->flags, RF_KILL_BODY); rf_on(lore->flags, RF_MOVE_BODY); } if (kill_ok || move_ok) { /* Get the names of the monsters involved */ char n_name[80]; monster_desc(n_name, sizeof(n_name), mon1, MDESC_IND_HID); /* Reveal mimics */ if (is_mimicking(mon1)) become_aware(mon1); /* Note if visible */ if (mflag_has(mon->mflag, MFLAG_VISIBLE) && mflag_has(mon->mflag, MFLAG_VIEW)) msg("%s %s %s.", m_name, kill_ok ? "tramples over" : "pushes past", n_name); /* Monster ate another monster */ if (kill_ok) delete_monster(ny, nx); monster_swap(mon->fy, mon->fx, ny, nx); return true; } } return false; }
/** * Move player in the given direction. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/rubble/etc. */ void move_player(int dir, bool disarm) { int y = player->py + ddy[dir]; int x = player->px + ddx[dir]; int m_idx = cave->squares[y][x].mon; struct monster *mon = cave_monster(cave, m_idx); bool alterable = (square_isknowntrap(cave, y, x) || square_iscloseddoor(cave, y, x)); /* Attack monsters, alter traps/doors on movement, hit obstacles or move */ if (m_idx > 0) { /* Mimics surprise the player */ if (is_mimicking(mon)) { become_aware(mon); /* Mimic wakes up */ mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false); } else { py_attack(y, x); } } else if (disarm && square_isknown(cave, y, x) && alterable) { /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); do_cmd_alter_aux(dir); } else if (player->upkeep->running && square_isknowntrap(cave, y, x)) { /* Stop running before known traps */ disturb(player, 0); } else if (!square_ispassable(cave, y, x)) { disturb(player, 0); /* Notice unknown obstacles, mention known obstacles */ if (!square_isknown(cave, y, x)) { if (square_isrubble(cave, y, x)) { msgt(MSG_HITWALL, "You feel a pile of rubble blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else if (square_iscloseddoor(cave, y, x)) { msgt(MSG_HITWALL, "You feel a door blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else { msgt(MSG_HITWALL, "You feel a wall blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } } else { if (square_isrubble(cave, y, x)) msgt(MSG_HITWALL, "There is a pile of rubble blocking your way."); else if (square_iscloseddoor(cave, y, x)) msgt(MSG_HITWALL, "There is a door blocking your way."); else msgt(MSG_HITWALL, "There is a wall blocking your way."); } } else { /* Move player */ monster_swap(player->py, player->px, y, x); /* Handle store doors, or notice objects */ if (square_isshop(cave, y, x)) { disturb(player, 0); event_signal(EVENT_ENTER_STORE); event_remove_handler_type(EVENT_ENTER_STORE); event_signal(EVENT_USE_STORE); event_remove_handler_type(EVENT_USE_STORE); event_signal(EVENT_LEAVE_STORE); event_remove_handler_type(EVENT_LEAVE_STORE); } else { square_know_pile(cave, y, x); cmdq_push(CMD_AUTOPICKUP); } /* Discover invisible traps, set off visible ones */ if (square_issecrettrap(cave, y, x)) { disturb(player, 0); hit_trap(y, x); } else if (square_isknowntrap(cave, y, x)) { disturb(player, 0); hit_trap(y, x); } /* Update view and search */ update_view(cave, player); search(); } player->upkeep->running_firststep = false; }
/** * Open a closed/locked/jammed door or a closed/locked chest. * * Unlocking a locked chest is worth one experience point; since doors are * player lockable, there is no experience for unlocking doors. */ void do_cmd_open(struct command *cmd) { int y, x, dir; struct object *obj; bool more = false; int err; struct monster *m; /* Get arguments */ err = cmd_get_arg_direction(cmd, "direction", &dir); if (err || dir == DIR_UNKNOWN) { int y2, x2; int n_closed_doors, n_locked_chests; n_closed_doors = count_feats(&y2, &x2, square_iscloseddoor, false); n_locked_chests = count_chests(&y2, &x2, CHEST_OPENABLE); if (n_closed_doors + n_locked_chests == 1) { dir = coords_to_dir(y2, x2); cmd_set_arg_direction(cmd, "direction", dir); } else if (cmd_get_direction(cmd, "direction", &dir, false)) { return; } } /* Get location */ y = player->py + ddy[dir]; x = player->px + ddx[dir]; /* Check for chest */ obj = chest_check(y, x, CHEST_OPENABLE); /* Check for door */ if (!obj && !do_cmd_open_test(y, x)) { /* Cancel repeat */ disturb(player, 0); return; } /* Take a turn */ player->upkeep->energy_use = z_info->move_energy; /* Apply confusion */ if (player_confuse_dir(player, &dir, false)) { /* Get location */ y = player->py + ddy[dir]; x = player->px + ddx[dir]; /* Check for chest */ obj = chest_check(y, x, CHEST_OPENABLE); } /* Monster */ m = square_monster(cave, y, x); if (m) { /* Mimics surprise the player */ if (is_mimicking(m)) { become_aware(m); /* Mimic wakes up */ mon_clear_timed(m, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false); } else { /* Message */ msg("There is a monster in the way!"); /* Attack */ py_attack(y, x); } } else if (obj) { /* Chest */ more = do_cmd_open_chest(y, x, obj); } else { /* Door */ more = do_cmd_open_aux(y, x); } /* Cancel repeat unless we may continue */ if (!more) disturb(player, 0); }
/* * Move player in the given direction. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/rubble/etc. */ void move_player(int dir, bool disarm) { int py = p_ptr->py; int px = p_ptr->px; int y = py + ddy[dir]; int x = px + ddx[dir]; int m_idx = cave->m_idx[y][x]; /* Attack monsters */ if (m_idx > 0) { /* Mimics surprise the player */ if (is_mimicking(m_idx)) { become_aware(m_idx); /* Mimic wakes up */ mon_clear_timed(m_idx, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE); } else { py_attack(y, x); } } /* Optionally alter traps/doors on movement */ else if (disarm && (cave->info[y][x] & CAVE_MARK) && (cave_isknowntrap(cave, y, x) || cave_iscloseddoor(cave, y, x))) { /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); do_cmd_alter_aux(dir); } /* Cannot walk through walls */ else if (!cave_floor_bold(y, x)) { /* Disturb the player */ disturb(p_ptr, 0, 0); /* Notice unknown obstacles */ if (!(cave->info[y][x] & CAVE_MARK)) { /* Rubble */ if (cave->feat[y][x] == FEAT_RUBBLE) { msgt(MSG_HITWALL, "You feel a pile of rubble blocking your way."); cave->info[y][x] |= (CAVE_MARK); cave_light_spot(cave, y, x); } /* Closed door */ else if (cave->feat[y][x] < FEAT_SECRET) { msgt(MSG_HITWALL, "You feel a door blocking your way."); cave->info[y][x] |= (CAVE_MARK); cave_light_spot(cave, y, x); } /* Wall (or secret door) */ else { msgt(MSG_HITWALL, "You feel a wall blocking your way."); cave->info[y][x] |= (CAVE_MARK); cave_light_spot(cave, y, x); } } /* Mention known obstacles */ else { if (cave->feat[y][x] == FEAT_RUBBLE) msgt(MSG_HITWALL, "There is a pile of rubble blocking your way."); else if (cave->feat[y][x] < FEAT_SECRET) msgt(MSG_HITWALL, "There is a door blocking your way."); else msgt(MSG_HITWALL, "There is a wall blocking your way."); } } /* Normal movement */ else { /* See if trap detection status will change */ bool old_dtrap = ((cave->info2[py][px] & (CAVE2_DTRAP)) != 0); bool new_dtrap = ((cave->info2[y][x] & (CAVE2_DTRAP)) != 0); /* Note the change in the detect status */ if (old_dtrap != new_dtrap) p_ptr->redraw |= (PR_DTRAP); /* Disturb player if the player is about to leave the area */ if (OPT(disturb_detect) && p_ptr->running && !p_ptr->running_firststep && old_dtrap && !new_dtrap) { disturb(p_ptr, 0, 0); return; } /* Move player */ monster_swap(py, px, y, x); /* New location */ y = py = p_ptr->py; x = px = p_ptr->px; /* Searching */ if (p_ptr->searching || (p_ptr->state.skills[SKILL_SEARCH_FREQUENCY] >= 50) || one_in_(50 - p_ptr->state.skills[SKILL_SEARCH_FREQUENCY])) search(FALSE); /* Handle "store doors" */ if ((cave->feat[p_ptr->py][p_ptr->px] >= FEAT_SHOP_HEAD) && (cave->feat[p_ptr->py][p_ptr->px] <= FEAT_SHOP_TAIL)) { /* Disturb */ disturb(p_ptr, 0, 0); cmd_insert(CMD_ENTER_STORE); } /* All other grids (including traps) */ else { /* Handle objects (later) */ p_ptr->notice |= (PN_PICKUP); } /* Discover invisible traps */ if (cave->feat[y][x] == FEAT_INVIS) { /* Disturb */ disturb(p_ptr, 0, 0); /* Message */ msg("You found a trap!"); /* Pick a trap */ pick_trap(y, x); /* Hit the trap */ hit_trap(y, x); } /* Set off an visible trap */ else if (cave_isknowntrap(cave, y, x)) { /* Disturb */ disturb(p_ptr, 0, 0); /* Hit the trap */ hit_trap(y, x); } } p_ptr->running_firststep = FALSE; }
/** * Process all the "live" monsters, once per game turn. * * During each game turn, we scan through the list of all the "live" monsters, * (backwards, so we can excise any "freshly dead" monsters), energizing each * monster, and allowing fully energized monsters to move, attack, pass, etc. * * This function and its children are responsible for a considerable fraction * of the processor time in normal situations, greater if the character is * resting. */ void process_monsters(struct chunk *c, int minimum_energy) { int i; int mspeed; /* Only process some things every so often */ bool regen = false; /* Regenerate hitpoints and mana every 100 game turns */ if (turn % 100 == 0) regen = true; /* Process the monsters (backwards) */ for (i = cave_monster_max(c) - 1; i >= 1; i--) { struct monster *mon; bool moving; /* Handle "leaving" */ if (player->is_dead || player->upkeep->generate_level) break; /* Get a 'live' monster */ mon = cave_monster(c, i); if (!mon->race) continue; /* Ignore monsters that have already been handled */ if (mflag_has(mon->mflag, MFLAG_HANDLED)) continue; /* Not enough energy to move yet */ if (mon->energy < minimum_energy) continue; /* Does this monster have enough energy to move? */ moving = mon->energy >= z_info->move_energy ? true : false; /* Prevent reprocessing */ mflag_on(mon->mflag, MFLAG_HANDLED); /* Handle monster regeneration if requested */ if (regen) regen_monster(mon); /* Calculate the net speed */ mspeed = mon->mspeed; if (mon->m_timed[MON_TMD_FAST]) mspeed += 10; if (mon->m_timed[MON_TMD_SLOW]) mspeed -= 10; /* Give this monster some energy */ mon->energy += turn_energy(mspeed); /* End the turn of monsters without enough energy to move */ if (!moving) continue; /* Use up "some" energy */ mon->energy -= z_info->move_energy; /* Mimics lie in wait */ if (is_mimicking(mon)) continue; /* Check if the monster is active */ if (monster_check_active(c, mon)) { /* Process timed effects - skip turn if necessary */ if (process_monster_timed(c, mon)) continue; /* Set this monster to be the current actor */ c->mon_current = i; /* Process the monster */ process_monster(c, mon); /* Monster is no longer current */ c->mon_current = -1; } } /* Update monster visibility after this */ /* XXX This may not be necessary */ player->upkeep->update |= PU_MONSTERS; }
/** * Update the current "run" path * * Return TRUE if the running should be stopped */ static bool run_test(void) { int py = player->py; int px = player->px; int prev_dir; int new_dir; int row, col; int i, max, inv; int option, option2; /* No options yet */ option = 0; option2 = 0; /* Where we came from */ prev_dir = run_old_dir; /* Range of newly adjacent grids */ max = (prev_dir & 0x01) + 1; /* Look at every newly adjacent square. */ for (i = -max; i <= max; i++) { struct object *obj; /* New direction */ new_dir = cycle[chome[prev_dir] + i]; /* New location */ row = py + ddy[new_dir]; col = px + ddx[new_dir]; /* Visible monsters abort running */ if (cave->squares[row][col].mon > 0) { monster_type *m_ptr = square_monster(cave, row, col); /* Visible monster */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) return (TRUE); } /* Visible objects abort running */ for (obj = square_object(cave, row, col); obj; obj = obj->next) /* Visible object */ if (obj->marked && !ignore_item_ok(obj)) return (TRUE); /* Assume unknown */ inv = TRUE; /* Check memorized grids */ if (square_ismark(cave, row, col)) { bool notice = square_noticeable(cave, row, col); /* Interesting feature */ if (notice) return (TRUE); /* The grid is "visible" */ inv = FALSE; } /* Analyze unknown grids and floors */ if (inv || square_ispassable(cave, row, col)) { /* Looking for open area */ if (run_open_area) { /* Nothing */ } else if (!option) { /* The first new direction. */ option = new_dir; } else if (option2) { /* Three new directions. Stop running. */ return (TRUE); } else if (option != cycle[chome[prev_dir] + i - 1]) { /* Two non-adjacent new directions. Stop running. */ return (TRUE); } else if (new_dir & 0x01) { /* Two new (adjacent) directions (case 1) */ option2 = new_dir; } else { /* Two new (adjacent) directions (case 2) */ option2 = option; option = new_dir; } } else { /* Obstacle, while looking for open area */ if (run_open_area) { if (i < 0) { /* Break to the right */ run_break_right = TRUE; } else if (i > 0) { /* Break to the left */ run_break_left = TRUE; } } } } /* Look at every soon to be newly adjacent square. */ for (i = -max; i <= max; i++) { /* New direction */ new_dir = cycle[chome[prev_dir] + i]; /* New location */ row = py + ddy[prev_dir] + ddy[new_dir]; col = px + ddx[prev_dir] + ddx[new_dir]; /* HACK: Ugh. Sometimes we come up with illegal bounds. This will * treat the symptom but not the disease. */ if (row >= cave->height || col >= cave->width) continue; if (row < 0 || col < 0) continue; /* Visible monsters abort running */ if (cave->squares[row][col].mon > 0) { monster_type *m_ptr = square_monster(cave, row, col); /* Visible monster */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE) && !is_mimicking(m_ptr)) return (TRUE); } } /* Looking for open area */ if (run_open_area) { /* Hack -- look again */ for (i = -max; i < 0; i++) { new_dir = cycle[chome[prev_dir] + i]; row = py + ddy[new_dir]; col = px + ddx[new_dir]; /* Unknown grid or non-wall */ /* Was: square_ispassable(cave, row, col) */ if (!square_ismark(cave, row, col) || (square_ispassable(cave, row, col))) { /* Looking to break right */ if (run_break_right) { return (TRUE); } } else { /* Obstacle */ /* Looking to break left */ if (run_break_left) { return (TRUE); } } } /* Hack -- look again */ for (i = max; i > 0; i--) { new_dir = cycle[chome[prev_dir] + i]; row = py + ddy[new_dir]; col = px + ddx[new_dir]; /* Unknown grid or non-wall */ /* Was: square_ispassable(cave, row, col) */ if (!square_ismark(cave, row, col) || (square_ispassable(cave, row, col))) { /* Looking to break left */ if (run_break_left) { return (TRUE); } } else { /* Obstacle */ /* Looking to break right */ if (run_break_right) { return (TRUE); } } } } else { /* Not looking for open area */ /* No options */ if (!option) { return (TRUE); } else if (!option2) { /* One option */ /* Primary option */ run_cur_dir = option; /* No other options */ run_old_dir = option; } else { /* Two options, examining corners */ /* Primary option */ run_cur_dir = option; /* Hack -- allow curving */ run_old_dir = option2; } } /* About to hit a known wall, stop */ if (see_wall(run_cur_dir, py, px)) return (TRUE); /* Failure */ return (FALSE); }
/* * Open a closed/locked/jammed door or a closed/locked chest. * * Unlocking a locked door/chest is worth one experience point. */ void do_cmd_open(cmd_code code, cmd_arg args[]) { int y, x, dir; s16b o_idx; bool more = FALSE; dir = args[0].direction; /* Get location */ y = p_ptr->py + ddy[dir]; x = p_ptr->px + ddx[dir]; /* Check for chests */ o_idx = chest_check(y, x); /* Verify legality */ if (!o_idx && !do_cmd_open_test(y, x)) { /* Cancel repeat */ disturb(p_ptr, 0, 0); return; } /* Take a turn */ p_ptr->energy_use = 100; /* Apply confusion */ if (player_confuse_dir(p_ptr, &dir, FALSE)) { /* Get location */ y = p_ptr->py + ddy[dir]; x = p_ptr->px + ddx[dir]; /* Check for chest */ o_idx = chest_check(y, x); } /* Monster */ if (cave->m_idx[y][x] > 0) { int m_idx = cave->m_idx[y][x]; /* Mimics surprise the player */ if (is_mimicking(m_idx)) { become_aware(m_idx); /* Mimic wakes up */ mon_clear_timed(m_idx, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE); } else { /* Message */ msg("There is a monster in the way!"); /* Attack */ py_attack(y, x); } } /* Chest */ else if (o_idx) { /* Open the chest */ more = do_cmd_open_chest(y, x, o_idx); } /* Door */ else { /* Open the door */ more = do_cmd_open_aux(y, x); } /* Cancel repeat unless we may continue */ if (!more) disturb(p_ptr, 0, 0); }
/** * Move player in the given direction. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/rubble/etc. */ void move_player(int dir, bool disarm) { int py = player->py; int px = player->px; int y = py + ddy[dir]; int x = px + ddx[dir]; int m_idx = cave->squares[y][x].mon; struct monster *mon = cave_monster(cave, m_idx); bool alterable = (square_isknowntrap(cave, y, x) || square_iscloseddoor(cave, y, x)); /* Attack monsters, alter traps/doors on movement, hit obstacles or move */ if (m_idx > 0) { /* Mimics surprise the player */ if (is_mimicking(mon)) { become_aware(mon); /* Mimic wakes up */ mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false); } else { py_attack(y, x); } } else if (disarm && square_isknown(cave, y, x) && alterable) { /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); do_cmd_alter_aux(dir); } else if (player->upkeep->running && square_isknowntrap(cave, y, x)) { /* Stop running before known traps */ disturb(player, 0); } else if (!square_ispassable(cave, y, x)) { /* Disturb the player */ disturb(player, 0); /* Notice unknown obstacles, mention known obstacles */ if (!square_isknown(cave, y, x)) { if (square_isrubble(cave, y, x)) { msgt(MSG_HITWALL, "You feel a pile of rubble blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else if (square_iscloseddoor(cave, y, x)) { msgt(MSG_HITWALL, "You feel a door blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else { msgt(MSG_HITWALL, "You feel a wall blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } } else { if (square_isrubble(cave, y, x)) msgt(MSG_HITWALL, "There is a pile of rubble blocking your way."); else if (square_iscloseddoor(cave, y, x)) msgt(MSG_HITWALL, "There is a door blocking your way."); else msgt(MSG_HITWALL, "There is a wall blocking your way."); } } else { /* See if trap detection status will change */ bool old_dtrap = square_isdtrap(cave, py, px); bool new_dtrap = square_isdtrap(cave, y, x); /* Note the change in the detect status */ if (old_dtrap != new_dtrap) player->upkeep->redraw |= (PR_DTRAP); /* Disturb player if the player is about to leave the area */ if (player->upkeep->running && !player->upkeep->running_firststep && old_dtrap && !new_dtrap) { disturb(player, 0); return; } /* Move player */ monster_swap(py, px, y, x); /* New location */ y = py = player->py; x = px = player->px; /* Searching */ if (player->searching || (player->state.skills[SKILL_SEARCH_FREQUENCY] >= 50) || one_in_(50 - player->state.skills[SKILL_SEARCH_FREQUENCY])) search(false); /* Handle store doors, or notice objects */ if (square_isshop(cave, player->py, player->px)) { /* Disturb */ disturb(player, 0); event_signal(EVENT_ENTER_STORE); event_remove_handler_type(EVENT_ENTER_STORE); event_signal(EVENT_USE_STORE); event_remove_handler_type(EVENT_USE_STORE); event_signal(EVENT_LEAVE_STORE); event_remove_handler_type(EVENT_LEAVE_STORE); } else { /* Know objects, queue autopickup */ floor_pile_know(cave, player->py, player->px); cmdq_push(CMD_AUTOPICKUP); } /* Discover invisible traps, set off visible ones */ if (square_issecrettrap(cave, y, x)) { /* Disturb */ disturb(player, 0); /* Hit the trap. */ hit_trap(y, x); } else if (square_isknowntrap(cave, y, x)) { /* Disturb */ disturb(player, 0); /* Hit the trap */ hit_trap(y, x); } } player->upkeep->running_firststep = false; }
/** * This function takes a pointer to a grid info struct describing the * contents of a grid location (as obtained through the function map_info) * and fills in the character and attr pairs for display. * * ap and cp are filled with the attr/char pair for the monster, object or * floor tile that is at the "top" of the grid (monsters covering objects, * which cover floor, assuming all are present). * * tap and tcp are filled with the attr/char pair for the floor, regardless * of what is on it. This can be used by graphical displays with * transparency to place an object onto a floor tile, is desired. * * Any lighting effects are also applied to these pairs, clear monsters allow * the underlying colour or feature to show through (ATTR_CLEAR and * CHAR_CLEAR), multi-hued colour-changing (ATTR_MULTI) is applied, and so on. * Technically, the flag "CHAR_MULTI" is supposed to indicate that a monster * looks strange when examined, but this flag is currently ignored. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * The "zero" entry in the feature/object/monster arrays are * used to provide "special" attr/char codes, with "monster zero" being * used for the player attr/char, "object zero" being used for the "pile" * attr/char, and "feature zero" being used for the "darkness" attr/char. * * TODO: * The transformations for tile colors, or brightness for the 16x16 * tiles should be handled differently. One possibility would be to * extend feature_type with attr/char definitions for the different states. * This will probably be done outside of the current text->graphics mappings * though. */ void grid_data_as_text(grid_data *g, int *ap, wchar_t *cp, int *tap, wchar_t *tcp) { feature_type *f_ptr = &f_info[g->f_idx]; int a = feat_x_attr[g->lighting][f_ptr->fidx]; wchar_t c = feat_x_char[g->lighting][f_ptr->fidx]; /* Check for trap detection boundaries */ if (use_graphics == GRAPHICS_NONE) grid_get_attr(g, &a); else if (g->trapborder && tf_has(f_ptr->flags, TF_FLOOR) && (g->m_idx || g->first_kind)) { /* if there is an object or monster here, and this is a plain floor * display the border here rather than an overlay below */ a = feat_x_attr[g->lighting][FEAT_DTRAP_FLOOR]; c = feat_x_char[g->lighting][FEAT_DTRAP_FLOOR]; } /* Save the terrain info for the transparency effects */ (*tap) = a; (*tcp) = c; /* There is a trap in this grid, and we are not hallucinating */ if (g->trap && (!g->hallucinate)) /* Change graphics to indicate a trap (if visible) */ get_trap_graphics(cave, g, &a, &c); /* If there's an object, deal with that. */ if (g->unseen_money) { /* $$$ gets an orange star*/ a = object_kind_attr(&k_info[7]); c = object_kind_char(&k_info[7]); } else if (g->unseen_object) { /* Everything else gets a red star */ a = object_kind_attr(&k_info[6]); c = object_kind_char(&k_info[6]); } else if (g->first_kind) { if (g->hallucinate) { /* Just pick a random object to display. */ hallucinatory_object(&a, &c); } else if (g->multiple_objects) { /* Get the "pile" feature instead */ a = object_kind_attr(&k_info[0]); c = object_kind_char(&k_info[0]); } else { /* Normal attr and char */ a = object_kind_attr(g->first_kind); c = object_kind_char(g->first_kind); } } /* Handle monsters, the player and trap borders */ if (g->m_idx > 0) { if (g->hallucinate) { /* Just pick a random monster to display. */ hallucinatory_monster(&a, &c); } else if (!is_mimicking(cave_monster(cave, g->m_idx))) { monster_type *m_ptr = cave_monster(cave, g->m_idx); byte da; wchar_t dc; /* Desired attr & char */ da = monster_x_attr[m_ptr->race->ridx]; dc = monster_x_char[m_ptr->race->ridx]; /* Special handling of attrs and/or chars */ if (da & 0x80) { /* Special attr/char codes */ a = da; c = dc; } else if (OPT(purple_uniques) && rf_has(m_ptr->race->flags, RF_UNIQUE)) { /* Turn uniques purple if desired (violet, actually) */ a = COLOUR_VIOLET; c = dc; } else if (rf_has(m_ptr->race->flags, RF_ATTR_MULTI) || rf_has(m_ptr->race->flags, RF_ATTR_FLICKER) || rf_has(m_ptr->race->flags, RF_ATTR_RAND)) { /* Multi-hued monster */ a = m_ptr->attr ? m_ptr->attr : da; c = dc; } else if (!flags_test(m_ptr->race->flags, RF_SIZE, RF_ATTR_CLEAR, RF_CHAR_CLEAR, FLAG_END)) { /* Normal monster (not "clear" in any way) */ a = da; /* Desired attr & char. da is not used, should a be set to it?*/ /*da = monster_x_attr[m_ptr->race->ridx];*/ dc = monster_x_char[m_ptr->race->ridx]; c = dc; } else if (a & 0x80) { /* Hack -- Bizarre grid under monster */ a = da; c = dc; } else if (!rf_has(m_ptr->race->flags, RF_CHAR_CLEAR)) { /* Normal char, Clear attr, monster */ c = dc; } else if (!rf_has(m_ptr->race->flags, RF_ATTR_CLEAR)) { /* Normal attr, Clear char, monster */ a = da; } /* Store the drawing attr so we can use it elsewhere */ m_ptr->attr = a; } } else if (g->is_player) { monster_race *r_ptr = &r_info[0]; /* Get the "player" attr */ a = monster_x_attr[r_ptr->ridx]; if ((OPT(hp_changes_color)) && !(a & 0x80)) { switch(player->chp * 10 / player->mhp) { case 10: case 9: { a = COLOUR_WHITE; break; } case 8: case 7: { a = COLOUR_YELLOW; break; } case 6: case 5: { a = COLOUR_ORANGE; break; } case 4: case 3: { a = COLOUR_L_RED; break; } case 2: case 1: case 0: { a = COLOUR_RED; break; } default: { a = COLOUR_WHITE; break; } } } /* Get the "player" char */ c = monster_x_char[r_ptr->ridx]; } else if (g->trapborder && (g->f_idx) && !(g->first_kind) && (use_graphics != GRAPHICS_NONE)) { /* No overlay is used, so we can use the trap border overlay */ a = feat_x_attr[g->lighting][FEAT_DTRAP_WALL]; c = feat_x_char[g->lighting][FEAT_DTRAP_WALL]; } /* Result */ (*ap) = a; (*cp) = c; }