/* * Activate a new Term (and deactivate the current Term) * * This function is extremely important, and also somewhat bizarre. * It is the only function that should "modify" the value of "Term". * * To "create" a valid "term", one should do "term_init(t)", then * set the various flags and hooks, and then do "Term_activate(t)". */ errr Term_activate(term *t) { /* Hack -- already done */ if (Term == t) return (1); /* Deactivate the old Term */ if (Term) Term_xtra(TERM_XTRA_LEVEL, 0); /* Hack -- Call the special "init" hook */ if (t && !t->active_flag) { /* Call the "init" hook */ if (t->init_hook) (*t->init_hook)(t); /* Remember */ t->active_flag = TRUE; /* Assume mapped */ t->mapped_flag = TRUE; } /* Remember the Term */ Term = t; /* Activate the new Term */ if (Term) Term_xtra(TERM_XTRA_LEVEL, 1); /* Success */ return (0); }
static void activate_module() { /* Initialize the module table */ call_lua("assign_current_module", "(s)", "", game_module); /* Do misc inits */ call_lua("get_module_info", "(s)", "d", "max_plev", &max_plev); call_lua("get_module_info", "(s)", "d", "death_dungeon", &DUNGEON_DEATH); call_lua("get_module_info", "(s)", "d", "random_artifact_weapon_chance", &RANDART_WEAPON); call_lua("get_module_info", "(s)", "d", "random_artifact_armor_chance", &RANDART_ARMOR); call_lua("get_module_info", "(s)", "d", "random_artifact_jewelry_chance", &RANDART_JEWEL); call_lua("get_module_info", "(s,d)", "d", "version", 1, &VERSION_MAJOR); call_lua("get_module_info", "(s,d)", "d", "version", 2, &VERSION_MINOR); call_lua("get_module_info", "(s,d)", "d", "version", 3, &VERSION_PATCH); version_major = VERSION_MAJOR; version_minor = VERSION_MINOR; version_patch = VERSION_PATCH; /* Change window name if needed */ if (strcmp(game_module, "ToME")) { strnfmt(angband_term_name[0], 79, "T-Engine: %s", game_module); Term_xtra(TERM_XTRA_RENAME_MAIN_WIN, 0); } /* Reprocess the player name, just in case */ process_player_base(); }
bool target_set_closest(int mode) { int y, x, m_idx; monster_type *m_ptr; char m_name[80]; bool visibility; struct point_set *targets; /* Cancel old target */ target_set_monster(0); /* Get ready to do targetting */ targets = target_set_interactive_prepare(mode); /* If nothing was prepared, then return */ if (point_set_size(targets) < 1) { msg("No Available Target."); point_set_dispose(targets); return FALSE; } /* Find the first monster in the queue */ y = targets->pts[0].y; x = targets->pts[0].x; m_idx = cave->m_idx[y][x]; /* Target the monster, if possible */ if ((m_idx <= 0) || !target_able(m_idx)) { msg("No Available Target."); point_set_dispose(targets); return FALSE; } /* Target the monster */ m_ptr = cave_monster(cave, m_idx); monster_desc(m_name, sizeof(m_name), m_ptr, 0x00); if (!(mode & TARGET_QUIET)) msg("%^s is targeted.", m_name); Term_fresh(); /* Set up target information */ monster_race_track(m_ptr->r_idx); health_track(p_ptr, cave->m_idx[y][x]); target_set_monster(m_idx); /* Visual cue */ Term_get_cursor(&visibility); (void)Term_set_cursor(TRUE); move_cursor_relative(y, x); Term_redraw_section(x, y, x, y); /* TODO: what's an appropriate amount of time to spend highlighting */ Term_xtra(TERM_XTRA_DELAY, 150); (void)Term_set_cursor(visibility); point_set_dispose(targets); return TRUE; }
/* * Nuke the "curses" system */ static void Term_nuke_gcu(term *t) { int x, y; term_data *td = (term_data *)(t->data); /* Delete this window */ delwin(td->win); /* Count nuke's, handle last */ if (--active != 0) return; /* Hack -- make sure the cursor is visible */ Term_xtra(TERM_XTRA_SHAPE, 1); #ifdef A_COLOR /* Reset colors to defaults */ start_color(); #endif /* This moves curses to bottom right corner */ getyx(stdscr, y, x); mvcur(y, x, LINES - 1, 0); /* Flush the curses buffer */ (void)refresh(); /* Exit curses */ endwin(); /* Flush the output */ (void)fflush(stdout); /* Normal keymap */ keymap_norm(); }
/* * Helper function called only from "inkey()" */ static ui_event inkey_aux(int scan_cutoff) { int w = 0; ui_event ke; /* Wait for a keypress */ if (scan_cutoff == SCAN_OFF) { (void)(Term_inkey(&ke, TRUE, TRUE)); } else { w = 0; /* Wait only as long as macro activation would wait*/ while (Term_inkey(&ke, FALSE, TRUE) != 0) { /* Increase "wait" */ w++; /* Excessive delay */ if (w >= scan_cutoff) { ui_event empty = EVENT_EMPTY; return empty; } /* Delay */ Term_xtra(TERM_XTRA_DELAY, 10); } } return (ke); }
/** * Redraw the screen * * This command performs various low level updates, clears all the "extra" * windows, does a total redraw of the main window, and requests all of the * interesting updates and redraws that I can think of. * * This command is also used to "instantiate" the results of the user * selecting various things, such as graphics mode, so it must call * the "TERM_XTRA_REACT" hook before redrawing the windows. * */ void do_cmd_redraw(void) { int j; term *old = Term; /* Low level flush */ Term_flush(); /* Reset "inkey()" */ event_signal(EVENT_INPUT_FLUSH); if (character_dungeon) verify_panel(); /* Hack -- React to changes */ Term_xtra(TERM_XTRA_REACT, 0); if (character_dungeon) { /* Combine the pack (later) */ player->upkeep->notice |= (PN_COMBINE); /* Update torch, gear */ player->upkeep->update |= (PU_TORCH | PU_INVEN); /* Update stuff */ player->upkeep->update |= (PU_BONUS | PU_HP | PU_SPELLS); /* Fully update the visuals */ player->upkeep->update |= (PU_FORGET_VIEW | PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw everything */ player->upkeep->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP | PR_INVEN | PR_EQUIP | PR_MESSAGE | PR_MONSTER | PR_OBJECT | PR_MONLIST | PR_ITEMLIST); } /* Clear screen */ Term_clear(); if (character_dungeon) { /* Hack -- update */ handle_stuff(player); /* Place the cursor on the player */ if (0 != character_dungeon) move_cursor_relative(player->px, player->py); } /* Redraw every window */ for (j = 0; j < ANGBAND_TERM_MAX; j++) { if (!angband_term[j]) continue; Term_activate(angband_term[j]); Term_redraw(); Term_fresh(); Term_activate(old); } }
/* * Hack -- Make a (relevant?) sound */ void sound(int val) { /* No sound */ if (!use_sound) return; /* Make a sound (if allowed) */ Term_xtra(TERM_XTRA_SOUND, val); }
/* * Check for a pending keypress on the key queue. * * Store the keypress, if any, in "ch", and return "0". * Otherwise store "zero" in "ch", and return "1". * * Wait for a keypress if "wait" is true. * * Remove the keypress if "take" is true. */ errr Term_inkey(char *ch, bool_ wait, bool_ take) { /* Assume no key */ (*ch) = '\0'; /* Process queued UI events */ Term_xtra(TERM_XTRA_BORED, 0); /* Wait */ if (wait) { /* Process pending events while necessary */ while (Term->key_head == Term->key_tail) { /* Process events (wait for one) */ Term_xtra(TERM_XTRA_EVENT, TRUE); } } /* Do not Wait */ else { /* Process pending events if necessary */ if (Term->key_head == Term->key_tail) { /* Process events (do not wait) */ Term_xtra(TERM_XTRA_EVENT, FALSE); } } /* No keys are ready */ if (Term->key_head == Term->key_tail) return (1); /* Extract the next keypress */ (*ch) = Term->key_queue[Term->key_tail]; /* If requested, advance the queue, wrap around if necessary */ if (take && (++Term->key_tail == Term->key_size)) Term->key_tail = 0; /* Success */ return (0); }
static void colors_pref_load(const char *title, int row) { /* Ask for and load a user pref file */ do_cmd_pref_file_hack(8); /* XXX should probably be a cleaner way to tell UI about * colour changes - how about doing this in the pref file * loading code too? */ Term_xtra(TERM_XTRA_REACT, 0); Term_redraw(); }
/* * Suspend/Resume */ static errr Term_xtra_gcu_alive(int v) { int x, y; /* Suspend */ if (!v) { /* Go to normal keymap mode */ keymap_norm(); /* Restore modes */ nocbreak(); echo(); nl(); /* Hack -- make sure the cursor is visible */ Term_xtra(TERM_XTRA_SHAPE, 1); /* Flush the curses buffer */ (void)refresh(); /* Get current cursor position */ getyx(curscr, y, x); /* Move the cursor to bottom right corner */ mvcur(y, x, LINES - 1, 0); /* Exit curses */ endwin(); /* Flush the output */ (void)fflush(stdout); } /* Resume */ else { /* Refresh */ /* (void)touchwin(curscr); */ /* (void)wrefresh(curscr); */ /* Restore the settings */ cbreak(); noecho(); nonl(); /* Go to angband keymap mode */ keymap_game(); } /* Success */ return (0); }
/* * Flush and forget the input */ errr Term_flush(void) { /* Hack -- Flush all events */ Term_xtra(TERM_XTRA_FLUSH, 0); /* Forget all keypresses */ Term->key_head = Term->key_tail = 0; /* Success */ return (0); }
/* * Suspend/Resume */ static errr Term_xtra_gcu_alive(int v) { /* Suspend */ if (!v) { /* Go to normal keymap mode */ keymap_norm(); /* Restore modes */ nocbreak(); echo(); nl(); /* Hack -- make sure the cursor is visible */ Term_xtra(TERM_XTRA_SHAPE, 1); /* Flush the curses buffer */ (void)refresh(); #ifdef SPECIAL_BSD /* this moves curses to bottom right corner */ mvcur(curscr->cury, curscr->curx, LINES - 1, 0); #else /* this moves curses to bottom right corner */ mvcur(getcury(curscr), getcurx(curscr), LINES - 1, 0); #endif /* Exit curses */ endwin(); /* Flush the output */ (void)fflush(stdout); } /* Resume */ else { /* Refresh */ /* (void)touchwin(curscr); */ /* (void)wrefresh(curscr); */ /* Restore the settings */ cbreak(); noecho(); nonl(); /* Go to angband keymap mode */ keymap_game(); } /* Success */ return (0); }
void browse_movie(void) { Term_clear(); Term_fresh(); Term_xtra(TERM_XTRA_REACT, 0); while (read_movie_file() == 0) { while (fresh_queue.next != fresh_queue.tail) { if (!flush_ringbuf_client()) { Term_xtra(TERM_XTRA_FLUSH, 0); /* ソケットにデータが来ているかどうか調べる */ #ifdef WINDOWS Sleep(WAIT); #else usleep(WAIT); #endif } } } }
/* * Handle signals -- suspend * * Actually suspend the game, and then resume cleanly */ static void handle_signal_suspend(int sig) { /* Protect errno from library calls in signal handler */ int save_errno = errno; /* Disable handler */ (void)(*signal_aux)(sig, SIG_IGN); #ifdef SIGSTOP /* Flush output */ Term_fresh(); /* Suspend the "Term" */ Term_xtra(TERM_XTRA_ALIVE, 0); /* Suspend ourself */ (void)kill(0, SIGSTOP); /* Resume the "Term" */ Term_xtra(TERM_XTRA_ALIVE, 1); /* Redraw the term */ Term_redraw(); /* Flush the term */ Term_fresh(); #endif /* Restore handler */ (void)(*signal_aux)(sig, handle_signal_suspend); /* Restore errno */ errno = save_errno; }
/** * Redraw a term when it is resized */ void redraw_window(void) { /* Only if the dungeon exists */ if (!character_dungeon) return; /* Hack - Activate term zero for the redraw */ Term_activate(&term_screen[0]); /* Hack -- react to changes */ Term_xtra(TERM_XTRA_REACT, 0); /* Hack -- update */ handle_stuff(p_ptr); /* Redraw */ Term_redraw(); /* Refresh */ Term_fresh(); }
/** * Target closest monster. * * XXX: Move to using CMD_TARGET_CLOSEST at some point instead of invoking * target_set_closest() directly. */ void textui_target_closest(void) { if (target_set_closest(TARGET_KILL)) { bool visibility; int x, y; target_get(&x, &y); /* Visual cue */ Term_fresh(); Term_get_cursor(&visibility); (void)Term_set_cursor(TRUE); move_cursor_relative(y, x); Term_redraw_section(x, y, x, y); /* TODO: what's an appropriate amount of time to spend highlighting */ Term_xtra(TERM_XTRA_DELAY, 150); (void)Term_set_cursor(visibility); } }
/* * Flush the screen, make a noise */ void bell(cptr reason) { /* Mega-Hack -- Flush the output */ Term_fresh(); /* Hack -- memorize the reason if possible */ if (character_generated && reason) { message_add(reason, MSG_BELL); /* Window stuff */ p_ptr->window |= (PW_MESSAGE); /* Force window redraw */ window_stuff(); } /* Make a bell noise (if allowed) */ if (ring_bell) Term_xtra(TERM_XTRA_NOISE, 0); /* Flush the input (later!) */ flush(); }
/* * Handle signals -- simple (interrupt and quit) * * This function was causing a *huge* number of problems, so it has * been simplified greatly. We keep a global variable which counts * the number of times the user attempts to kill the process, and * we commit suicide if the user does this a certain number of times. * * We attempt to give "feedback" to the user as he approaches the * suicide thresh-hold, but without penalizing accidental keypresses. * * To prevent messy accidents, we should reset this global variable * whenever the user enters a keypress, or something like that. */ static void handle_signal_simple(int sig) { /* Protect errno from library calls in signal handler */ int save_errno = errno; /* Disable handler */ (void)(*signal_aux)(sig, SIG_IGN); /* Nothing to save, just quit */ if (!character_generated || character_saved) quit(NULL); /* Count the signals */ signal_count++; /* Terminate dead characters */ if (p_ptr->is_dead) { /* Mark the savefile */ my_strcpy(p_ptr->died_from, "Abortion", sizeof(p_ptr->died_from)); close_game(); /* Quit */ quit("interrupt"); } /* Allow suicide (after 5) */ else if (signal_count >= 5) { /* Cause of "death" */ my_strcpy(p_ptr->died_from, "Interrupting", sizeof(p_ptr->died_from)); /* Commit suicide */ p_ptr->is_dead = TRUE; /* Stop playing */ p_ptr->playing = FALSE; /* Leaving */ p_ptr->leaving = TRUE; /* Close stuff */ close_game(); /* Quit */ quit("interrupt"); } /* Give warning (after 4) */ else if (signal_count >= 4) { /* Make a noise */ Term_xtra(TERM_XTRA_NOISE, 0); /* Clear the top line */ Term_erase(0, 0, 255); /* Display the cause */ Term_putstr(0, 0, -1, TERM_WHITE, "Contemplating suicide!"); /* Flush */ Term_fresh(); } /* Give warning (after 2) */ else if (signal_count >= 2) { /* Make a noise */ Term_xtra(TERM_XTRA_NOISE, 0); } /* Restore handler */ (void)(*signal_aux)(sig, handle_signal_simple); /* Restore errno */ errno = save_errno; }
/** * This is a helper function used by do_cmd_throw and do_cmd_fire. * * It abstracts out the projectile path, display code, identify and clean up * logic, while using the 'attack' parameter to do work particular to each * kind of attack. */ static void ranged_helper(int item, int dir, int range, int shots, ranged_attack attack) { /* Get the ammo */ object_type *o_ptr = object_from_item_idx(item); int i, j; byte missile_attr = object_attr(o_ptr); char missile_char = object_char(o_ptr); object_type object_type_body; object_type *i_ptr = &object_type_body; char o_name[80]; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor; /* Start at the player */ int x = p_ptr->px; int y = p_ptr->py; /* Predict the "target" location */ s16b ty = y + 99 * ddy[dir]; s16b tx = x + 99 * ddx[dir]; bool hit_target = FALSE; /* Check for target validity */ if ((dir == 5) && target_okay()) { int taim; char msg[80]; target_get(&tx, &ty); taim = distance(y, x, ty, tx); if (taim > range) { sprintf (msg, "Target out of range by %d squares. Fire anyway? ", taim - range); if (!get_check(msg)) return; } } /* Sound */ sound(MSG_SHOOT); object_notice_on_firing(o_ptr); /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR); /* Actually "fire" the object -- Take a partial turn */ p_ptr->energy_use = (100 / shots); /* Calculate the path */ path_n = project_path(path_g, range, y, x, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(p_ptr); /* Start at the player */ x = p_ptr->px; y = p_ptr->py; /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(p_ptr); Term_xtra(TERM_XTRA_DELAY, msec); cave_light_spot(cave, y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(p_ptr); } else { /* Delay anyway for consistency */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave->m_idx[y][x] > 0) break; } /* Try the attack on the monster at (x, y) if any */ if (cave->m_idx[y][x] > 0) { monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]); monster_race *r_ptr = &r_info[m_ptr->r_idx]; int visible = m_ptr->ml; bool fear = FALSE; char m_name[80]; const char *note_dies = monster_is_unusual(r_ptr) ? " is destroyed." : " dies."; struct attack_result result = attack(o_ptr, y, x); int dmg = result.dmg; u32b msg_type = result.msg_type; const char *hit_verb = result.hit_verb; if (result.success) { hit_target = TRUE; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); object_notice_attack_plusses(o_ptr); /* No negative damage; change verb if no damage done */ if (dmg <= 0) { dmg = 0; hit_verb = "fail to harm"; } if (!visible) { /* Invisible monster */ msgt(MSG_SHOOT_HIT, "The %s finds a mark.", o_name); } else { /* Visible monster */ if (msg_type == MSG_SHOOT_HIT) msgt(MSG_SHOOT_HIT, "The %s %s %s.", o_name, hit_verb, m_name); else if (msg_type == MSG_HIT_GOOD) { msgt(MSG_HIT_GOOD, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { msgt(MSG_HIT_GREAT, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { msgt(MSG_HIT_SUPERB, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } /* Track this monster */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); if (m_ptr->ml) health_track(p_ptr, cave->m_idx[y][x]); } /* Complex message */ if (p_ptr->wizard) msg("You do %d (out of %d) damage.", dmg, m_ptr->hp); /* Hit the monster, check for death */ if (!mon_take_hit(cave->m_idx[y][x], dmg, &fear, note_dies)) { message_pain(cave->m_idx[y][x], dmg); if (fear && m_ptr->ml) add_monster_message(m_name, cave->m_idx[y][x], MON_MSG_FLEE_IN_TERROR, TRUE); } } } /* Obtain a local object */ object_copy(i_ptr, o_ptr); object_split(i_ptr, o_ptr, 1); /* See if the ammunition broke or not */ j = breakage_chance(i_ptr, hit_target); /* Drop (or break) near that location */ drop_near(cave, i_ptr, j, y, x, TRUE); if (item >= 0) { /* The ammo is from the inventory */ inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } else { /* The ammo is from the floor */ floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } }
static void _greater_whirlwind_attack_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Greater Ambush"); break; case SPELL_DESC: var_set_string(res, "Perform a massive ambush on nearby monsters."); break; case SPELL_CAST: { int i, x, y; cave_type *c_ptr; monster_type *m_ptr; /* cba d218l e3@7k f456j ghi */ typedef struct _offset_t { int dx; int dy; } _offset; static _offset offsets[] = { { 0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, { 0, 1}, { 1, 1}, { 1, 0}, { 1, -1}, { 1, -2}, { 0, -2}, {-1, -2}, {-2, -1}, {-2, 0}, {-2, 1}, {-1, 2}, { 0, 2}, { 1, 2}, { 2, 1}, { 2, 0}, { 2, -1}, { 0, 0}, /* sentinel */ }; for (i = 0;; i++) { _offset offset = offsets[i]; if (offset.dx == 0 && offset.dy == 0) break; y = py + offset.dy; x = px + offset.dx; if (!in_bounds(y, x)) continue; if (!projectable(py, px, y, x)) continue; c_ptr = &cave[y][x]; if (!c_ptr->m_idx) continue; m_ptr = &m_list[c_ptr->m_idx]; if (m_ptr->ml || cave_have_flag_bold(y, x, FF_PROJECT)) { int msec = delay_factor * delay_factor * delay_factor; if (panel_contains(y, x) && player_can_see_bold(y, x)) { char c = 0x30; byte a = TERM_WHITE; print_rel(c, a, y, x); move_cursor_relative(y, x); Term_fresh(); Term_xtra(TERM_XTRA_DELAY, msec); lite_spot(y, x); Term_fresh(); } else Term_xtra(TERM_XTRA_DELAY, msec); py_attack(y, x, 0); } } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
/* * Interactive group by. * Recognises inscriptions, graphical symbols, lore */ static void display_knowledge(const char *title, int *obj_list, int o_count, group_funcs g_funcs, member_funcs o_funcs, const char *otherfields) { /* maximum number of groups to display */ int max_group = g_funcs.maxnum < o_count ? g_funcs.maxnum : o_count; /* This could (should?) be (void **) */ int *g_list, *g_offset; const char **g_names; int g_name_len = 8; /* group name length, minumum is 8 */ int grp_cnt = 0; /* total number groups */ int g_cur = 0, grp_old = -1; /* group list positions */ int o_cur = 0; /* object list positions */ int g_o_count = 0; /* object count for group */ int oid = -1; /* object identifiers */ region title_area = { 0, 0, 0, 4 }; region group_region = { 0, 6, MISSING, -2 }; region object_region = { MISSING, 6, 0, -2 }; /* display state variables */ bool tiles = (current_graphics_mode != NULL); bool tile_picker = FALSE; bool glyph_picker = FALSE; byte attr_top = 0; byte char_left = 0; int delay = 0; menu_type group_menu; menu_type object_menu; menu_iter object_iter = { NULL, NULL, display_group_member, NULL, NULL }; /* Panel state */ /* These are swapped in parallel whenever the actively browsing " */ /* changes */ int *active_cursor = &g_cur, *inactive_cursor = &o_cur; menu_type *active_menu = &group_menu, *inactive_menu = &object_menu; int panel = 0; void *swapspace; bool do_swap = FALSE; bool flag = FALSE; bool redraw = TRUE; int browser_rows; int wid, hgt; int i; int prev_g = -1; int omode = OPT(rogue_like_commands); ui_event ke; /* Get size */ Term_get_size(&wid, &hgt); browser_rows = hgt - 8; /* Disable the roguelike commands for the duration */ OPT(rogue_like_commands) = FALSE; /* Determine if using tiles or not */ if (tiles) tiles = (current_graphics_mode->grafID != 0); if (g_funcs.gcomp) sort(obj_list, o_count, sizeof(*obj_list), g_funcs.gcomp); /* Sort everything into group order */ g_list = C_ZNEW(max_group + 1, int); g_offset = C_ZNEW(max_group + 1, int); for (i = 0; i < o_count; i++) { if (prev_g != g_funcs.group(obj_list[i])) { prev_g = g_funcs.group(obj_list[i]); g_offset[grp_cnt] = i; g_list[grp_cnt++] = prev_g; } } g_offset[grp_cnt] = o_count; g_list[grp_cnt] = -1; /* The compact set of group names, in display order */ g_names = C_ZNEW(grp_cnt, const char *); for (i = 0; i < grp_cnt; i++) { int len; g_names[i] = g_funcs.name(g_list[i]); len = strlen(g_names[i]); if (len > g_name_len) g_name_len = len; } /* Reasonable max group name len */ if (g_name_len >= 20) g_name_len = 20; object_region.col = g_name_len + 3; group_region.width = g_name_len; /* Leave room for the group summary information */ if (g_funcs.summary) object_region.page_rows = -3; /* Set up the two menus */ menu_init(&group_menu, MN_SKIN_SCROLL, menu_find_iter(MN_ITER_STRINGS)); menu_setpriv(&group_menu, grp_cnt, g_names); menu_layout(&group_menu, &group_region); menu_init(&object_menu, MN_SKIN_SCROLL, &object_iter); menu_setpriv(&object_menu, 0, &o_funcs); menu_layout(&object_menu, &object_region); o_funcs.is_visual = FALSE; /* Save screen */ screen_save(); clear_from(0); /* This is the event loop for a multi-region panel */ /* Panels are -- text panels, two menus, and visual browser */ /* with "pop-up menu" for lore */ while ((!flag) && (grp_cnt)) { bool recall = FALSE; if (redraw) { /* Print the title bits */ region_erase(&title_area); prt(format("Knowledge - %s", title), 2, 0); prt("Group", 4, 0); prt("Name", 4, g_name_len + 3); if (otherfields) prt(otherfields, 4, 46); /* Print dividers: horizontal and vertical */ for (i = 0; i < 79; i++) Term_putch(i, 5, TERM_WHITE, '='); for (i = 0; i < browser_rows; i++) Term_putch(g_name_len + 1, 6 + i, TERM_WHITE, '|'); /* Reset redraw flag */ redraw = FALSE; } if (g_cur != grp_old) { grp_old = g_cur; o_cur = 0; g_o_count = g_offset[g_cur + 1] - g_offset[g_cur]; menu_set_filter(&object_menu, obj_list + g_offset[g_cur], g_o_count); group_menu.cursor = g_cur; object_menu.cursor = 0; } /* HACK ... */ if (!(tile_picker || glyph_picker)) { /* ... The object menu may be browsing the entire group... */ o_funcs.is_visual = FALSE; menu_set_filter(&object_menu, obj_list + g_offset[g_cur], g_o_count); object_menu.cursor = o_cur; } else { /* ... or just a single element in the group. */ o_funcs.is_visual = TRUE; menu_set_filter(&object_menu, obj_list + o_cur + g_offset[g_cur], 1); object_menu.cursor = 0; } oid = obj_list[g_offset[g_cur] + o_cur]; /* Print prompt */ { const char *pedit = (!o_funcs.xattr) ? "" : (!(attr_idx | char_idx) ? ", 'c' to copy" : ", 'c', 'p' to paste"); const char *xtra = o_funcs.xtra_prompt ? o_funcs.xtra_prompt(oid) : ""; const char *pvs = ""; if (tile_picker) pvs = ", ENTER to accept"; else if (glyph_picker) pvs = ", 'i' to insert, ENTER to accept"; else if (o_funcs.xattr) pvs = ", 'v' for visuals"; prt(format("<dir>%s%s%s, ESC", pvs, pedit, xtra), hgt - 1, 0); } if (do_swap) { do_swap = FALSE; swap(active_menu, inactive_menu); swap(active_cursor, inactive_cursor); panel = 1 - panel; } if (g_funcs.summary && !tile_picker && !glyph_picker) { g_funcs.summary(g_cur, obj_list, g_o_count, g_offset[g_cur], object_menu.active.row + object_menu.active.page_rows, object_region.col); } menu_refresh(inactive_menu, FALSE); menu_refresh(active_menu, FALSE); handle_stuff(p_ptr); if (tile_picker) { bigcurs = TRUE; display_tiles(g_name_len + 3, 7, browser_rows - 1, wid - (g_name_len + 3), attr_top, char_left); place_tile_cursor(g_name_len + 3, 7, *o_funcs.xattr(oid), (byte) * o_funcs.xchar(oid), attr_top, char_left); } if (glyph_picker) { display_glyphs(g_name_len + 3, 7, browser_rows - 1, wid - (g_name_len + 3), *o_funcs.xattr(oid), *o_funcs.xchar(oid)); } if (delay) { /* Force screen update */ Term_fresh(); /* Delay */ Term_xtra(TERM_XTRA_DELAY, delay); delay = 0; } ke = inkey_ex(); if (!tile_picker && !glyph_picker) { ui_event ke0 = EVENT_EMPTY; if (ke.type == EVT_MOUSE) menu_handle_mouse(active_menu, &ke, &ke0); else if (ke.type == EVT_KBRD) menu_handle_keypress(active_menu, &ke, &ke0); if (ke0.type != EVT_NONE) ke = ke0; } /* XXX Do visual mode command if needed */ if (o_funcs.xattr && o_funcs.xchar) { if (tiles) { if (tile_picker_command(ke, &tile_picker, browser_rows - 1, wid - (g_name_len + 3), &attr_top, &char_left, o_funcs.xattr(oid), (byte *) o_funcs.xchar(oid), g_name_len + 3, 7, &delay)) continue; } else { if (glyph_command(ke, &glyph_picker, browser_rows - 1, wid - (g_name_len + 3), o_funcs.xattr(oid), o_funcs.xchar(oid), g_name_len + 3, 7)) continue; } } switch (ke.type) { case EVT_KBRD: { if (ke.key.code == 'r' || ke.key.code == 'R') recall = TRUE; else if (o_funcs.xtra_act) o_funcs.xtra_act(ke.key, oid); break; } case EVT_MOUSE: { /* Change active panels */ if (region_inside(&inactive_menu->boundary, &ke)) { swap(active_menu, inactive_menu); swap(active_cursor, inactive_cursor); panel = 1 - panel; } continue; } case EVT_ESCAPE: { if (panel == 1) do_swap = TRUE; else flag = TRUE; break; } case EVT_SELECT: { if (panel == 0) do_swap = TRUE; else if (panel == 1 && oid >= 0 && o_cur == active_menu->cursor) recall = TRUE; break; } case EVT_MOVE: { *active_cursor = active_menu->cursor; break; } default: { break; } } /* Recall on screen */ if (recall) { if (oid >= 0) o_funcs.lore(oid); redraw = TRUE; } } /* Restore roguelike option */ OPT(rogue_like_commands) = omode; /* Prompt */ if (!grp_cnt) prt(format("No %s known.", title), 15, 0); FREE(g_names); FREE(g_offset); FREE(g_list); screen_load(); }
/* * Fire an object from the pack or floor. * * You may only fire items that "match" your missile launcher. * * See "calc_bonuses()" for more calculations and such. * * Note that "firing" a missile is MUCH better than "throwing" it. * * Note: "unseen" monsters are very hard to hit. * * Objects are more likely to break if they "attempt" to hit a monster. * * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots. * The "extra shot" code works by decreasing the amount of energy * required to make each shot, spreading the shots out over time. * * Note that when firing missiles, the launcher multiplier is applied * after all the bonuses are added in, making multipliers very useful. * * Note that Bows of "Extra Might" get extra range and an extra bonus * for the damage multiplier. */ void do_cmd_fire(cmd_code code, cmd_arg args[]) { int dir, item; int i, j, y, x; s16b ty, tx; int tdam, tdis, thits; int bonus, chance; object_type *o_ptr; object_type *j_ptr; object_type *i_ptr; object_type object_type_body; bool hit_body = FALSE; byte missile_attr; char missile_char; char o_name[80]; u32b msg_type = 0; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor * op_ptr->delay_factor; /* Get the "bow" */ j_ptr = &p_ptr->inventory[INVEN_BOW]; /* Require a usable launcher */ if (!j_ptr->tval || !p_ptr->state.ammo_tval) { msg_print("You have nothing to fire with."); return; } /* Get item to fire and direction to fire in. */ item = args[0].item; dir = args[1].direction; /* Check the item being fired is usable by the player. */ if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR))) { msg_format("That item is not within your reach."); return; } /* Get the object for the ammo */ o_ptr = object_from_item_idx(item); /* Check the ammo can be used with the launcher */ if (o_ptr->tval != p_ptr->state.ammo_tval) { msg_format("That ammo cannot be fired by your current weapon."); return; } /* Base range XXX XXX */ tdis = 6 + 2 * p_ptr->state.ammo_mult; /* Start at the player */ x = p_ptr->px; y = p_ptr->py; /* Predict the "target" location */ ty = y + 99 * ddy[dir]; tx = x + 99 * ddx[dir]; /* Check for target validity */ if ((dir == 5) && target_okay()) { target_get(&tx, &ty); if (distance(y, x, ty, tx) > tdis) { if (!get_check("Target out of range. Fire anyway? ")) return; } } /* Sound */ sound(MSG_SHOOT); object_notice_on_firing(o_ptr); /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR); /* Find the color and symbol for the object for throwing */ missile_attr = object_attr(o_ptr); missile_char = object_char(o_ptr); /* Use the proper number of shots */ thits = p_ptr->state.num_fire; /* Actually "fire" the object */ bonus = (p_ptr->state.to_h + o_ptr->to_h + j_ptr->to_h); chance = p_ptr->state.skills[SKILL_TO_HIT_BOW] + (bonus * BTH_PLUS_ADJ); /* Take a (partial) turn */ p_ptr->energy_use = (100 / thits); /* Calculate the path */ path_n = project_path(path_g, tdis, y, x, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(); /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { /* Visual effects */ print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); Term_xtra(TERM_XTRA_DELAY, msec); light_spot(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); } /* Delay anyway for consistency */ else { /* Pause anyway, for consistancy */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x); int visible = m_ptr->ml; int multiplier = 1; const char *hit_verb = "hits"; const slay_t *best_s_ptr = NULL; /* Note the collision */ hit_body = TRUE; /* Did we hit it (penalize distance travelled) */ if (test_hit(chance2, r_ptr->ac, m_ptr->ml)) { bool fear = FALSE; /* Assume a default death */ cptr note_dies = " dies."; improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr); improve_attack_modifier(j_ptr, m_ptr, &best_s_ptr); if (best_s_ptr != NULL) hit_verb = best_s_ptr->range_verb; /* Some monsters get "destroyed" */ if (monster_is_unusual(r_ptr)) { /* Special note at death */ note_dies = " is destroyed."; } /* Calculate multiplier */ multiplier = p_ptr->state.ammo_mult; if (best_s_ptr != NULL) multiplier += best_s_ptr->mult; /* Apply damage: multiplier, slays, criticals, bonuses */ tdam = damroll(o_ptr->dd, o_ptr->ds); tdam += o_ptr->to_d + j_ptr->to_d; tdam *= multiplier; tdam = critical_shot(o_ptr->weight, o_ptr->to_h, tdam, &msg_type); object_notice_attack_plusses(o_ptr); object_notice_attack_plusses(&p_ptr->inventory[INVEN_BOW]); /* No negative damage; change verb if no damage done */ if (tdam <= 0) { tdam = 0; hit_verb = "fail to harm"; } /* Handle unseen monster */ if (!visible) { /* Invisible monster */ message_format(MSG_SHOOT_HIT, 0, "The %s finds a mark.", o_name); } /* Handle visible monster */ else { char m_name[80]; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Tell the player what happened */ if (msg_type == MSG_SHOOT_HIT) message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name); else { if (msg_type == MSG_HIT_GOOD) { message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } } /* Hack -- Track this monster race */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Hack -- Track this monster */ if (m_ptr->ml) health_track(cave_m_idx[y][x]); } /* Complex message */ if (p_ptr->wizard) { msg_format("You do %d (out of %d) damage.", tdam, m_ptr->hp); } /* Hit the monster, check for death */ if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies)) { /* Dead monster */ } /* No death */ else { /* Message */ message_pain(cave_m_idx[y][x], tdam); /* Take note */ if (fear && m_ptr->ml) { char m_name[80]; /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); } } } /* Stop looking */ break; } } /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Single object */ i_ptr->number = 1; if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Reduce and describe floor item */ else { floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } /* Chance of breakage (during attacks) */ j = (hit_body ? breakage_chance(i_ptr) : 0); /* Drop (or break) near that location */ drop_near(i_ptr, j, y, x, TRUE); }
static void colors_modify(const char *title, int row) { int i; static byte a = 0; /* Prompt */ prt("Command: Modify colors", 8, 0); /* Hack -- query until done */ while (1) { const char *name; char index; struct keypress cx; /* Clear */ clear_from(10); /* Exhibit the normal colors */ for (i = 0; i < BASIC_COLORS; i++) { /* Exhibit this color */ Term_putstr(i*3, 20, -1, a, "##"); /* Exhibit character letter */ Term_putstr(i*3, 21, -1, (byte)i, format(" %c", color_table[i].index_char)); /* Exhibit all colors */ Term_putstr(i*3, 22, -1, (byte)i, format("%2d", i)); } /* Describe the color */ name = ((a < BASIC_COLORS) ? color_table[a].name : "undefined"); index = ((a < BASIC_COLORS) ? color_table[a].index_char : '?'); /* Describe the color */ Term_putstr(5, 10, -1, COLOUR_WHITE, format("Color = %d, Name = %s, Index = %c", a, name, index)); /* Label the Current values */ Term_putstr(5, 12, -1, COLOUR_WHITE, format("K = 0x%02x / R,G,B = 0x%02x,0x%02x,0x%02x", angband_color_table[a][0], angband_color_table[a][1], angband_color_table[a][2], angband_color_table[a][3])); /* Prompt */ Term_putstr(0, 14, -1, COLOUR_WHITE, "Command (n/N/k/K/r/R/g/G/b/B): "); /* Get a command */ cx = inkey(); /* All done */ if (cx.code == ESCAPE) break; /* Analyze */ if (cx.code == 'n') a = (byte)(a + 1); if (cx.code == 'N') a = (byte)(a - 1); if (cx.code == 'k') angband_color_table[a][0] = (byte)(angband_color_table[a][0] + 1); if (cx.code == 'K') angband_color_table[a][0] = (byte)(angband_color_table[a][0] - 1); if (cx.code == 'r') angband_color_table[a][1] = (byte)(angband_color_table[a][1] + 1); if (cx.code == 'R') angband_color_table[a][1] = (byte)(angband_color_table[a][1] - 1); if (cx.code == 'g') angband_color_table[a][2] = (byte)(angband_color_table[a][2] + 1); if (cx.code == 'G') angband_color_table[a][2] = (byte)(angband_color_table[a][2] - 1); if (cx.code == 'b') angband_color_table[a][3] = (byte)(angband_color_table[a][3] + 1); if (cx.code == 'B') angband_color_table[a][3] = (byte)(angband_color_table[a][3] - 1); /* Hack -- react to changes */ Term_xtra(TERM_XTRA_REACT, 0); /* Hack -- redraw */ Term_redraw(); } }
/* * Perform an action in the dungeon * * Return TRUE if a "meaningful" action was performed * Otherwise, return FALSE so we will be called again * * Strategy: * Make sure we are happy with our "status" (see above) * Attack and kill visible monsters, if near enough * Open doors, disarm traps, tunnel through rubble * Pick up (or tunnel to) gold and useful objects * Explore "interesting" grids, to expand the map * Explore the dungeon and revisit old grids * * Fleeing: * Use word of recall when level is "scary" * Flee to stairs when there is a chance of death * Avoid "stair bouncing" if at all possible * * Note that the various "flow" actions allow the Borg to flow * "through" closed doors, which will be opened when he attempts * to pass through them, so we do not have to pursue terrain until * all monsters and objects have been dealt with. * * XXX XXX XXX The poor Borg often kills a nasty monster, and * then takes a nap to recover from damage, but gets yanked * back to town before he can collect his reward. */ bool borg_think_dungeon(void) { int i, j; int msec = (delay_factor * delay_factor * delay_factor); /* Hack -- prevent clock wrapping */ if (borg_t >= 20000000) { /* Panic */ borg_oops("clock overflow"); /* Oops */ return (TRUE); } /* Add a short pause to slow the borg down for viewing */ Term_xtra(TERM_XTRA_DELAY, msec); /* Prevent clock overflow */ if (borg_t - borg_began >= 100000) { /* Start leaving */ if (!goal_leaving) { /* Note */ borg_note("# Leaving (boredom)"); /* Start leaving */ goal_leaving = TRUE; } /* Start fleeing */ if (!goal_fleeing) { /* Note */ borg_note("# Fleeing (boredom)"); /* Start fleeing */ goal_fleeing = TRUE; } } /* Avoid the burning sun */ if (FLAG(bp_ptr, TR_HURT_LITE) && !FLAG(bp_ptr, TR_RES_LITE) && !bp_ptr->depth && bp_ptr->hour > 5 && bp_ptr->hour < 18) { /* Get out of the Sun */ if (!goal_fleeing) { /* Flee */ borg_note("# Avoiding Sunlight."); /* Ignore multipliers */ goal_fleeing = TRUE; } } /* Count the awake breeders */ for (j = 0, i = 1; i < borg_kills_nxt; i++) { borg_kill *kill = &borg_kills[i]; monster_race *r_ptr; /* Skip dead monsters */ if (!kill->r_idx) continue; /* Skip sleeping monsters */ if (kill->m_flags & MONST_ASLEEP) continue; r_ptr = &r_info[kill->r_idx]; /* Count the monsters which are "breeders" */ if (FLAG(r_ptr, RF_MULTIPLY)) j++; } /* hack -- close doors on breeder levles */ if (j >= 8) { /* set the flag to close doors */ breeder_level = TRUE; } /* Hack -- caution from breeders */ if ((j >= MIN(bp_ptr->lev, 5)) && (!bp_ptr->recall || (bp_ptr->lev < 35))) { /* Ignore monsters from caution */ if (!goal_ignoring) { /* Flee */ borg_note("# Ignoring breeders (no recall)"); /* Ignore multipliers */ goal_ignoring = TRUE; } /* Start leaving */ if (!goal_leaving) { /* Note */ borg_note("# Leaving (no recall)"); /* Start leaving */ goal_leaving = TRUE; } /* Start fleeing */ if (!goal_fleeing) { /* Note */ borg_note("# Fleeing (no recall)"); /* Start fleeing */ goal_fleeing = TRUE; } } /* Reset avoidance */ if (avoidance != bp_ptr->chp) { /* Reset "avoidance" */ avoidance = bp_ptr->chp; /* Re-calculate danger */ borg_danger_wipe = TRUE; } /*** crucial goals ***/ /* Set the internally kept stats correctly */ g_power = borg_power(); g_power_home = borg_power_home(); /* require light-- */ if (!bp_ptr->cur_lite && (bp_ptr->depth >= 1)) { if (goal_recalling) { /* just wait */ borg_keypress('R'); borg_keypress('9'); borg_keypress('\n'); return (TRUE); } /* attempt to refuel */ if (borg_refuel()) return (TRUE); /* wear stuff and see if it glows */ if (borg_wear_stuff()) return (TRUE); /* Can I recall out with a rod */ if (!goal_recalling && borg_recall()) return (TRUE); /* Test for stairs */ if (map_loc(c_x, c_y)->feat == FEAT_LESS) { /* Take it */ borg_keypress('<'); return (TRUE); } /* Try to flow to a lite if I can recall */ if (bp_ptr->recall) { /* Can I recall out with a spell */ if (borg_flow_light(GOAL_FLEE)) return (TRUE); } } /* Decrease the amount of time not allowed to retreat */ if (borg_no_retreat > 0) borg_no_retreat--; /*** Important goals ***/ /* Try not to die */ if (borg_caution()) return (TRUE); /* Get to a non-hurting feat */ if (borg_flow_non_hurt()) return (TRUE); /*** if returning from dungeon in bad shape...***/ if (!bp_ptr->cur_lite || bp_ptr->status.cut || bp_ptr->status.poisoned || bp_ptr->status.weak) { /* First try to wear something */ if (!bp_ptr->cur_lite) { /* attempt to refuel */ if (borg_refuel()) return (TRUE); /* wear stuff and see if it glows */ if (borg_wear_stuff()) return (TRUE); } /* Recover from damage */ if (borg_recover()) return (TRUE); /* Continue flowing (see below) */ if (borg_flow_old(GOAL_TOWN)) return (TRUE); /* Shop for something that will help us */ if (borg_choose_shop()) { /* Try and visit a shop, if so desired */ if (borg_flow_shop_entry(goal_shop)) return (TRUE); } } /* Learn useful spells immediately */ if (borg_play_magic(FALSE)) return (TRUE); /* If using a digger, Wear "useful" equipment before fighting monsters */ if (equipment[EQUIP_WIELD].tval == TV_DIGGING && borg_wear_stuff()) { return (TRUE); } /* Attack monsters */ if (borg_attack(FALSE)) return (TRUE); /* Wear things that need to be worn */ if (borg_wear_stuff()) return (TRUE); /* Take off things that have become useless */ if (borg_unwear_stuff()) return (TRUE); /* Check the light */ if (borg_check_lite()) return (TRUE); /* Recover from damage */ if (borg_recover()) return (TRUE); /* Perform "cool" perma spells */ if (borg_perma_spell()) return (TRUE); /*** Flee the level XXX XXX XXX ***/ /* Return to Stairs, but not use them */ if (goal_less) { /* Continue fleeing to stair */ if (borg_flow_old(GOAL_FLEE)) return (TRUE); /* Try to find some stairs */ if (scaryguy_on_level && !bp_ptr->depth && borg_flow_stair_both(GOAL_FLEE)) return (TRUE); /* Try to find some stairs up */ if (borg_flow_stair_less(GOAL_FLEE)) return (TRUE); } /* Flee the level */ if (goal_fleeing && !goal_recalling) { /* Hack -- Take the next stairs */ stair_less = stair_more = TRUE; /* Continue fleeing the level */ if (borg_flow_old(GOAL_FLEE)) return (TRUE); /* Try to find some stairs */ if (scaryguy_on_level && !bp_ptr->depth && borg_flow_stair_both(GOAL_FLEE)) return (TRUE); /* Try to find some stairs up */ if (borg_flow_stair_less(GOAL_FLEE)) return (TRUE); /* Try to find some stairs down */ if (borg_flow_stair_more(GOAL_FLEE)) return (TRUE); /* Try to hide on a glyph if no stairs */ if (borg_flow_glyph(GOAL_FLEE)) return (TRUE); } /* Continue flowing towards monsters */ if (borg_flow_old(GOAL_KILL)) return (TRUE); /* Find a (viewable) monster */ if (borg_flow_kill(TRUE, 250)) return (TRUE); /* Find a viewable monster and line up a shot on him */ /* Disabled because it is buggy, causing live-lock. if (borg_flow_kill_aim(TRUE)) return (TRUE); */ /* Dig an anti-summon corridor */ if (borg_flow_kill_corridor(TRUE)) return (TRUE); /*** Deal with inventory objects ***/ /* Use things */ if (borg_use_things()) return (TRUE); /* Try to identify things */ if (borg_id_meta()) return (TRUE); /* Enchant things */ if (borg_enchanting()) return (TRUE); /* Recharge things */ if (borg_recharging()) return (TRUE); /* Maybe destroy an item */ if (borg_destroy()) return (TRUE); /*** Flow towards objects ***/ /* Continue flowing towards objects */ if (borg_flow_old(GOAL_TAKE)) return (TRUE); /* Find a (viewable) object */ if (borg_flow_take(TRUE, 250)) return (TRUE); /*** Leave the level XXX XXX XXX ***/ /* Leave the level */ if (goal_leaving && !goal_recalling && !unique_on_level) { /* Only go down if fleeing or prepared. */ if (!borg_prepared(bp_ptr->depth + 1)) stair_more = TRUE; /* Continue leaving the level */ if (borg_flow_old(GOAL_FLEE)) return (TRUE); /* Try to find some stairs up */ if (stair_less) if (borg_flow_stair_less(GOAL_FLEE)) return (TRUE); /* Try to find some stairs down */ if (stair_more) if (borg_flow_stair_more(GOAL_FLEE)) return (TRUE); } /*** Exploration ***/ /* Continue flowing for low importance stuff */ if (goal >= GOAL_SHOP && goal < GOAL_MAX && borg_flow_old(goal)) return (TRUE); /*** Explore the dungeon ***/ /* Chase close monsters */ if (borg_flow_kill(FALSE, 35)) return (TRUE); /* Chase close objects */ if (borg_flow_take(FALSE, 35)) return (TRUE); /* Chase old monsters */ if (borg_flow_kill(FALSE, 250)) return (TRUE); /* Chase old objects */ if (borg_flow_take(FALSE, 250)) return (TRUE); /* Explore interesting grids */ if (borg_flow_dark(TRUE)) return (TRUE); /* Possibly leave the level (not bored) */ if (borg_leave_level(FALSE)) return (TRUE); /* Explore interesting grids */ if (borg_flow_dark(FALSE)) return (TRUE); /*** Deal with shops ***/ if (borg_find_shop()) return (TRUE); /*** Leave the Level ***/ /* Study/Test boring spells/prayers */ if (!goal_fleeing && borg_play_magic(TRUE)) return (TRUE); /* Search for secret doors */ if (borg_flow_spastic(FALSE)) return (TRUE); /* Recharge items before leaving the level */ if (borg_wait_recharge()) return (TRUE); /* Leave the level (bored) */ if (borg_leave_level(TRUE)) return (TRUE); /* Search for secret doors */ if (borg_flow_spastic(TRUE)) return (TRUE); /*** Wait for recall ***/ /* Wait for recall, unless in danger */ if (goal_recalling && borg_on_safe_feat(map_loc(c_x, c_y)->feat) && (borg_danger(c_x, c_y, 1, TRUE) <= 0)) { /* Take note */ borg_note("# Waiting for Recall..."); /* Rest until done */ borg_keypress('R'); borg_keypress('\n'); /* Done */ return (TRUE); } /*** Nothing to do ***/ /* Wait for daylight */ if (borg_waits_daylight()) return (TRUE); /* Try to cross the wilderness to do some fun shopping */ if (borg_find_town()) return (TRUE); /* Try to cross the wilderness to find a challenging dungeon */ if (borg_find_dungeon()) return (TRUE); /* Explore the wilderness */ if (borg_flow_dark_wild()) return (TRUE); /* Set a flag that the borg is not allowed to retreat for 5 rounds */ borg_no_retreat = 5; /* Boost slightly */ if (avoidance < bp_ptr->chp * 2) { bool done = FALSE; /* Note */ borg_note("# Boosting bravery (1) from %d to %d!", avoidance, bp_ptr->chp * 2); /* Hack -- ignore some danger */ avoidance = (bp_ptr->chp * 2); /* Forget the danger fields */ borg_danger_wipe = TRUE; /* Try anything */ if (borg_think_dungeon_brave()) done = TRUE; /* Reset "avoidance" */ avoidance = bp_ptr->chp; /* Re-calculate danger */ borg_danger_wipe = TRUE; /* Done */ if (done) return (TRUE); } /* Try phase before boosting bravery further and acting goofy */ borg_times_twitch++; /* Phase to get out of being twitchy up to 3 times per level. */ if (bp_ptr->depth && borg_times_twitch < 3) { borg_note("# Considering Phase (twitchy)"); /* Phase */ if (bp_ptr->able.phase && borg_caution_phase(15, 2) && (borg_spell(REALM_SORCERY, 0, 1) || borg_spell(REALM_TRUMP, 0, 0) || borg_spell(REALM_ARCANE, 0, 4) || borg_read_scroll(SV_SCROLL_PHASE_DOOR))) { /* Success */ return (TRUE); } } /* Set a flag that the borg is not allowed */ /* to retreat for 10 rounds */ borg_no_retreat = 10; /* Boost some more */ if (avoidance < bp_ptr->mhp * 4) { bool done = FALSE; /* Note */ borg_note("# Boosting bravery (2) from %d to %d!", avoidance, bp_ptr->mhp * 4); /* Hack -- ignore some danger */ avoidance = (bp_ptr->mhp * 4); /* Forget the danger fields */ borg_danger_wipe = TRUE; /* Try anything */ if (borg_think_dungeon_brave()) done = TRUE; /* Reset "avoidance" */ avoidance = bp_ptr->chp; /* Re-calculate danger */ borg_danger_wipe = TRUE; /* Done */ if (done) return (TRUE); } /* Boost a lot */ if (avoidance < 30000) { bool done = FALSE; /* Note */ borg_note("# Boosting bravery (3) from %d to %d!", avoidance, 30000); /* Hack -- ignore some danger */ avoidance = 30000; /* Forget the danger fields */ borg_danger_wipe = TRUE; /* Try anything */ if (borg_think_dungeon_brave()) done = TRUE; /* Reset "avoidance" */ avoidance = bp_ptr->chp; /* Re-calculate danger */ borg_danger_wipe = TRUE; /* Done */ if (done) return (TRUE); } /* try teleporting before acting goofy */ borg_times_twitch++; /* Teleport to get out of being twitchy up to 5 times per level. */ if (bp_ptr->depth && borg_times_twitch < 5) { borg_note("# Teleport (twitchy)"); /* Teleport */ if (borg_activate(BORG_ACT_TELEPORT) || borg_spell_fail(REALM_ARCANE, 2, 3, 45) || borg_spell_fail(REALM_TRUMP, 0, 4, 45) || borg_spell_fail(REALM_CHAOS, 0, 7, 45) || borg_spell_fail(REALM_SORCERY, 0, 5, 45) || borg_use_staff(SV_STAFF_TELEPORTATION) || borg_read_scroll(SV_SCROLL_TELEPORT)) { /* Success */ return (TRUE); } } /* Recall to town */ if (bp_ptr->depth && (borg_recall())) { /* Note */ borg_note("# Recalling (twitchy)"); /* Success */ return (TRUE); } /* Twitch around */ if (borg_twitchy()) return (TRUE); /* Oops */ return (FALSE); }
/* * Throw an object from the pack or floor. * * Note: "unseen" monsters are very hard to hit. * * Should throwing a weapon do full damage? Should it allow the magic * to hit bonus of the weapon to have an effect? Should it ever cause * the item to be destroyed? Should it do any damage at all? */ void do_cmd_throw(cmd_code code, cmd_arg args[]) { int dir, item; int i, j, y, x; s16b ty, tx; int chance, tdam, tdis; int weight; object_type *o_ptr; object_type *i_ptr; object_type object_type_body; bool hit_body = FALSE; byte missile_attr; char missile_char; char o_name[80]; u32b msg_type = 0; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor * op_ptr->delay_factor; /* Get item to throw and direction in which to throw it. */ item = args[0].item; dir = args[1].direction; /* Make sure the player isn't throwing wielded items */ if (item >= INVEN_WIELD && item < QUIVER_START) { msg_print("You have cannot throw wielded items."); return; } /* Check the item being thrown is usable by the player. */ if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR))) { msg_format("That item is not within your reach."); return; } /* Get the object */ o_ptr = object_from_item_idx(item); object_notice_on_firing(o_ptr); /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Distribute the charges of rods/wands/staves between the stacks */ distribute_charges(o_ptr, i_ptr, 1); /* Single object */ i_ptr->number = 1; /* Reduce and describe inventory */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Reduce and describe floor item */ else { floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } /* Description */ object_desc(o_name, sizeof(o_name), i_ptr, ODESC_FULL); /* Find the color and symbol for the object for throwing */ missile_attr = object_attr(i_ptr); missile_char = object_char(i_ptr); /* Enforce a minimum "weight" of one pound */ weight = ((i_ptr->weight > 10) ? i_ptr->weight : 10); /* Hack -- Distance -- Reward strength, penalize weight */ tdis = (adj_str_blow[p_ptr->state.stat_ind[A_STR]] + 20) * 10 / weight; /* Max distance of 10 */ if (tdis > 10) tdis = 10; /* Hack -- Base damage from thrown object */ tdam = damroll(i_ptr->dd, i_ptr->ds); if (!tdam) tdam = 1; tdam += i_ptr->to_d; /* Chance of hitting */ chance = (p_ptr->state.skills[SKILL_TO_HIT_THROW] + (p_ptr->state.to_h * BTH_PLUS_ADJ)); /* Take a turn */ p_ptr->energy_use = 100; /* Start at the player */ y = p_ptr->py; x = p_ptr->px; /* Predict the "target" location */ ty = p_ptr->py + 99 * ddy[dir]; tx = p_ptr->px + 99 * ddx[dir]; /* Check for "target request" */ if ((dir == 5) && target_okay()) { target_get(&tx, &ty); } /* Calculate the path */ path_n = project_path(path_g, tdis, p_ptr->py, p_ptr->px, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(); /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { /* Visual effects */ print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); Term_xtra(TERM_XTRA_DELAY, msec); light_spot(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); } /* Delay anyway for consistency */ else { /* Pause anyway, for consistancy */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x); int visible = m_ptr->ml; /* Note the collision */ hit_body = TRUE; /* Did we hit it (penalize range) */ if (test_hit(chance2, r_ptr->ac, m_ptr->ml)) { const char *hit_verb = "hits"; bool fear = FALSE; const slay_t *best_s_ptr = NULL; /* Assume a default death */ cptr note_dies = " dies."; /* Some monsters get "destroyed" */ if (monster_is_unusual(r_ptr)) { /* Special note at death */ note_dies = " is destroyed."; } /* Apply special damage - brought forward to fill in hit_verb XXX XXX XXX */ improve_attack_modifier(i_ptr, m_ptr, &best_s_ptr); if (best_s_ptr != NULL) { tdam *= best_s_ptr->mult; hit_verb = best_s_ptr->range_verb; } /* Apply special damage XXX XXX XXX */ tdam = critical_shot(i_ptr->weight, i_ptr->to_h, tdam, &msg_type); /* No negative damage; change verb if no damage done */ if (tdam <= 0) { tdam = 0; hit_verb = "fail to harm"; } /* Handle unseen monster */ if (!visible) { /* Invisible monster */ msg_format("The %s finds a mark.", o_name); } /* Handle visible monster */ else { char m_name[80]; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Tell the player what happened */ if (msg_type == MSG_SHOOT_HIT) message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name); else { if (msg_type == MSG_HIT_GOOD) { message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } } /* Hack -- Track this monster race */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Hack -- Track this monster */ if (m_ptr->ml) health_track(cave_m_idx[y][x]); } /* Learn the bonuses */ /* XXX Eddie This is messed up, better done for firing, */ /* should use that method [split last] instead */ /* check if inven_optimize removed what o_ptr referenced */ if (object_similar(i_ptr, o_ptr, OSTACK_PACK)) object_notice_attack_plusses(o_ptr); object_notice_attack_plusses(i_ptr); /* Complex message */ if (p_ptr->wizard) msg_format("You do %d (out of %d) damage.", tdam, m_ptr->hp); /* Hit the monster, check for death */ if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies)) { /* Dead monster */ } /* No death */ else { /* Message */ message_pain(cave_m_idx[y][x], tdam); /* Take note */ if (fear && m_ptr->ml) { char m_name[80]; /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); } } } /* Stop looking */ break; } } /* Chance of breakage (during attacks) */ j = (hit_body ? breakage_chance(i_ptr) : 0); /* Drop (or break) near that location */ drop_near(i_ptr, j, y, x, TRUE); }
/* * Actually perform all requested changes to the window * * If absolutely nothing has changed, not even temporarily, or if the * current "Term" is not mapped, then this function will return 1 and * do absolutely nothing. * * Note that when "soft_cursor" is true, we erase the cursor (if needed) * whenever anything has changed, and redraw it (if needed) after all of * the screen updates are complete. This will induce a small amount of * "cursor flicker" but only when the screen has been updated. If the * screen is updated and then restored, you may still get this flicker. * * When "soft_cursor" is not true, we make the cursor invisible before * doing anything else if it is supposed to be invisible by the time we * are done, and we make it visible after moving it to its final location * after all of the screen updates are complete. * * Note that "Term_xtra(TERM_XTRA_CLEAR,0)" must erase the entire screen, * including the cursor, if needed, and may place the cursor anywhere. * * Note that "Term_xtra(TERM_XTRA_FRESH,0)" will be called after * all of the rows have been "flushed". * * The helper functions currently "skip" any grids which already contain * the desired contents. This may or may not be the best method, especially * when the desired content fits nicely into the current stripe. For example, * it might be better to go ahead and queue them while allowed, but keep a * count of the "trailing skipables", then, when time to flush, or when a * "non skippable" is found, force a flush if there are too many skippables. * * Perhaps an "initialization" stage, where the "text" (and "attr") * buffers are "filled" with information, converting "blanks" into * a convenient representation, and marking "skips" with "zero chars", * and then some "processing" is done to determine which chars to skip. * * Currently, the helper functions are optimal for systems which prefer * to "print a char + move a char + print a char" to "print three chars", * and for applications that do a lot of "detailed" color printing. * * In the two "queue" functions, total "non-changes" are "pre-skipped". * The helper functions must also handle situations in which the contents * of a grid are changed, but then changed back to the original value, * and situations in which two grids in the same row are changed, but * the grids between them are unchanged. * * Normally, the "Term_wipe()" function is used only to display "blanks" * that were induced by "Term_clear()" or "Term_erase()", and then only * if the "attr_blank" and "char_blank" fields have not been redefined * to use "white space" instead of the default "black space". Actually, * the "Term_wipe()" function is used to display all "black" text, such * as the default "spaces" created by "Term_clear()" and "Term_erase()". * * Note that if no "black" text is ever drawn, and if "attr_blank" is * not "zero", then the "Term_wipe" hook will never be used. * * This function does nothing unless the "Term" is "mapped", which allows * certain systems to optimize the handling of "closed" windows. * * On systems with a "soft" cursor, we must explicitly erase the cursor * before flushing the output, if needed, to prevent a "jumpy" refresh. * The actual method for this is horrible, but there is very little that * we can do to simplify it efficiently. XXX XXX XXX * * On systems with a "hard" cursor, we will "hide" the cursor before * flushing the output, if needed, to avoid a "flickery" refresh. It * would be nice to *always* hide the cursor during the refresh, but * this might be expensive (and/or ugly) on some machines. * * The "Term->icky_corner" flag is used to avoid calling "Term_wipe()" * or "Term_pict()" or "Term_text()" on the bottom right corner of the * window, which might induce "scrolling" or other nasty stuff on old * dumb terminals. This flag is handled very efficiently. We assume * that the "Term_curs()" call will prevent placing the cursor in the * corner, if needed, though I doubt such placement is ever a problem. * Currently, the use of "Term->icky_corner" and "Term->soft_cursor" * together may result in undefined behavior. */ errr Term_fresh(void) { int x, y; int w = Term->wid; int h = Term->hgt; int y1 = Term->y1; int y2 = Term->y2; term_win *old = Term->old; term_win *scr = Term->scr; /* Do nothing unless "mapped" */ if (!Term->mapped_flag) return (1); /* Trivial Refresh */ if ((y1 > y2) && (scr->cu == old->cu) && (scr->cv == old->cv) && (scr->cx == old->cx) && (scr->cy == old->cy) && !(Term->total_erase)) { /* Nothing */ return (1); } /* Paranoia -- use "fake" hooks to prevent core dumps */ if (!Term->curs_hook) Term->curs_hook = Term_curs_hack; if (!Term->text_hook) Term->text_hook = Term_text_hack; /* Handle "total erase" */ if (Term->total_erase) { byte na = ATTR_BLANK; char nc = CHAR_BLANK; /* Physically erase the entire window */ Term_xtra(TERM_XTRA_CLEAR, 0); /* Hack -- clear all "cursor" data */ old->cv = old->cu = old->cx = old->cy = 0; /* Wipe each row */ for (y = 0; y < h; y++) { byte *aa = old->a[y]; char *cc = old->c[y]; /* Wipe each column */ for (x = 0; x < w; x++) { /* Wipe each grid */ *aa++ = na; *cc++ = nc; } } /* Redraw every row */ Term->y1 = y1 = 0; Term->y2 = y2 = h - 1; /* Redraw every column */ for (y = 0; y < h; y++) { Term->x1[y] = 0; Term->x2[y] = w - 1; } /* Forget "total erase" */ Term->total_erase = FALSE; } /* Cursor update -- Erase old Cursor */ if (Term->soft_cursor) { /* Cursor was visible */ if (!old->cu && old->cv) { int tx = old->cx; int ty = old->cy; byte *old_aa = old->a[ty]; char *old_cc = old->c[ty]; byte oa = old_aa[tx]; char oc = old_cc[tx]; /* Hack -- restore the actual character */ (void)((*Term->text_hook)(tx, ty, 1, oa, &oc)); } } /* Cursor Update -- Erase old Cursor */ else { /* Cursor will be invisible */ if (scr->cu || !scr->cv) { /* Make the cursor invisible */ Term_xtra(TERM_XTRA_SHAPE, 0); } } /* Something to update */ if (y1 <= y2) { /* Handle "icky corner" */ if (Term->icky_corner) { /* Avoid the corner */ if (y2 >= h - 1) { /* Avoid the corner */ if (Term->x2[h - 1] > w - 2) { /* Avoid the corner */ Term->x2[h - 1] = w - 2; } } } /* Scan the "modified" rows */ for (y = y1; y <= y2; ++y) { int x1 = Term->x1[y]; int x2 = Term->x2[y]; /* Flush each "modified" row */ if (x1 <= x2) { /* Flush the row */ Term_fresh_row_text(y, x1, x2); /* This row is all done */ Term->x1[y] = w; Term->x2[y] = 0; } } /* No rows are invalid */ Term->y1 = h; Term->y2 = 0; } /* Cursor update -- Show new Cursor */ if (Term->soft_cursor) { /* Draw the cursor */ if (!scr->cu && scr->cv) { /* Call the cursor display routine */ (void)((*Term->curs_hook)(scr->cx, scr->cy)); } } /* Cursor Update -- Show new Cursor */ else { /* The cursor is useless, hide it */ if (scr->cu) { /* Paranoia -- Put the cursor NEAR where it belongs */ (void)((*Term->curs_hook)(w - 1, scr->cy)); /* Make the cursor invisible */ /* Term_xtra(TERM_XTRA_SHAPE, 0); */ } /* The cursor is invisible, hide it */ else if (!scr->cv) { /* Paranoia -- Put the cursor where it belongs */ (void)((*Term->curs_hook)(scr->cx, scr->cy)); /* Make the cursor invisible */ /* Term_xtra(TERM_XTRA_SHAPE, 0); */ } /* The cursor is visible, display it correctly */ else { /* Put the cursor where it belongs */ (void)((*Term->curs_hook)(scr->cx, scr->cy)); /* Make the cursor visible */ Term_xtra(TERM_XTRA_SHAPE, 1); } } /* Save the "cursor state" */ old->cu = scr->cu; old->cv = scr->cv; old->cx = scr->cx; old->cy = scr->cy; /* Actually flush the output */ Term_xtra(TERM_XTRA_FRESH, 0); /* Success */ return (0); }
/* * Hack -- redraw the screen * * This command performs various low level updates, clears all the "extra" * windows, does a total redraw of the main window, and requests all of the * interesting updates and redraws that I can think of. * * This command is also used to "instantiate" the results of the user * selecting various things, such as graphics mode, so it must call * the "TERM_XTRA_REACT" hook before redrawing the windows. */ void do_cmd_redraw(void) { s32b j; term *old = Term; /* Hack -- react to changes */ Term_xtra(TERM_XTRA_REACT, 0); /* Combine and Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Update torch */ p_ptr->update |= (PU_TORCH); /* Update stuff */ p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS | PU_POWERS | PU_SANITY | PU_BODY); /* Forget view */ p_ptr->update |= (PU_UN_VIEW); /* Update view */ p_ptr->update |= (PU_VIEW); /* Update monster light */ p_ptr->update |= (PU_MON_LITE); /* Update monsters */ p_ptr->update |= (PU_MONSTERS); /* Redraw everything */ flag_bool(&p_ptr->redraw, FLAG_PR_WIPE); flag_bool(&p_ptr->redraw, FLAG_PR_BASIC); flag_bool(&p_ptr->redraw, FLAG_PR_EXTRA); flag_bool(&p_ptr->redraw, FLAG_PR_MAP); /* Window stuff */ flag_bool(&p_ptr->window, FLAG_PW_ALL); /* Hack -- update */ handle_stuff(); /* Redraw every window */ for (j = 0; j < 8; j++) { /* Dead window */ if (!angband_term[j]) continue; /* Activate */ Term_activate(angband_term[j]); /* Redraw */ Term_redraw(); /* Refresh */ Term_fresh(); /* Restore */ Term_activate(old); } }
/* * Modify the "window" options */ void do_cmd_options_win(void) { s32b j; call_lua("windows.configure", "()", ""); #if 0 s32b i, j, d; s32b y = 0; s32b x = 0; s32b ch; bool go = TRUE; u32b old_flag[8]; /* Memorize old flags */ for (j = 0; j < 8; j++) { /* Acquire current flags */ old_flag[j] = window_flag[j]; } /* Clear screen */ Term_clear(); /* Interact */ while (go) { /* Prompt XXX XXX XXX */ prt("Window Flags (<dir>, t, y, n, ESC) ", 0, 0); /* Display the windows */ for (j = 0; j < 8; j++) { byte a = TERM_WHITE; cptr s = angband_term_name[j]; /* Use color */ if (use_color && (j == x)) a = TERM_L_BLUE; /* Window name, staggered, centered */ Term_putstr(35 + j * 5 - strlen(s) / 2, 2 + j % 2, -1, a, s); } /* Display the options */ for (i = 0; i < 16; i++) { byte a = TERM_WHITE; cptr str = window_flag_desc[i]; /* Use color */ if (use_color && (i == y)) a = TERM_L_BLUE; /* Unused option */ if (!str) str = "(Unused option)"; /* Flag name */ Term_putstr(0, i + 5, -1, a, str); /* Display the windows */ for (j = 0; j < 8; j++) { byte a = TERM_WHITE; char c = '.'; /* Use color */ if (use_color && (i == y) && (j == x)) a = TERM_L_BLUE; /* Active flag */ if (window_flag[j] & (1L << i)) c = 'X'; /* Flag value */ Term_putch(35 + j * 5, i + 5, a, c); } } /* Place Cursor */ Term_gotoxy(35 + x * 5, y + 5); /* Get key */ ch = inkey(); /* Analyze */ switch (ch) { case ESCAPE: { go = FALSE; break; } case 'T': case 't': { /* Clear windows */ for (j = 0; j < 8; j++) { window_flag[j] &= ~(1L << y); } /* Clear flags */ for (i = 0; i < 16; i++) { window_flag[x] &= ~(1L << i); } /* Fall through */ } case 'y': case 'Y': { /* Ignore screen */ if (x == 0) break; /* Set flag */ window_flag[x] |= (1L << y); break; } case 'n': case 'N': { /* Clear flag */ window_flag[x] &= ~(1L << y); break; } default: { d = get_keymap_dir(ch); x = (x + ddx[d] + 8) % 8; y = (y + ddy[d] + 16) % 16; if (!d) bell(); break; } } } #endif /* Notice changes */ for (j = 1; j < 8; j++) { term *old = Term; /* Dead window */ if (!angband_term[j]) continue; /* Ignore non-changes */ // if (window_flag[j] == old_flag[j]) continue; /* Activate */ Term_activate(angband_term[j]); /* Erase */ Term_clear(); /* Refresh */ Term_fresh(); #ifdef USE_SDL Term_xtra(TERM_XTRA_WINVIS, (flag_used(&window_flag[j]) ? 1 : 0)); #endif /* Restore */ Term_activate(old); } }
/* * (From the Angband Borg by Ben Harrison & Dr Andrew White) * * This function lets the automaton "steal" control from the user. * * The "z-term.c" file provides a special hook which we use to * bypass the standard "Term_flush()" and "Term_inkey()" functions * and replace them with the function below. * * The only way that the automaton can be stopped once it is started, * unless it dies or encounters an error, is to press any key. * This function checks for user input on a regular basic, and * when any is encountered, it relinquishes control gracefully. * * Note that this function hook automatically removes itself when * it realizes that it should no longer be active. Note that this * may take place after the game has asked for the next keypress, * but the various "keypress" routines should be able to handle this. * * XXX XXX XXX We do not correctly handle the "take" flag */ char automaton_inkey_hack(int flush_first) { int i; char ch; // paranoia if (!p_ptr->automaton) { stop_automaton(); /* Nothing ready */ return (ESCAPE); } // flush key buffer if requested if (flush_first) { // only flush if needed if (automaton_inkey(FALSE) != 0) { // Flush keys ////automaton_flush(); currently not actually doing this as it stops us queuing a 'y' for stepping on traps } } // check for manual user abort (void)Term_inkey(&ch, FALSE, TRUE); // if a key is hit, stop the automaton if (ch > 0) { stop_automaton(); return (ESCAPE); } // check for a previously queued key, without taking it from the queue i = automaton_inkey(FALSE); // if it was empty and we need more keys if (!i) { // handle waiting for commands separately if (waiting_for_command) { // takes its turn by choosing some keys representing commands and queuing them automaton_turn(); // pause for a moment so the user can see what is happening Term_xtra(TERM_XTRA_DELAY, 25 * op_ptr->delay_factor); } else { /* Hack -- Process events (do not wait) */ (void)Term_xtra(TERM_XTRA_EVENT, FALSE); stop_automaton(); return (ESCAPE); } } // check for a previously queued key, taking it from the queue i = automaton_inkey(TRUE); // deal with empty queue if (!i) { // exit return('\0'); } // return the key chosen return (i); }
void Term_bell() { Term_xtra(TERM_XTRA_NOISE, 0); }