From: Martin Read Date: Tue, 21 Jan 2014 16:16:23 +0000 (+0000) Subject: Incremental checkpoint for project "No prose in the game engine" X-Git-Tag: printmsg-purged~33 X-Git-Url: http://git.blackswordsonics.com/?a=commitdiff_plain;h=273b0ba7b141ae872fa59685f4040953170aa821;p=victrix-abyssi Incremental checkpoint for project "No prose in the game engine" --- diff --git a/display-nc.cc b/display-nc.cc index 0c4df74..62e9eae 100644 --- a/display-nc.cc +++ b/display-nc.cc @@ -2,7 +2,7 @@ * \brief ncurses display support */ -/* Copyright 2005-2013 Martin Read +/* Copyright 2005-2014 Martin Read * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ PANEL *status_panel; PANEL *world_panel; PANEL *message_panel; PANEL *inventory_panel; +bool force_ascii; int wall_colour; int you_colour; @@ -60,55 +62,33 @@ int map_updated; int show_terrain; int hard_redraw; -attr_t colour_attrs[1 + LAST_COLOUR] = -{ - 0, - 0 | A_BOLD, - 0, - 0, - 0, - 0, - 0, - 0, - A_BOLD, - 0 | A_BOLD, - 0 | A_BOLD, - 0 | A_BOLD, - 0 | A_BOLD, - 0 | A_BOLD, - 0 | A_BOLD, - 0, - A_BOLD, - A_BOLD -}; - -short colour_cpairs[1 + LAST_COLOUR] = -{ - Gcol_l_grey, - Gcol_d_grey, - Gcol_red, - Gcol_blue, - Gcol_green, - Gcol_purple, - Gcol_brown, - Gcol_cyan, - Gcol_l_grey, - Gcol_red, - Gcol_blue, - Gcol_green, - Gcol_purple, - Gcol_brown, - Gcol_cyan, - /* Fancy colours */ - Gcol_cyan, // Iron = dark cyan - Gcol_brown, // Gold = yellow - Gcol_l_grey // Silver = white +struct Attr_wrapper +{ + attr_t attr; + short cpair; }; -attr_t terrain_attrs[NUM_TERRAINS] = +Attr_wrapper colour_data[1 + LAST_COLOUR] = { - 0, 0, 0, 0, - 0, 0, 0, 0 + { 0, Gcol_l_grey }, + { A_BOLD, Gcol_d_grey }, + { 0, Gcol_red }, + { 0, Gcol_blue }, + { 0, Gcol_green }, + { 0, Gcol_purple }, + { 0, Gcol_brown }, + { 0, Gcol_cyan }, + { A_BOLD, Gcol_l_grey }, + { A_BOLD, Gcol_red }, + { A_BOLD, Gcol_blue }, + { A_BOLD, Gcol_green }, + { A_BOLD, Gcol_purple }, + { A_BOLD, Gcol_brown }, + { A_BOLD, Gcol_cyan }, + /* Fancy colours */ + { 0, Gcol_cyan }, /* Iron = dark cyan */ + { A_BOLD, Gcol_brown }, /* Gold = yellow */ + { A_BOLD, Gcol_l_grey }, /* Silver = white */ }; cchar_t terrain_tiles[NUM_TERRAINS]; @@ -123,6 +103,7 @@ cchar_t permon_tiles[NUM_OF_PERMONS]; cchar_t blank_tile; cchar_t player_tile; cchar_t const *back_buffer[DUN_HEIGHT][DUN_WIDTH]; +Attr_wrapper attr_override[DISP_HEIGHT][DISP_WIDTH]; cchar_t const *front_buffer[DISP_HEIGHT][DISP_WIDTH]; /* Prototypes for static funcs */ @@ -265,6 +246,86 @@ static void draw_world(void) } } +static void load_unicode_tiles() +{ + int i; + { + wchar_t wch[2]; + wch[0] = L'@'; + wch[1] = 0; + setcchar(&player_tile, wch, 0, 0, NULL); + wch[0] = L' '; + setcchar(&blank_tile, wch, 0, 0, NULL); + } + for (i = 0; i < NUM_OF_PERMONS; ++i) + { + wchar_t wch[2]; + wch[0] = permons[i].sym; + wch[1] = 0; + setcchar(permon_tiles + i, wch, + colour_data[permons[i].colour].attr, + colour_data[permons[i].colour].cpair, NULL); + } + for (i = 0; i < NUM_TERRAINS; ++i) + { + wchar_t wch[2]; + /* policy decision: for now we don't support use of combining + * characters for terrain. */ + mbtowc(wch, terrain_props[i].unicode, 4); + wch[1] = 0; + setcchar(terrain_tiles + i, wch, + colour_data[terrain_props[i].colour].attr, + colour_data[terrain_props[i].colour].cpair, NULL); + } + for (i = 0; i < NUM_OF_PERMOBJS; ++i) + { + wchar_t wch[2]; + /* policy decision: for now we don't support use of combining + * characters for tiles. */ + mbtowc(wch, permobjs[i].unicode, 4); + wch[1] = 0; + setcchar(permobj_tiles + i, wch, 0, 0, NULL); + } +} + +static void load_ascii_tiles() +{ + int i; + { + wchar_t wch[2]; + wch[0] = L'@'; + wch[1] = 0; + setcchar(&player_tile, wch, 0, 0, NULL); + wch[0] = L' '; + setcchar(&blank_tile, wch, 0, 0, NULL); + } + for (i = 0; i < NUM_OF_PERMONS; ++i) + { + wchar_t wch[2]; + wch[0] = permons[i].sym; + wch[1] = 0; + setcchar(permon_tiles + i, wch, + colour_data[permons[i].colour].attr, + colour_data[permons[i].colour].cpair, NULL); + } + for (i = 0; i < NUM_TERRAINS; ++i) + { + wchar_t wch[2]; + wch[0] = terrain_props[i].ascii; + wch[1] = 0; + setcchar(terrain_tiles + i, wch, + colour_data[terrain_props[i].colour].attr, + colour_data[terrain_props[i].colour].cpair, NULL); + } + for (i = 0; i < NUM_OF_PERMOBJS; ++i) + { + wchar_t wch[2]; + wch[0] = permobjs[i].sym; + wch[1] = 0; + setcchar(permobj_tiles + i, wch, 0, 0, NULL); + } +} + /* extern funcs */ /*! \brief Wait for the user to press RETURN @@ -311,23 +372,47 @@ void display_update(void) int display_init(void) { int i; - char const *foo; - foo = getenv("LANG"); - if (foo) - { - setlocale(LC_CTYPE, foo); - } - else + int j; + char const *lang; + char const *ct; + char const *all; + char const *encoding; + + /* + * Yes, this code will misidentify the availability of meaningful wide + * characters on architectures where char is larger than 8 bits. + * + * It also treats all character encodings that are not UTF-8 as "ASCII". + * + * Contributions of additional display-[foo].cc modules that provide + * support for such architectures and/or character encodings will be + * considered. + */ + if (sizeof(wchar_t) > 1) { - foo = getenv("LC_CTYPE"); - if (foo) + lang = getenv("LANG"); + ct = getenv("LC_CTYPE"); + all = getenv("LC_ALL"); + if (all || lang || ct) { - setlocale(LC_CTYPE, foo); + setlocale(LC_ALL, ""); } else { + /* In the name of my narrowly defined concept of sanity, if the + * user has not configured any of the relevant locale envvars, + * force the C.UTF-8 locale. */ setlocale(LC_CTYPE, "C.UTF-8"); } + /* The only wire encodings I am willing to support are UTF-8 and + * ASCII. If you want support for other wire encodings, you can + * maintain your own patch for it. */ + encoding = nl_langinfo(CODESET); + force_ascii = strcmp(encoding, "UTF-8"); + } + else + { + force_ascii = true; } initscr(); noecho(); @@ -342,48 +427,32 @@ int display_init(void) init_pair(Gcol_cyan, COLOR_CYAN, COLOR_BLACK); wall_colour = Gcol_brown; you_colour = Gcol_white; + for (i = 0; i < DISP_HEIGHT; ++i) { - wchar_t wch[2]; - wch[0] = L'@'; - wch[1] = 0; - setcchar(&player_tile, wch, 0, 0, NULL); - wch[0] = L' '; - setcchar(&blank_tile, wch, 0, 0, NULL); - } - for (i = 0; i < NUM_OF_PERMONS; ++i) - { - wchar_t wch[2]; - wch[0] = permons[i].sym; - wch[1] = 0; - setcchar(permon_tiles + i, wch, colour_attrs[permons[i].colour], colour_cpairs[permons[i].colour], NULL); + for (j = 0; j < DISP_WIDTH; ++j) + { + } } - for (i = 0; i < NUM_TERRAINS; ++i) + if (force_ascii) { - wchar_t wch[2]; - /* policy decision: for now we don't support use of combining - * characters for terrain. */ - mbtowc(wch, terrain_props[i].unicode, 4); - wch[1] = 0; - setcchar(terrain_tiles + i, wch, terrain_attrs[i], colour_cpairs[terrain_props[i].colour], NULL); + load_ascii_tiles(); } - for (i = 0; i < NUM_OF_PERMOBJS; ++i) + else { - wchar_t wch[2]; - wch[0] = permobjs[i].sym; - wch[1] = 0; - setcchar(permobj_tiles + i, wch, 0, 0, NULL); + load_unicode_tiles(); } /* OK. We want a 21x21 viewport (player at centre), a 21x58 message * window, and a 2x80 status line. */ - status_window = newwin(2, 80, 22, 0); + status_window = newwin(2, 80, DISP_HEIGHT + 1, 0); status_panel = new_panel(status_window); - world_window = newwin(21, 21, 0, 0); + world_window = newwin(DISP_HEIGHT, DISP_WIDTH, 0, 0); world_panel = new_panel(world_window); - message_window = newwin(21, 58, 0, 22); + message_window = newwin(DISP_HEIGHT, 58, 0, DISP_WIDTH + 1); message_panel = new_panel(message_window); - inventory_window = newwin(22, 58, 0, 22); + inventory_window = newwin(DISP_HEIGHT, 58, 0, DISP_WIDTH + 1); inventory_panel = new_panel(inventory_window); - wattrset(inventory_window, colour_attrs[Gcol_l_grey]); + wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, + colour_data[Gcol_l_grey].cpair, NULL); hide_panel(inventory_panel); clear(); wclear(status_window); @@ -423,18 +492,19 @@ int read_input(char *buffer, int length) /*! \brief Print some text in the message window * - * \todo Handle the message window getting resized + * Calling print_msg() prints formatted text (printf-style) to the message + * window. It also calls display_update(), so any change to the map or + * the player should be flagged *before* print_msg() is called with the + * message announcing the change. + * + * \todo Handle the message window getting resized. + * \todo Implement message scrollback. + * \todo Put line breaks at word gaps in long messages. + * \todo Handle large volumes of messages between player turns. */ void print_msg(char const *fmt, ...) { va_list ap; - /* For now, assume (1) that the player will never be so inundated - * with messages that it's dangerous to let them just fly past (2) - * that messages will be of sane length and nicely formatted. THIS - * IS VERY BAD CODING PRACTICE! */ - /* Note that every message forces a call to display_update(). - * Events that cause changes to the map or the player should flag - * the change before calling printmsg. */ va_start(ap, fmt); vw_printw(message_window, fmt, ap); va_end(ap); @@ -442,6 +512,9 @@ void print_msg(char const *fmt, ...) } /*! \brief Set a message and whether 'nothing' should be listed in inventory + * + * \param s Message to set. + * \param allow_nil Whether the 'nothing' option should be listed. */ void set_inventory_message(char const *s, bool allow_nil) { @@ -460,7 +533,7 @@ void set_inventory_message(char const *s, bool allow_nil) */ void reset_inventory_message(void) { - wattrset(inventory_window, colour_attrs[Gcol_l_grey]); + wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, colour_data[Gcol_l_grey].cpair, NULL); mvwprintw(inventory_window, 0, 0, " === INVENTORY ==="); mvwprintw(inventory_window, 20, 0, " "); } @@ -474,7 +547,7 @@ void show_inv(void) doupdate(); } -/*! \brief Hide the inventory if necessary on this display type +/*! \brief Hide the inventory if necessary on this display type */ void hide_inv(void) { @@ -486,18 +559,18 @@ void hide_inv(void) /*! \brief Update the inventory window to reflect the filter in force * - * \todo Switch to using a function pointer + private argument for filtering + * \todo Switch to using a function pointer + private argument for filtering */ void update_inv(enum poclass_num filter) { int i; char inv_line[60]; - wattr_set(inventory_window, colour_attrs[Gcol_d_grey], Gcol_d_grey, NULL); + wattr_set(inventory_window, colour_data[Gcol_d_grey].attr, colour_data[Gcol_d_grey].cpair, NULL); for (i = 0; i < 19; i++) { if (u.inventory[i] == NO_OBJ) { - wattr_set(inventory_window, colour_attrs[Gcol_d_grey], Gcol_d_grey, NULL); + wattr_set(inventory_window, colour_data[Gcol_d_grey].attr, colour_data[Gcol_d_grey].cpair, NULL); mvwprintw(inventory_window, i + 1, 0, "%c) -----\n", 'a' + i); } else @@ -505,11 +578,11 @@ void update_inv(enum poclass_num filter) if ((filter == POCLASS_NONE) || (permobjs[objects[u.inventory[i]].obj_id].poclass == filter)) { - wattr_set(inventory_window, colour_attrs[Gcol_l_grey], Gcol_l_grey, NULL); + wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, colour_data[Gcol_l_grey].cpair, NULL); } else { - wattr_set(inventory_window, colour_attrs[Gcol_d_grey], Gcol_d_grey, NULL); + wattr_set(inventory_window, colour_data[Gcol_d_grey].attr, colour_data[Gcol_d_grey].cpair, NULL); } sprintf(inv_line, "%c) ", 'a' + i); sprint_obj_name(inv_line + 3, u.inventory[i], 45); @@ -550,11 +623,11 @@ int inv_select(enum poclass_num filter, char const *action, int accept_blank) print_msg("You have nothing to %s.\n", action); return SLOT_CANCEL; } - wattrset(inventory_window, colour_attrs[Gcol_l_grey]); + wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, colour_data[Gcol_l_grey].cpair, NULL); snprintf(msg, 58, "What do you want to %s?\n", action); set_inventory_message(msg, accept_blank); update_inv(filter); - wattrset(inventory_window, colour_attrs[Gcol_l_grey]); + wattr_set(inventory_window, colour_data[Gcol_l_grey].attr, colour_data[Gcol_l_grey].cpair, NULL); mvwprintw(inventory_window, 21, 17, "[ESC or SPACE to cancel]"); show_inv(); tryagain: @@ -680,9 +753,11 @@ Pass_fail select_dir(Offset *pstep) * * \todo Consider redesigning in a way friendlier to non-terminal platforms */ -Game_cmd get_command(void) +void get_player_action(Action *act) { int ch; + Pass_fail pf; + Offset step; while (1) { ch = wgetch(message_window); @@ -697,19 +772,69 @@ Game_cmd get_command(void) switch (ch) { case 'a': - return ATTACK; + { + act->cmd = ATTACK; + pf = select_dir(&step); + if (pf != You_fail) + { + act->details[0] = step.y; + act->details[1] = step.x; + return; + } + } + break; case '0': case ',': case 'g': - return GET_ITEM; + act->cmd = GET_ITEM; + /*! \todo revisit if we ever implement multiple items/square */ + return; case 'd': - return DROP_ITEM; + { + if (lvl.obj_at(u.pos) != NO_OBJ) + { + print_msg("There is already an item here.\n"); + } + else + { + int slot = inv_select(POCLASS_NONE, "drop", 0); + if (slot >= 0) + { + if ((u.inventory[slot] == u.ring) || + (u.inventory[slot] == u.armour)) + { + print_msg("You cannot drop something you are wearing.\n"); + } + else + { + act->cmd = DROP_ITEM; + act->details[0] = slot; + return; + } + } + } + } + break; case '@': - return DUMP_CHARA; + write_char_dump(); + break; case 'S': - return SAVE_GAME; + act->cmd = SAVE_GAME; + return; case 'X': - return QUIT; + { + int j = getYN("Really quit?\n"); + if (j > 0) + { + act->cmd = QUIT; + return; + } + else + { + print_msg("Never mind.\n"); + } + } + break; case 'i': if (panel_hidden(inventory_panel)) { @@ -721,77 +846,235 @@ Game_cmd get_command(void) { hide_inv(); } - continue; + break; case 'I': - return INSPECT_ITEM; + { + int slot = inv_select(POCLASS_NONE, "inspect", 0); + if ((slot != SLOT_CANCEL) && (u.inventory[slot] != NO_OBJ)) + { + describe_object(u.inventory[slot]); + } + } + break; case ';': - return EXAMINE_MONSTER; + print_msg("Monster examination not implemented yet.\n"); + break; case '#': - return SHOW_TERRAIN; - case '\x12': - return RNG_TEST; + show_terrain = 1; + touch_back_buffer(); + display_update(); + print_msg("Display of monsters and objects suppressed.\n"); + press_enter(); + show_terrain = 0; + touch_back_buffer(); + display_update(); + break; case '4': case 'h': - return MOVE_WEST; + { + act->cmd = WALK; + act->details[0] = West.y; + act->details[1] = West.x; + } + return; case '2': case 'j': - return MOVE_SOUTH; + { + act->cmd = WALK; + act->details[0] = South.y; + act->details[1] = South.x; + } + return; case '8': case 'k': - return MOVE_NORTH; + { + act->cmd = WALK; + act->details[0] = North.y; + act->details[1] = North.x; + } + return; case '6': case 'l': - return MOVE_EAST; + { + act->cmd = WALK; + act->details[0] = East.y; + act->details[1] = East.x; + } + return; case '7': case 'y': - return MOVE_NW; + { + act->cmd = WALK; + act->details[0] = Northwest.y; + act->details[1] = Northwest.x; + } + return; case '9': case 'u': - return MOVE_NE; + { + act->cmd = WALK; + act->details[0] = Northeast.y; + act->details[1] = Northeast.x; + } + return; case '1': case 'b': - return MOVE_SW; + { + act->cmd = WALK; + act->details[0] = Southwest.y; + act->details[1] = Southwest.x; + } + return; case '3': case 'n': - return MOVE_SE; + { + act->cmd = WALK; + act->details[0] = Southeast.y; + act->details[1] = Southeast.x; + } + return; case 'q': - return QUAFF_POTION; + { + int slot = inv_select(POCLASS_POTION, "quaff", 0); + if (slot != SLOT_CANCEL) + { + act->cmd = QUAFF_POTION; + act->details[0] = slot; + return; + } + } + break; case 'r': - return READ_SCROLL; + { + int slot = inv_select(POCLASS_SCROLL, "read", 0); + if (slot != SLOT_CANCEL) + { + act->cmd = READ_SCROLL; + act->details[0] = slot; + return; + } + } + break; case 'e': - return EAT_FOOD; - case 't': - return THROW_FLASK; + { + int slot = inv_select(POCLASS_FOOD, "eat", 0); + if (slot != SLOT_CANCEL) + { + act->cmd = EAT_FOOD; + act->details[0] = slot; + return; + } + } + break; + /*case 't': + // nobbling flask-throwing for now, as part of the general + // revisting of ranged combat. + return THROW_FLASK;*/ case 'w': - return WIELD_WEAPON; + { + int slot = inv_select(POCLASS_WEAPON, "wield", 1); + if (slot != SLOT_CANCEL) + { + if (slot == SLOT_NOTHING && u.weapon == NO_OBJ) + { + print_msg("Already empty-handed.\n"); + } + else + { + act->cmd = WIELD_WEAPON; + act->details[0] = slot; + return; + } + } + } + break; case 'z': - return ZAP_WEAPON; + if (u.weapon == NO_OBJ) + { + print_msg("You cannot zap your weapon when you aren't wielding one.\n"); + } + else + { + act->cmd = ZAP_WEAPON; + return; + } + break; case 'W': - return WEAR_ARMOUR; + { + int slot = inv_select(POCLASS_ARMOUR, "wear", 1); + if (slot != SLOT_CANCEL) + { + act->cmd = WEAR_ARMOUR; + act->details[0] = slot; + return; + } + } + break; case 'T': - return TAKE_OFF_ARMOUR; + act->cmd = TAKE_OFF_ARMOUR; + return; case 'E': - return EMANATE_ARMOUR; + act->cmd = EMANATE_ARMOUR; + return; case 'P': - return PUT_ON_RING; + if (u.ring != NO_OBJ) + { + print_msg("You are already wearing a magic ring. Remove it first.\n"); + } + else + { + int slot = inv_select(POCLASS_RING, "put on", 0); + if (slot != SLOT_CANCEL) + { + act->cmd = PUT_ON_RING; + act->details[0] = slot; + return; + } + } + break; case 'R': - return REMOVE_RING; + if (u.ring == NO_OBJ) + { + print_msg("You have no ring to remove!\n"); + } + else if (ring_removal_unsafe(Noise_std) == You_pass) + { + act->cmd = REMOVE_RING; + return; + } + break; case 'm': - return MAGIC_RING; + if (u.ring == NO_OBJ) + { + print_msg("You are not wearing a ring.\n"); + } + else + { + act->cmd = MAGIC_RING; + return; + } + break; case '?': - return GIVE_HELP; + print_help(); + break; case '>': - return GO_DOWN_STAIRS; + act->cmd = GO_DOWN_STAIRS; + return; case '5': case '.': - return STAND_STILL; + act->cmd = STAND_STILL; + return; case '\x04': - return WIZARD_DESCEND; + act->cmd = WIZARD_DESCEND; + return; case '\x05': - return WIZARD_LEVELUP; + act->cmd = WIZARD_LEVELUP; + return; } } - return QUIT; + print_msg("BUG: broke out of input loop!\n"); + act->cmd = QUIT; + return; } /*! \brief Shut down the display subsystem @@ -949,5 +1232,211 @@ void touch_one_screen(Coord c) } } -/* display.c */ +/* And now for the API fun that is "moving all print_msg() calls out of the + * engine code". Which we will do one step at a time. */ + +void notify_level_gain(void) +{ + status_updated = 1; + print_msg("You gained a level!\n"); +} + +void notify_agility_gain(int amount) +{ + status_updated = 1; + print_msg("You gained %d Agility.\n", amount); +} + +void notify_body_gain(int amount) +{ + status_updated = 1; + print_msg("You gained %d Body.\n", amount); +} + +void notify_hp_gain(int amount) +{ + status_updated = 1; + print_msg("You gained %d hit points.\n", amount); +} + +void notify_player_teleport(void) +{ + print_msg("You are whisked away!\n"); +} + + +void notify_player_telefail(void) +{ + print_msg("You feel briefly dislocated.\n"); +} + +void notify_player_regen(void) +{ + print_msg("Your ring pulses soothingly.\n"); +} + +void notify_hunger_level(int severity) +{ + switch (severity) + { + case 0: + default: + break; + case 1: + print_msg("You are getting quite hungry.\n"); + break; + case 2: + print_msg("You are feeling hunger pangs, and will recover\nmore slowly from your injuries.\n"); + break; + } +} + +void notify_leadfoot_recovered(void) +{ + print_msg("You shed your feet of lead.\n"); +} + +void notify_armourmelt_recovered(void) +{ + print_msg("Your armour seems solid once more.\n"); +} + +void notify_wither_recovered(void) +{ + print_msg("Your limbs straighten.\n"); +} + +void notify_protection_lost(void) +{ + print_msg("You feel like you are no longer being helped.\n"); +} + +void notify_start_lavawalk(void) +{ + print_msg("You walk on the lava.\n"); +} + +void notify_blocked_lava(void) +{ + print_msg("The fierce heat of the molten rock repels you.\n"); +} + +void notify_start_waterwalk(void) +{ + print_msg("You walk on the water.\n"); +} + +void notify_blocked_water(void) +{ + print_msg("The idiot who raised you never taught you to swim.\n"); +} + +void notify_obj_at(Coord c) +{ + print_msg("You see here "); + print_obj_name(lvl.obj_at(c)); + print_msg(".\n"); +} + +void debug_move_oob(Coord c) +{ + print_msg("NOTICE: Attempted move out of bounds (dest %d, %d)\n", c.y, c.x); +} + +void debug_agility_gain(int amount) +{ + print_msg("BUG: Attempt to cause negative agility gain %d\n", amount); +} + +void debug_body_gain(int amount) +{ + print_msg("BUG: Attempt to cause negative body gain %d\n", amount); +} + +void notify_swing_bow(void) +{ + print_msg("You can't use that weapon in melee!\n"); +} + +void notify_cant_go(void) +{ + print_msg("You cannot go there.\n"); +} + +void notify_wasted_gain(void) +{ + print_msg("You feel disappointed.\n"); +} + +void debug_bad_monspell(int spell) +{ + print_msg("BUG: Attempt by monster to cast bogus/unimplemented spell %d!\n", spell); +} + +void notify_summon_help(int mon, bool success) +{ + /* Do the summoning... */ + print_mon_name(mon, 3); + print_msg(" calls for help...\n"); + if (success) + { + print_msg("... and gets it.\n"); + } + else + { + print_msg("... luckily for you, help wasn't listening.\n"); + } +} + +void notify_mon_disappear(int mon) +{ + print_mon_name(mon, 3); + print_msg(" vanishes in a puff of smoke.\n"); +} + +void notify_start_armourmelt(void) +{ + status_updated = 1; + print_msg("Your armour seems suddenly no stronger than dust!\n"); +} + +void notify_start_leadfoot(void) +{ + status_updated = 1; + print_msg("Your feet feel like lead!\n"); +} + +void notify_start_withering(void) +{ + status_updated = 1; + print_msg("Your limbs twist and wither!\n"); +} + +void notify_necrosmite_fail(void) +{ + print_msg("Darkness reaches towards you, but dissolves.\n"); +} + +void notify_necrosmite_hit(void) +{ + print_msg("Soul-chilling darkness engulfs you!\n"); +} + +void notify_moncurse_fail(void) +{ + print_msg("A malignant aura surrounds you briefly.\n"); +} + +void notify_hellfire_hit(bool resisted) +{ + print_msg("The fires of hell %s\n", resisted ? "lightly singe you." : "burn you!"); +} + +void notify_monster_cursing(int mon) +{ + print_mon_name(mon, 3); + print_msg(" points at you and curses horribly.\n"); +} + +/* display-nc.cc */ // vim:cindent diff --git a/display.hh b/display.hh index 6a185d9..6389df4 100644 --- a/display.hh +++ b/display.hh @@ -38,7 +38,7 @@ extern int display_shutdown(void); extern void newsym(Coord c); extern void touch_back_buffer(void); extern int inv_select(enum poclass_num filter, char const *action, int accept_blank); -extern Game_cmd get_command(void); +extern void get_player_action(Action *act); extern Pass_fail select_dir(Offset *pstep); extern int getYN(char const *msg); extern int getyn(char const *msg); @@ -54,7 +54,47 @@ extern int map_updated; /* "Show the player the terrain only" flag. */ extern int show_terrain; +/* Notification functions */ +void notify_level_gain(void); +void notify_agility_gain(int amount); +void notify_body_gain(int amount); +void notify_hp_gain(int amount); +void notify_player_teleport(void); +void notify_player_telefail(void); +void notify_player_regen(void); +void notify_hunger_level(int severity); +void notify_leadfoot_recovered(void); +void notify_armourmelt_recovered(void); +void notify_wither_recovered(void); +void notify_protection_lost(void); +void notify_start_lavawalk(void); +void notify_blocked_lava(void); +void notify_start_waterwalk(void); +void notify_blocked_water(void); +void notify_obj_at(Coord c); +void notify_swing_bow(void); +void notify_cant_go(void); +void notify_wasted_gain(void); + +/* Sorcery notifications */ +void notify_summon_help(int mon, bool success); +void notify_monster_cursing(int mon); +void notify_mon_disappear(int mon); +void notify_moncurse_fail(void); +void notify_start_armourmelt(void); +void notify_start_withering(void); +void notify_start_leadfoot(void); +void notify_necrosmite_fail(void); +void notify_necrosmite_hit(void); +void notify_hellfire_hit(bool resisted); + +/* Debugging notifications */ +void debug_move_oob(Coord c); +void debug_body_gain(int amount); +void debug_agility_gain(int amount); +void debug_bad_monspell(int spell); + #endif -/* display.h */ +/* display.hh */ // vim:cindent diff --git a/main.cc b/main.cc index f3deb6d..f48c359 100644 --- a/main.cc +++ b/main.cc @@ -224,40 +224,20 @@ void new_game(void) print_msg("Initialisation complete.\n"); } -Action_cost do_command(Game_cmd cmd) +Action_cost do_player_action(Action *act) { - int i; - int j; - Pass_fail pf; int slot; Action_cost cost; Offset step; - switch (cmd) + switch (act->cmd) { - case MOVE_NORTH: - return move_player(North); - case MOVE_SOUTH: - return move_player(South); - case MOVE_EAST: - return move_player(East); - case MOVE_WEST: - return move_player(West); - case MOVE_NW: - return move_player(Northwest); - case MOVE_NE: - return move_player(Northeast); - case MOVE_SE: - return move_player(Southeast); - case MOVE_SW: - return move_player(Southwest); + case WALK: + step.y = act->details[0]; + step.x = act->details[1]; + return move_player(step); case ATTACK: - pf = select_dir(&step); - if (pf != You_fail) - { - return player_attack(step); - } - return Cost_none; + return player_attack(step); case GET_ITEM: if (lvl.obj_at(u.pos) != NO_OBJ) @@ -272,22 +252,16 @@ Action_cost do_command(Game_cmd cmd) } case WIELD_WEAPON: - cost = Cost_none; - slot = inv_select(POCLASS_WEAPON, "wield", 1); + slot = act->details[0]; if (slot == SLOT_NOTHING) { - u.weapon = NO_OBJ; - print_msg("Weapon unwielded.\n"); + return player_unwield(Noise_std); } - else if (slot != SLOT_CANCEL) + else { - u.weapon = u.inventory[slot]; - cost = Cost_std; - print_msg("Wielding "); - print_obj_name(u.weapon); - print_msg(".\n"); + return player_wield(slot, Noise_std); } - return cost; + break; case WEAR_ARMOUR: cost = Cost_none; @@ -361,10 +335,6 @@ Action_cost do_command(Game_cmd cmd) return Cost_none; } - case GIVE_HELP: - print_help(); - return Cost_none; - case GO_DOWN_STAIRS: if (lvl.terrain_at(u.pos) == STAIRS) { @@ -381,163 +351,38 @@ Action_cost do_command(Game_cmd cmd) return Cost_std; case READ_SCROLL: - slot = inv_select(POCLASS_SCROLL, "read", 0); - if (slot != SLOT_CANCEL) - { - return read_scroll(u.inventory[slot]); - } - return Cost_none; + slot = act->details[0]; + return read_scroll(u.inventory[slot]); case EAT_FOOD: - slot = inv_select(POCLASS_FOOD, "eat", 0); - if (slot != SLOT_CANCEL) - { - return eat_food(u.inventory[slot]); - } - return Cost_none; + slot = act->details[0]; + return eat_food(u.inventory[slot]); case QUAFF_POTION: - slot = inv_select(POCLASS_POTION, "quaff", 0); - if (slot != SLOT_CANCEL) - { - return quaff_potion(u.inventory[slot]); - } - return Cost_none; + slot = act->details[0]; + return quaff_potion(u.inventory[slot]); case THROW_FLASK: - slot = inv_select(POCLASS_FLASK, "throw", 0); - if (slot != SLOT_CANCEL) - { - pf = select_dir(&step); - if (pf != You_fail) - { - return throw_flask(u.inventory[slot], step); - } - } return Cost_none; case REMOVE_RING: - cost = Cost_none; - if (u.ring == NO_OBJ) - { - print_msg("You have no ring to remove!\n"); - } - else if ((lvl.terrain_at(u.pos) == LAVA) && (u.resistances[DT_FIRE] == RESIST_RING)) - { - print_msg("That ring is your only current source of fire resistance. Removing\nit here would incinerate you.\n"); - } - else if ((objects[u.ring].obj_id == PO_FROST_RING) && (lvl.terrain_at(u.pos) == WATER)) - { - print_msg("Since nobody ever taught you to swim, removing that ring\nhere would result in your death by drowning.\n"); - } - else - { - print_msg("You remove your ring.\n"); - u.ring = NO_OBJ; - cost = Cost_std; - } - return cost; + return remove_ring(); + case PUT_ON_RING: - cost = Cost_none; - if (u.ring != NO_OBJ) - { - print_msg("You are already wearing a ring.\n"); - } - else - { - slot = inv_select(POCLASS_RING, "put on", 0); - if (slot != SLOT_CANCEL) - { - u.ring = u.inventory[slot]; - print_msg("You put on "); - print_obj_name(u.ring); - print_msg(".\n"); - cost = Cost_std; - } - } - return cost; - case INSPECT_ITEM: - slot = inv_select(POCLASS_NONE, "inspect", 0); - if ((slot != SLOT_CANCEL) && (u.inventory[slot] != NO_OBJ)) - { - describe_object(u.inventory[slot]); - } - return Cost_none; - case EXAMINE_MONSTER: - print_msg("Monster examination not implemented yet.\n"); - return Cost_none; - case SHOW_TERRAIN: - show_terrain = 1; - touch_back_buffer(); - display_update(); - print_msg("Display of monsters and objects suppressed.\n"); - press_enter(); - show_terrain = 0; - touch_back_buffer(); - display_update(); - return Cost_none; - case RNG_TEST: - { - int odds = 0; - int evens = 0; - for (i = 0; i < 100000; i++) - { - if (zero_die(2)) - { - odds++; - } - else - { - evens++; - } - } - print_msg("100k rolls: 0 %d, 1 %d\n", odds, evens); - } - print_msg(" 2: %d %d %d %d %d %d %d %d\n", zero_die(2), zero_die(2), zero_die(2), zero_die(2), zero_die(2), zero_die(2), zero_die(2), zero_die(2)); - print_msg(" 8: %d %d %d %d %d %d %d %d\n", zero_die(8), zero_die(8), zero_die(8), zero_die(8), zero_die(8), zero_die(8), zero_die(8), zero_die(8)); - print_msg("32: %d %d %d %d %d %d %d %d\n", zero_die(32), zero_die(32), zero_die(32), zero_die(32), zero_die(32), zero_die(32), zero_die(32), zero_die(32)); - return Cost_none; + slot = act->details[0]; + return put_on_ring(u.inventory[slot]); + case DROP_ITEM: - cost = Cost_none; - if (lvl.obj_at(u.pos) != NO_OBJ) - { - print_msg("There is already an item here.\n"); - } - else - { - slot = inv_select(POCLASS_NONE, "drop", 0); - if (slot >= 0) - { - if ((u.inventory[slot] != NO_OBJ) && - ((u.inventory[slot] == u.ring) || - (u.inventory[slot] == u.armour))) - { - print_msg("You cannot drop something you are wearing.\n"); - } - else - { - cost = drop_obj(slot); - } - } - } - return cost; - case DUMP_CHARA: - write_char_dump(); - return Cost_none; + slot = act->details[0]; + return drop_obj(slot); + case SAVE_GAME: game_finished = 1; save_game(); return Cost_none; + case QUIT: - j = getYN("Really quit?\n"); - if (j > 0) - { - game_finished = 1; - } - else - { - print_msg("Never mind.\n"); - } + game_finished = 1; return Cost_none; case WIZARD_DESCEND: @@ -571,7 +416,6 @@ Action_cost do_command(Game_cmd cmd) void main_loop(void) { - Game_cmd cmd; int i; int action_speed; print_msg("Welcome to the Abyss, Princess %s.\n", u.name); @@ -594,22 +438,17 @@ void main_loop(void) /* Player is always speed 1, for now. */ if (action_speed <= u.speed) { - i = 0; - while (!i) + Action act; + Action_cost cost = Cost_none; + do { - /* Take commands until the player does - * something that uses an action. */ - cmd = get_command(); - i = do_command(cmd); + get_player_action(&act); + cost = do_player_action(&act); if (game_finished) { break; } - } - if (game_finished) - { - break; - } + } while (cost == Cost_none); } for (i = 0; i < 100; i++) { diff --git a/map.cc b/map.cc index 09f106a..6b9a603 100644 --- a/map.cc +++ b/map.cc @@ -140,6 +140,10 @@ static void run_random_walk(Coord oc, rwalk_mod_funcptr func, } +/*! \brief Entry point for level generation. + * + * \todo Maybe implement support for Lua-based level generators. + */ void build_level(void) { int theme_roll; diff --git a/objects.cc b/objects.cc index 9059a47..2e522bf 100644 --- a/objects.cc +++ b/objects.cc @@ -192,11 +192,11 @@ Action_cost eat_food(int obj) print_msg("Vile power suffuses your body as you devour the devil\nspleen.\n"); if (zero_die(2)) { - gain_body(1, 1); + gain_body(1); } else { - gain_agility(1, 1); + gain_agility(1); } } else if (u.food < 0) @@ -220,10 +220,10 @@ Action_cost quaff_potion(int obj) switch (optr->obj_id) { case PO_BODY_POTION: - gain_body(1, 1); + gain_body(1); break; case PO_AGILITY_POTION: - gain_agility(1, 1); + gain_agility(1); break; case PO_HEALING_POTION: { @@ -808,5 +808,89 @@ Action_cost zap_weapon(void) } } -/* objects.c */ +/*! \brief Unwield the player's currently equipped weapon + * + * \todo Stickycurse? + * \todo Life-essential resistances? + */ +Action_cost player_unwield(Noisiness noisy) +{ + if (u.weapon == NO_OBJ) + { + print_msg("BUG: got to player_unwield() with no weapon wielded - have a quiet word with your HCI module's author, please.\n"); + return Cost_none; + } + u.weapon = NO_OBJ; + if (noisy == Noise_std) + { + print_msg("Weapon unwielded.\n"); + } + return Cost_std; +} + +Action_cost player_wield(int slot, Noisiness noisy) +{ + if (u.weapon != NO_OBJ) + { + player_unwield(Noise_low); + } + u.weapon = u.inventory[slot]; + print_msg("Wielding "); + print_obj_name(u.weapon); + print_msg(".\n"); + recalc_defence(); + return Cost_std; +} + +Action_cost put_on_ring(int obj) +{ + if (u.ring != NO_OBJ) + { + print_msg("BUG: calling put_on_ring with ring already equipped.\n"); + return Cost_none; + } + if (!objects[obj].with_you) + { + print_msg("BUG: attempting to put on uncarried ring.\n"); + return Cost_none; + } + u.ring = obj; + recalc_defence(); + return Cost_std; +} + +Action_cost remove_ring(void) +{ + if (u.ring == NO_OBJ) + { + print_msg("BUG: calling remove_ring with no ring equipped.\n"); + return Cost_none; + } + u.ring = NO_OBJ; + recalc_defence(); + return Cost_std; +} + +Pass_fail ring_removal_unsafe(Noisiness noisy) +{ + if ((lvl.terrain_at(u.pos) == LAVA) && (u.resistances[DT_FIRE] == RESIST_RING)) + { + if (noisy != Noise_silent) + { + print_msg("That ring is your only current source of fire resistance. Removing it here would incinerate you.\n"); + } + return You_fail; + } + else if ((objects[u.ring].obj_id == PO_FROST_RING) && (lvl.terrain_at(u.pos) == WATER)) + { + if (noisy != Noise_silent) + { + print_msg("Since nobody ever taught you to swim, removing that ring here would result in your death by drowning.\n"); + } + return You_fail; + } + return You_pass; +} + +/* objects.cc */ // vim:cindent diff --git a/objects.hh b/objects.hh index 40c1506..63da4b0 100644 --- a/objects.hh +++ b/objects.hh @@ -94,12 +94,21 @@ extern bool consume_obj(int obj); extern int create_obj_class(enum poclass_num pocl, int quantity, bool with_you, Coord c); extern Action_cost drop_obj(int inv_idx); +extern Action_cost put_on_ring(int obj); +extern Action_cost remove_ring(void); +extern Action_cost wear_armour(int obj); +extern Action_cost take_off_armour(void); extern Action_cost read_scroll(int obj); extern Action_cost quaff_potion(int obj); extern Action_cost eat_food(int obj); extern Action_cost magic_ring(void); extern Action_cost emanate_armour(void); extern Action_cost zap_weapon(void); +extern Action_cost player_unwield(Noisiness noisy = Noise_std); +extern Action_cost player_wield(int slot, Noisiness noisy = Noise_std); + +extern Pass_fail ring_removal_unsafe(Noisiness noisy = Noise_std); +extern Pass_fail armour_removal_unsafe(Noisiness noisy = Noise_std); #endif diff --git a/sorcery.cc b/sorcery.cc index 18c1b41..e25f62b 100644 --- a/sorcery.cc +++ b/sorcery.cc @@ -339,7 +339,7 @@ int mon_use_sorcery(int mon) default: /* If this happens, we're trying to cast an unimplemented * spell. */ - print_msg("Can't happen: Bogus spell %d!\n", to_cast); + debug_bad_monspell(to_cast); rval = -1; break; @@ -367,24 +367,13 @@ int mon_use_sorcery(int mon) case MS_TELEPORT_AND_SUMMON: mptr->next_summon = game_tick + 1000; - /* Do the summoning... */ - print_mon_name(mon, 3); - print_msg(" calls for help...\n"); /* (Try to) summon 2-6 monsters. */ i = summoning(mptr->pos, dice(2, 3)); - if (i == 0) - { - print_msg("... luckily for you, help wasn't listening.\n"); - } - else - { - print_msg("... and gets it.\n"); - } + notify_summon_help(mon, (i > 0)); /* ... and fall through. */ case MS_TELEPORT_ESCAPE: - print_mon_name(mon, 3); - print_msg(" vanishes in a puff of smoke.\n"); teleport_mon(mon); + notify_mon_disappear(mon); break; case MS_TELEPORT_ASSAULT: @@ -394,68 +383,68 @@ int mon_use_sorcery(int mon) break; case MS_CURSE_ARMOURMELT: - mon_curses(mon); + notify_monster_cursing(mon); if (u.protection) { - malignant_aura(); + notify_moncurse_fail(); } else { u.armourmelt = 10 + one_die(10); - print_msg("Your armour seems suddenly no stronger than dust!\n"); + recalc_defence(); + notify_start_armourmelt(); } break; case MS_CURSE_LEADFOOT: - mon_curses(mon); + notify_monster_cursing(mon); if (u.protection) { - malignant_aura(); + notify_moncurse_fail(); } else { u.leadfoot = 10 + one_die(10); - print_msg("Your feet feel like lead!\n"); + recalc_defence(); + notify_start_leadfoot(); } break; case MS_CURSE_WITHERING: - mon_curses(mon); + notify_monster_cursing(mon); if (u.protection) { - malignant_aura(); + notify_moncurse_fail(); } else { u.withering = 10 + one_die(10); - print_msg("Your limbs twist and wither!\n"); + recalc_defence(); + notify_start_withering(); } break; case MS_NECRO_SMITE: - mon_curses(mon); + notify_monster_cursing(mon); if (u.resists(DT_NECRO)) { - print_msg("Darkness reaches towards you, but dissolves.\n"); + notify_necrosmite_fail(); } else { - print_msg("Soul-chilling darkness engulfs you!\n"); damage_u(dice(1, 20), DEATH_KILLED_MON, permons[monsters[mon].mon_id].name); } break; case MS_FIRE_COLUMN: - mon_curses(mon); - print_msg("The fires of hell "); + notify_monster_cursing(mon); + notify_hellfire_hit(u.resists(DT_FIRE)); if (u.resists(DT_FIRE)) { - print_msg("lightly singe you.\n"); damage_u(dice(1, 5), DEATH_KILLED_MON, permons[monsters[mon].mon_id].name); } else { - print_msg("burn you!\n"); damage_u(dice(1, 20), DEATH_KILLED_MON, permons[monsters[mon].mon_id].name); } break; @@ -463,16 +452,5 @@ int mon_use_sorcery(int mon) return rval; } -void malignant_aura() -{ - print_msg("A malignant aura surrounds you briefly.\n"); -} - -void mon_curses(int mon) -{ - print_mon_name(mon, 3); - print_msg(" points at you and curses horribly.\n"); -} - -/* sorcery.c */ +/* sorcery.cc */ // vim:cindent diff --git a/u.cc b/u.cc index 7e02d3d..ea8f2a5 100644 --- a/u.cc +++ b/u.cc @@ -89,7 +89,7 @@ Action_cost move_player(Offset delta) if ((c.y < 0) || (c.y >= DUN_HEIGHT) || (c.x < 0) || (c.x >= DUN_WIDTH)) { - print_msg("Attempted move out of bounds.\n"); + debug_move_oob(c); return Cost_none; /* No movement. */ } if (lvl.mon_at(c) != NO_MON) @@ -100,7 +100,7 @@ Action_cost move_player(Offset delta) (objects[u.weapon].obj_id == PO_CROSSBOW) || (objects[u.weapon].obj_id == PO_THUNDERBOW)) { - print_msg("You can't use that weapon in melee!\n"); + notify_swing_bow(); return Cost_none; } } @@ -114,7 +114,7 @@ Action_cost move_player(Offset delta) case IRON_WALL: case SKIN_WALL: case BONE_WALL: - print_msg("You cannot go there.\n"); + notify_cant_go(); return Cost_none; case FLOOR: case AMETHYST_FLOOR: @@ -131,14 +131,14 @@ Action_cost move_player(Offset delta) { if (lvl.terrain_at(u.pos) != LAVA) { - print_msg("You walk on the lava.\n"); + notify_start_lavawalk(); } reloc_player(c); return Cost_std; } else { - print_msg("The fierce heat of the molten rock repels you.\n"); + notify_blocked_lava(); return Cost_none; } case WATER: @@ -146,14 +146,14 @@ Action_cost move_player(Offset delta) { if (lvl.terrain_at(u.pos) != WATER) { - print_msg("You walk on the water.\n"); + notify_start_waterwalk(); } reloc_player(c); return Cost_std; } else { - print_msg("The idiot who raised you never taught you to swim.\n"); + notify_blocked_water(); return Cost_none; } } @@ -171,17 +171,16 @@ void reloc_player(Coord c) display_update(); if (lvl.obj_at(c) != NO_OBJ) { - print_msg("You see here "); - print_obj_name(lvl.obj_at(c)); - print_msg(".\n"); + notify_obj_at(c); } } -int gain_body(int amount, int loud) +int gain_body(int amount) { if (amount < 1) { - print_msg("Absurd body gain %d\n", amount); + debug_body_gain(amount); + return 0; } if (u.body < 99) { @@ -191,19 +190,12 @@ int gain_body(int amount, int loud) } u.body += amount; status_updated = 1; - if (loud) - { - print_msg("You feel stronger!\n"); - } - else - { - display_update(); - } + notify_body_gain(amount); return amount; } else { - print_msg("You feel disappointed.\n"); + notify_wasted_gain(); return 0; } } @@ -229,11 +221,12 @@ int drain_body(int amount, char const *what, int permanent) return 0; } -int gain_agility(int amount, int loud) +int gain_agility(int amount) { if (amount < 1) { - print_msg("Absurd agility gain %d\n", amount); + debug_agility_gain(amount); + return 0; } if (u.agility < 99) { @@ -244,14 +237,7 @@ int gain_agility(int amount, int loud) u.agility += amount; status_updated = 1; recalc_defence(); - if (loud) - { - print_msg("You feel more agile!\n"); - } - else - { - display_update(); - } + notify_agility_gain(amount); return amount; } else @@ -528,18 +514,17 @@ void gain_experience(int amount) if (u.experience > lev_threshold(u.level)) { u.level++; - print_msg("You gained a level!\n"); if (!zero_die(2)) { - bodygain = gain_body(2, 0); - agilgain = gain_agility(1, 0); + bodygain = gain_body(2); + agilgain = gain_agility(1); } else { - bodygain = gain_body(1, 0); - agilgain = gain_agility(2, 0); + bodygain = gain_body(1); + agilgain = gain_agility(2); } - print_msg("You gained %d body and %d agility.\n", bodygain, agilgain); + notify_level_gain(); hpgain = u.body / 10 + 10; if (u.hpmax + hpgain > 999) { @@ -551,8 +536,7 @@ void gain_experience(int amount) * heals you. */ u.hpcur += hpgain; u.hpmax += hpgain; - status_updated = 1; - print_msg("You gained %d hit points.\n", hpgain); + notify_hp_gain(hpgain); } } else @@ -571,12 +555,12 @@ Pass_fail teleport_u(void) c.x = exclusive_flat(0, DUN_WIDTH - 1); if ((lvl.mon_at(c) == NO_MON) && (lvl.terrain_at(c) == FLOOR) && (c != u.pos)) { - print_msg("You are whisked away!\n"); reloc_player(c); + notify_player_teleport(); return You_pass; } } - print_msg("You feel briefly dislocated.\n"); + notify_player_telefail(); return You_fail; } @@ -604,7 +588,7 @@ void update_player(void) { /* Heal player for 1d3 hit points; do not allow HP gain, * and don't say anything apart from the regen ring message. */ - print_msg("Your ring pulses soothingly.\n"); + notify_player_regen(); heal_u(one_die(3), 0, 0); } if (u.food > MIN_FOOD) @@ -628,25 +612,14 @@ void update_player(void) } u.food -= food_use; status_updated = 1; - switch (squeal) - { - case 0: - default: - break; - case 1: - print_msg("You are getting quite hungry.\n"); - break; - case 2: - print_msg("You are feeling hunger pangs, and will recover\nmore slowly from your injuries.\n"); - break; - } + notify_hunger_level(squeal); } if (u.leadfoot > 0) { u.leadfoot--; if (!u.leadfoot) { - print_msg("You shed your feet of lead.\n"); + notify_leadfoot_recovered(); recalc_defence(); } } @@ -655,7 +628,7 @@ void update_player(void) u.armourmelt--; if (!u.armourmelt) { - print_msg("Your armour seems solid once more.\n"); + notify_armourmelt_recovered(); recalc_defence(); } } @@ -664,7 +637,7 @@ void update_player(void) u.withering--; if (!u.withering) { - print_msg("Your limbs straighten.\n"); + notify_wither_recovered(); recalc_defence(); } } @@ -673,7 +646,7 @@ void update_player(void) u.protection--; if (!u.protection) { - print_msg("You feel like you are no longer being helped.\n"); + notify_protection_lost(); } } display_update(); diff --git a/victrix-abyssi.hh b/victrix-abyssi.hh index b4c39e0..c861f10 100644 --- a/victrix-abyssi.hh +++ b/victrix-abyssi.hh @@ -61,6 +61,14 @@ enum Action_cost Cost_std = 1 }; +enum Noisiness +{ + Noise_silent, + Noise_low, + Noise_std +}; + + /* change WIZARD_MODE to 1 if you want the wizard mode commands. */ #define WIZARD_MODE 0 @@ -95,14 +103,12 @@ enum Damtyp { /* XXX enum Game_cmd - player actions. */ enum Game_cmd { - DROP_ITEM, SAVE_GAME, - MOVE_WEST, MOVE_SOUTH, MOVE_NORTH, MOVE_EAST, - MOVE_NW, MOVE_NE, MOVE_SW, MOVE_SE, + WALK, STAND_STILL, GO_DOWN_STAIRS, ATTACK, + GET_ITEM, DROP_ITEM, WIELD_WEAPON, WEAR_ARMOUR, TAKE_OFF_ARMOUR, PUT_ON_RING, REMOVE_RING, - QUAFF_POTION, READ_SCROLL, THROW_FLASK, - EMANATE_ARMOUR, ZAP_WEAPON, MAGIC_RING, ATTACK, - GET_ITEM, QUIT, GO_DOWN_STAIRS, STAND_STILL, EAT_FOOD, DUMP_CHARA, - GIVE_HELP, INSPECT_ITEM, EXAMINE_MONSTER, RNG_TEST, SHOW_TERRAIN, + QUAFF_POTION, READ_SCROLL, THROW_FLASK, EAT_FOOD, + EMANATE_ARMOUR, ZAP_WEAPON, MAGIC_RING, + SAVE_GAME, QUIT, WIZARD_LEVELUP, WIZARD_DESCEND }; @@ -188,7 +194,7 @@ extern int inclusive_flat(int lower, int upper); /* l ... u */ extern Offset random_step(void); extern Coord inclusive_boxed(Coord topleft, Coord botright); extern Coord exclusive_boxed(Coord topleft, Coord botright); -extern Action_cost do_command(Game_cmd command); +extern Action_cost do_player_action(Action *act); extern int game_finished; extern int game_tick; extern int wizard_mode; @@ -214,8 +220,8 @@ extern void write_char_dump(void); extern int do_death(Death d, char const *what); extern void heal_u(int amount, int boost, int loud); extern int damage_u(int amount, Death d, char const *what); -extern int gain_body(int amount, int loud); -extern int gain_agility(int amount, int loud); +extern int gain_body(int amount); +extern int gain_agility(int amount); extern int drain_body(int amount, char const *what, int permanent); extern int drain_agility(int amount, char const *what, int permanent); extern void gain_experience(int amount);