From a0d48b01861f3745455c731078bc2b15187b1050 Mon Sep 17 00:00:00 2001 From: dshaligram Date: Thu, 25 Jan 2007 10:43:02 +0000 Subject: Removed USE_NEW_RANDOM, USE_MACROS. Removed DOS_TERM, PLAIN_TERM special casery - all platforms get PLAIN_TERM. Better end-of-greedy-explore reporting for items on traps (Erik). Cleaned up find_travel_pos - moved guts of travel pathfinding to travel_pathfind class. Miscellaneous other stuff. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@882 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/AppHdr.h | 9 - crawl-ref/source/abl-show.cc | 24 -- crawl-ref/source/acr.cc | 4 - crawl-ref/source/chardump.cc | 18 - crawl-ref/source/command.cc | 15 +- crawl-ref/source/describe.cc | 52 --- crawl-ref/source/direct.cc | 2 - crawl-ref/source/dungeon.h | 2 +- crawl-ref/source/externs.h | 10 +- crawl-ref/source/files.cc | 15 +- crawl-ref/source/files.h | 3 +- crawl-ref/source/libunix.cc | 2 +- crawl-ref/source/libutil.h | 10 +- crawl-ref/source/macro.cc | 3 - crawl-ref/source/macro.h | 14 - crawl-ref/source/makefile.unix | 28 +- crawl-ref/source/menu.cc | 11 - crawl-ref/source/message.cc | 23 +- crawl-ref/source/mutation.cc | 11 - crawl-ref/source/newgame.cc | 24 +- crawl-ref/source/ouch.cc | 5 - crawl-ref/source/player.cc | 3 - crawl-ref/source/player.h | 2 +- crawl-ref/source/shopping.cc | 18 - crawl-ref/source/skills2.cc | 10 - crawl-ref/source/spl-book.cc | 10 - crawl-ref/source/spl-cast.cc | 26 -- crawl-ref/source/stuff.cc | 205 +---------- crawl-ref/source/travel.cc | 820 ++++++++++++++++++++++++----------------- crawl-ref/source/travel.h | 145 +++++++- crawl-ref/source/view.cc | 136 +++---- crawl-ref/source/view.h | 5 + 32 files changed, 751 insertions(+), 914 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/source/AppHdr.h b/crawl-ref/source/AppHdr.h index 892679d029..f68fdd97c7 100644 --- a/crawl-ref/source/AppHdr.h +++ b/crawl-ref/source/AppHdr.h @@ -98,7 +98,6 @@ // #define DGL_CLEAR_SCREEN "\033[2J" - #define PLAIN_TERM #define MULTIUSER #define USE_UNIX_SIGNALS @@ -164,7 +163,6 @@ #include "libunix.h" #elif defined(DOS) - #define DOS_TERM #define SHORT_FILE_NAMES #define EOL "\r\n" #define CHARACTER_SET A_ALTCHARSET @@ -184,7 +182,6 @@ #elif defined(WIN32CONSOLE) #include "libw32c.h" - #define PLAIN_TERM #define EOL "\n" #define CHARACTER_SET A_ALTCHARSET #define getstr(X,Y) getConsoleString(X,Y) @@ -246,16 +243,10 @@ // number of back messages saved during play (currently none saved into files) #define NUM_STORED_MESSAGES 1000 -// if this works out okay, eventually we can change this to USE_OLD_RANDOM -#define USE_NEW_RANDOM - // Uncomment this if you find the labyrinth to be buggy and want to // remove it from the game. // #define SHUT_LABYRINTH -// Define USE_MACRO if you want to use the macro patch in macro.cc. -#define USE_MACROS - // Set this to the number of runes that will be required to enter Zot's // domain. You shouldn't set this really high unless you want to // make players spend far too much time in Pandemonium/The Abyss. diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index 95821ef64d..52647aee30 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -1352,13 +1352,6 @@ char show_abilities( void ) } -#ifdef DOS_TERM - char buffer[4800]; - - gettext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif - clrscr(); cprintf(" Ability Cost Success"); lines++; @@ -1385,17 +1378,11 @@ char show_abilities( void ) if (ki == ESCAPE) { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif return (ESCAPE); } if (ki >= 'A' && ki <= 'z') { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif return (ki); } @@ -1447,26 +1434,15 @@ char show_abilities( void ) if (ki >= 'A' && ki <= 'z') { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif return (ki); } if (ki == 0) ki = getch(); -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return (ki); } -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - ki = getch(); return (ki); diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 92a71f22a1..a2624a8884 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -1327,11 +1327,9 @@ void process_command( command_type cmd ) { mpr("Char dump unsuccessful! Sorry about that."); break; -#ifdef USE_MACROS case CMD_MACRO_ADD: macro_add_query(); break; -#endif case CMD_LIST_WEAPONS: list_weapons(); @@ -2671,10 +2669,8 @@ static bool initialise(void) cio_init(); -#ifdef USE_MACROS // Load macros macro_init(); -#endif // system initialisation stuff: textbackground(0); diff --git a/crawl-ref/source/chardump.cc b/crawl-ref/source/chardump.cc index 3c2a087b72..180df83a9c 100644 --- a/crawl-ref/source/chardump.cc +++ b/crawl-ref/source/chardump.cc @@ -1011,11 +1011,6 @@ static bool write_dump( void display_notes() { -#ifdef DOS_TERM - char dosbuffer[4000]; - gettext( 1, 1, 80, 25, dosbuffer ); - window( 1, 1, 80, 25 ); -#endif Menu scr; scr.set_title( new MenuEntry("| Turn |Location | Note")); for ( unsigned int i = 0; i < note_list.size(); ++i ) @@ -1036,20 +1031,11 @@ void display_notes() } scr.show(); -#ifdef DOS_TERM - puttext(1, 1, 80, 25, dosbuffer); - window(1, 1, 80, 25); -#endif redraw_screen(); } void resists_screen() { -#ifdef DOS_TERM - char dosbuffer[4000]; - gettext( 1, 1, 80, 25, dosbuffer ); - window( 1, 1, 80, 25 ); -#endif std::vector vfs = get_full_detail(false); clrscr(); gotoxy(1,1); @@ -1060,9 +1046,5 @@ void resists_screen() scr.add_item_formatted_string(vfs[i]); scr.show(); -#ifdef DOS_TERM - puttext(1, 1, 80, 25, dosbuffer); - window(1, 1, 80, 25); -#endif redraw_screen(); } diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index b9e9b73589..14263ce8e2 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -716,7 +716,9 @@ static void show_keyhelp_menu(const std::vector &lines, { for ( int i = 0; help_files[i].name != NULL; ++i ) { - FILE* fp=fopen(datafile_path(std::string(help_files[i].name)).c_str(),"r"); + FILE* fp = + fopen( + datafile_path(help_files[i].name, false).c_str(), "r"); if ( !fp ) continue; @@ -993,13 +995,6 @@ static void list_wizard_commands() const char *line; int j = 0; -#ifdef DOS_TERM - char buffer[4800]; - - window(1, 1, 80, 25); - gettext(1, 1, 80, 25, buffer); -#endif - clrscr(); // BCR - Set to screen length - 1 to display the "more" string @@ -1030,10 +1025,6 @@ static void list_wizard_commands() getch(); -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return; } // end list_commands() diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index eaabafcb77..17cb25705d 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -98,14 +98,7 @@ static void print_description( const std::string &d ) while(currentPos < d.length()) { if (currentPos != 0) - { -#ifdef PLAIN_TERM gotoxy(1, wherey() + 1); -#endif -#ifdef DOS_TERM - cprintf(EOL); -#endif - } // see if $ sign is within one lineWidth if (nlSearch) @@ -3348,12 +3341,6 @@ std::string get_item_description( const item_def &item, bool verbose, bool dump //--------------------------------------------------------------- void describe_item( const item_def &item ) { -#ifdef DOS_TERM - char buffer[4000]; - gettext(1, 1, 80, 25, buffer); - // window(25, 1, 80, 25); -#endif - clrscr(); std::string description = get_item_description( item, 1 ); @@ -3377,10 +3364,6 @@ void describe_item( const item_def &item ) if (getch() == 0) getch(); - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif } // end describe_item() @@ -3397,12 +3380,6 @@ void describe_spell(int spelled) description.reserve(500); -#ifdef DOS_TERM - char buffer[4000]; - gettext(1, 1, 80, 25, buffer); - // window(25, 1, 80, 25); -#endif - clrscr(); description += spell_title( spelled ); description += "$$This spell "; // NB: the leading space is here {dlb} @@ -4495,11 +4472,6 @@ void describe_spell(int spelled) if (getch() == 0) getch(); - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif } // end describe_spell() static std::string describe_draconian_role(const monsters *mon) @@ -4599,12 +4571,6 @@ void describe_monsters(int class_described, unsigned char which_mons) description.reserve(200); -#ifdef DOS_TERM - char buffer[4000]; - gettext(1, 1, 80, 25, buffer); - // window(25, 1, 80, 25); -#endif - clrscr(); description = ptr_monam( &(menv[ which_mons ]), DESC_CAP_A ); @@ -6306,11 +6272,6 @@ void describe_monsters(int class_described, unsigned char which_mons) if (getch() == 0) getch(); - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif } // end describe_monsters //--------------------------------------------------------------- @@ -6431,12 +6392,6 @@ void describe_god( int which_god, bool give_title ) const char *description; // mv: tmp string used for printing description int colour; // mv: colour used for some messages -#ifdef DOS_TERM - char buffer[4000]; - gettext( 1, 1, 80, 25, buffer ); - window( 1, 1, 80, 25 ); -#endif - clrscr(); if (give_title) @@ -6737,11 +6692,4 @@ void describe_god( int which_god, bool give_title ) end_god_info: //end of everything (life, world, universe etc.) getch(); // wait until keypressed - -#ifdef DOS_TERM //mv: if DOS_TERM is defined than buffer is returned to screen - //if not redraw_screen() is called everytime when this function is - //called - puttext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif } //mv: That's all folks. diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index fb42388bcc..7d7b474000 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -43,9 +43,7 @@ #include "travel.h" #include "view.h" -#ifdef USE_MACROS #include "macro.h" -#endif enum LOSSelect { diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index 79a4d4809b..c2122f8c37 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -17,7 +17,7 @@ #include "FixVec.h" #include "externs.h" -#define MAKE_GOOD_ITEM 351 +const int MAKE_GOOD_ITEM = 351; // Should be the larger of GXM/GYM #define MAP_SIDE GXM diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 688152562b..5817437c33 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -109,21 +109,25 @@ struct coord_def int x; int y; - coord_def( int x_in, int y_in ) : x(x_in), y(y_in) { } - coord_def() : x(0), y(0) { } + explicit coord_def( int x_in = 0, int y_in = 0 ) : x(x_in), y(y_in) { } void set(int xi, int yi) { x = xi; y = yi; } + + void reset() + { + set(0, 0); + } bool operator == (const coord_def &other) const { return x == other.x && y == other.y; } bool operator != (const coord_def &other) const { - return x != other.x || y != other.y; + return !operator == (other); } bool operator < (const coord_def &other) const { diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 5c79274aae..21ce1e7122 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -351,7 +351,7 @@ static bool create_dirs(const std::string &dir) return (true); } -std::string datafile_path(const std::string &basename) +std::string datafile_path(const std::string &basename, bool croak_on_fail) { std::string cdir = SysEnv.crawl_dir? SysEnv.crawl_dir : ""; @@ -400,8 +400,9 @@ std::string datafile_path(const std::string &basename) } // Die horribly. - end(1, false, "Cannot find data file '%s' anywhere, aborting\n", - basename.c_str()); + if (croak_on_fail) + end(1, false, "Cannot find data file '%s' anywhere, aborting\n", + basename.c_str()); return (""); } @@ -629,10 +630,6 @@ void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth, bool just_created_level = false; -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif - std::string cha_fil = make_filename( you.your_name, you.your_level, you.where_are_you, you.level_type != LEVEL_DUNGEON, @@ -1222,10 +1219,6 @@ void save_game(bool leave_game) save_level(you.your_level, (you.level_type != LEVEL_DUNGEON), you.where_are_you); -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif - clrscr(); #ifdef SAVE_PACKAGE_CMD diff --git a/crawl-ref/source/files.h b/crawl-ref/source/files.h index b87e4f9bea..577e443333 100644 --- a/crawl-ref/source/files.h +++ b/crawl-ref/source/files.h @@ -26,7 +26,8 @@ // referenced in files - newgame - ouch: extern FixedArray tmp_file_pairs; -std::string datafile_path(const std::string &basename); +std::string datafile_path(const std::string &basename, + bool croak_on_fail = true); bool check_dir(const std::string &what, std::string &dir); diff --git a/crawl-ref/source/libunix.cc b/crawl-ref/source/libunix.cc index e58c4f5bf2..14c6044517 100644 --- a/crawl-ref/source/libunix.cc +++ b/crawl-ref/source/libunix.cc @@ -494,7 +494,7 @@ int clrscr() #ifndef DGAMELAUNCH refresh(); #else - printf(DGL_CLEAR_SCREEN); + printf("%s", DGL_CLEAR_SCREEN); fflush(stdout); #endif return (retval); diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h index be30ec5ebd..5ad02e504e 100644 --- a/crawl-ref/source/libutil.h +++ b/crawl-ref/source/libutil.h @@ -80,8 +80,10 @@ inline std::string lowercase_first(std::string s) return (s); } -template -std::string comma_separated_line(Z start, Z end) +template +std::string comma_separated_line(Z start, Z end, + const std::string &andc = " and ", + const std::string &comma = ", ") { std::string text; for (Z i = start; i != end; ++i) @@ -89,9 +91,9 @@ std::string comma_separated_line(Z start, Z end) if (i != start) { if (i + 1 != end) - text += ", "; + text += comma; else - text += " and "; + text += andc; } text += *i; diff --git a/crawl-ref/source/macro.cc b/crawl-ref/source/macro.cc index 2e322e4143..6a4783519f 100644 --- a/crawl-ref/source/macro.cc +++ b/crawl-ref/source/macro.cc @@ -30,7 +30,6 @@ #include "AppHdr.h" -#ifdef USE_MACROS #define MACRO_CC #include "macro.h" @@ -739,5 +738,3 @@ void macro_userfn(const char *keys, const char *regname) // to happen in a hurry. } #endif - -#endif diff --git a/crawl-ref/source/macro.h b/crawl-ref/source/macro.h index c3ea7516a8..9d8fa4f126 100644 --- a/crawl-ref/source/macro.h +++ b/crawl-ref/source/macro.h @@ -11,8 +11,6 @@ * <1> -/--/-- JS Created */ -#ifdef USE_MACROS - #ifndef MACRO_H #define MACRO_H @@ -51,15 +49,3 @@ bool is_userfunction(int key); const char *get_userfunction(int key); #endif - -#else - -#define getch_with_command_macros() getch() -#define getchm(x) getch() -#define flush_input_buffer(XXX) ; -#define macro_buf_add(x) -#define is_userfunction(x) false -#define get_userfunction(x) NULL -#define call_userfunction(x) - -#endif diff --git a/crawl-ref/source/makefile.unix b/crawl-ref/source/makefile.unix index 2e1f2a88ff..b8f3784aae 100644 --- a/crawl-ref/source/makefile.unix +++ b/crawl-ref/source/makefile.unix @@ -1,4 +1,4 @@ -# -*- Makefile -*- for Dungeon Crawl (linux) +# -*- Makefile -*- for Dungeon Crawl (unix) # # Modified for Crawl Reference by $Author$ on $Date$ @@ -20,8 +20,19 @@ OS_TYPE = UNIX # Include path for curses or ncurses. INCLUDES = -I/usr/include/ncurses -MCHMOD = 2755 -INSTALLDIR := /usr/games +# If you have lex and yacc, set DOYACC to y (lowercase y). +DOYACC := y + +# Permissions to set on the game executable. +MCHMOD := 2755 + +# Permissions to set on the save directory. +MCHMOD_SAVEDIR := 775 + +# The user:group to install the game as. +INSTALL_UGRP := games:games + +INSTALLDIR := /usr/games # If you're installing Crawl for multiple users, you *must* set this to a # valid path before building Crawl. This is not necessary if you are building @@ -50,10 +61,6 @@ endif CFLAGS := $(INCLUDES) $(CFWARN) $(CFOTHERS) YCFLAGS := $(INCLUDES) $(CFOTHERS) - -# If you have lex and yacc, set DOYACC to y (lowercase y). -DOYACC := y - UTIL = util/ LEX := lex @@ -143,6 +150,7 @@ endif install: $(GAME) [ -d $(INSTALLDIR) ] || mkdir -p $(INSTALLDIR) $(COPY) $(GAME) ${INSTALLDIR} + chown $(INSTALL_UGRP) $(INSTALLDIR)/$(GAME) chmod ${MCHMOD} ${INSTALLDIR}/$(GAME) ifeq ($(DATADIR),) $(error DATADIR not set! Set DATADIR and run make clean install again) @@ -151,8 +159,11 @@ endif cp dat/*.des $(DATADIR)/data mkdir -p $(DATADIR)/docs cp ../docs/*.txt $(DATADIR)/docs + chown -R $(INSTALL_UGRP) $(DATADIR) ifneq ($(SAVEDIR),) mkdir -p $(SAVEDIR) + chown $(INSTALL_UGRP) $(SAVEDIR) + chmod $(MCHMOD_SAVEDIR) $(SAVEDIR) endif clean: @@ -192,9 +203,6 @@ profile: $(GAME_DEPENDS) $(UTIL)%.o: $(UTIL)%.cc $(CXX) $(YCFLAGS) -o $@ -c $< -.h.cc: - touch $@ - ############################################################################# # Packaging a source tarball for release # diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc index bd68b3b188..dfdefa778f 100644 --- a/crawl-ref/source/menu.cc +++ b/crawl-ref/source/menu.cc @@ -109,19 +109,8 @@ std::vector Menu::show(bool reuse_selections) if (max_pagesize > 0 && pagesize > max_pagesize) pagesize = max_pagesize; -#ifdef DOS_TERM - char buffer[4600]; - - gettext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif - do_menu(); -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return (sel); } diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc index ece8b189c6..7f78039a17 100644 --- a/crawl-ref/source/message.cc +++ b/crawl-ref/source/message.cc @@ -355,10 +355,6 @@ static void base_mpr(const char *inf, int channel, int param) flush_input_buffer( FLUSH_ON_MESSAGE ); -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif - const int num_lines = get_message_window_height(); if (New_Message_Count == num_lines - 1) @@ -373,7 +369,12 @@ static void base_mpr(const char *inf, int channel, int param) message_out( Message_Line, colour, inf, Options.delay_message_clear? 2 : 1 ); - New_Message_Count++; + // Prompt lines are presumably shown to / seen by the player accompanied + // by a request for input, which should do the equivalent of a more(); to + // save annoyance, don't bump New_Message_Count for prompts. + if (channel != MSGCH_PROMPT) + New_Message_Count++; + if (Message_Line < num_lines - 1) Message_Line++; @@ -491,13 +492,6 @@ void replay_messages(void) if (last_message < 0) last_message += NUM_STORED_MESSAGES; -#ifdef DOS_TERM - char buffer[4800]; - - window(1, 1, 80, 25); - gettext(1, 1, 80, 25, buffer); -#endif - // track back a screen's worth of messages from the end win_start_line = Next_Message - (num_lines - 2); if (win_start_line < 0) @@ -636,10 +630,5 @@ void replay_messages(void) } } - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return; } // end replay_messages() diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc index 90c973c685..c69a4c7413 100644 --- a/crawl-ref/source/mutation.cc +++ b/crawl-ref/source/mutation.cc @@ -1129,23 +1129,12 @@ formatted_string describe_mutations() void display_mutations() { -#ifdef DOS_TERM - char buffer[4800]; - - window(1, 1, 80, 25); - gettext(1, 1, 80, 25, buffer); -#endif - clrscr(); gotoxy(1,1); describe_mutations().display(); if (getch() == 0) getch(); - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif } bool mutate(int which_mutation, bool failMsg) diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index 0f1c9d9e56..9b207ca2c6 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -348,18 +348,18 @@ static unsigned char random_potion_description() // Determine starting depths of branches static void initialise_branch_depths() { - branches[BRANCH_ECUMENICAL_TEMPLE].startdepth = 3 + random2(4); - branches[BRANCH_ORCISH_MINES].startdepth = 5 + random2(6); - branches[BRANCH_ELVEN_HALLS].startdepth = coinflip() ? 4 : 3; - branches[BRANCH_LAIR].startdepth = 7 + random2(6); - branches[BRANCH_HIVE].startdepth = 10 + random2(6); - branches[BRANCH_SLIME_PITS].startdepth = 3 + random2(4); - branches[BRANCH_SWAMP].startdepth = 2 + random2(6); - branches[BRANCH_SNAKE_PIT].startdepth = coinflip() ? 7 : 6; - branches[BRANCH_VAULTS].startdepth = 13 + random2(6); - branches[BRANCH_CRYPT].startdepth = 2 + random2(3); - branches[BRANCH_HALL_OF_BLADES].startdepth = 4; - branches[BRANCH_TOMB].startdepth = coinflip() ? 3 : 2; + branches[BRANCH_ECUMENICAL_TEMPLE].startdepth = random_range(4, 7); + branches[BRANCH_ORCISH_MINES].startdepth = random_range(6, 11); + branches[BRANCH_ELVEN_HALLS].startdepth = random_range(3, 4); + branches[BRANCH_LAIR].startdepth = random_range(8, 13); + branches[BRANCH_HIVE].startdepth = random_range(11, 16); + branches[BRANCH_SLIME_PITS].startdepth = random_range(3, 9); + branches[BRANCH_SWAMP].startdepth = random_range(2, 7); + branches[BRANCH_SNAKE_PIT].startdepth = random_range(3, 8); + branches[BRANCH_VAULTS].startdepth = random_range(14, 19); + branches[BRANCH_CRYPT].startdepth = random_range(2, 4); + branches[BRANCH_HALL_OF_BLADES].startdepth = random_range(4, 6); + branches[BRANCH_TOMB].startdepth = random_range(2, 3); } bool new_game(void) diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc index eee99451cf..85cfe0ad83 100644 --- a/crawl-ref/source/ouch.cc +++ b/crawl-ref/source/ouch.cc @@ -914,15 +914,10 @@ void end_game( struct scorefile_entry &se ) clrscr(); } -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif - clrscr(); cprintf( "Goodbye, %s.", you.your_name ); cprintf( EOL EOL " " ); // Space padding where # would go in list format - std::string hiscore = hiscores_format_single_long( se, true ); const int lines = count_occurrences(hiscore, EOL) + 1; diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 5915d6877a..962334975b 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -3183,9 +3183,6 @@ void redraw_skill(const char your_name[kNameLen], const char class_name[80]) print_it[40] = 0; -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif gotoxy(40, 1); textcolor( LIGHTGREY ); diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h index a9db520587..ed08ec44dd 100644 --- a/crawl-ref/source/player.h +++ b/crawl-ref/source/player.h @@ -158,7 +158,7 @@ bool player_item_conserve(bool calc_unid = true); int player_mental_clarity(bool calc_unid = true); bool player_can_smell(); - +bool player_can_swim(); /* *********************************************************************** * called from: fight - files - ouch diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc index 755a2610cf..d4a16c5c33 100644 --- a/crawl-ref/source/shopping.cc +++ b/crawl-ref/source/shopping.cc @@ -125,15 +125,6 @@ char in_a_shop( char shoppy, id_arr id ) unsigned char ft; std::string purchasable; -#ifdef DOS_TERM - char buffer[4800]; - gettext(1, 1, 80, 25, buffer); -#endif - -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif - clrscr(); int itty = 0; @@ -292,9 +283,6 @@ char in_a_shop( char shoppy, id_arr id ) shop_uninit_id(shoppy, shop_id); invent(-1, false); shop_init_id(shoppy, shop_id); -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif goto print_stock; } @@ -343,12 +331,6 @@ char in_a_shop( char shoppy, id_arr id ) shop_print("Goodbye!", 20); more3(); -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); - gotoxy(1, 1); - cprintf(" "); -#endif - shop_uninit_id( shoppy, shop_id ); activate_notes(true); return 0; diff --git a/crawl-ref/source/skills2.cc b/crawl-ref/source/skills2.cc index 20347ca01d..810f8e6df7 100644 --- a/crawl-ref/source/skills2.cc +++ b/crawl-ref/source/skills2.cc @@ -1824,13 +1824,6 @@ void show_skills(void) const int num_lines = get_number_of_lines(); -#ifdef DOS_TERM - window(1, 1, 80, 25); - char buffer[4600]; - - gettext(1, 1, 80, 25, buffer); -#endif - clrscr(); reprint_stuff: @@ -1989,9 +1982,6 @@ void show_skills(void) } } -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif return; } diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc index ea39448bc3..b07cf9beb2 100644 --- a/crawl-ref/source/spl-book.cc +++ b/crawl-ref/source/spl-book.cc @@ -913,11 +913,6 @@ unsigned char spellbook_contents( item_def &book, int action, if (update_screen) { cursor_control coff(false); -#ifdef DOS_TERM - char buffer[4800]; - gettext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif clrscr(); out.display(); @@ -925,11 +920,6 @@ unsigned char spellbook_contents( item_def &book, int action, keyn = getch(); if (keyn == 0) getch(); - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); - window(1, 18, 80, 25); -#endif } return (keyn); // try to figure out that for which this is used {dlb} diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 9391b81ab2..0b1ff598c1 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -92,16 +92,6 @@ char list_spells(void) const int num_lines = get_number_of_lines(); cursor_control coff(false); -#ifdef DOS_TERM - char buffer[4800]; - - gettext(1, 1, 80, 25, buffer); -#endif - -#ifdef DOS_TERM - window(1, 1, 80, 25); -#endif - clrscr(); cprintf( " Your Spells Type Power Success Level" ); @@ -118,17 +108,11 @@ char list_spells(void) if (ki == ESCAPE) { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif return (ESCAPE); } if (isalpha( ki )) { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif return (ki); } @@ -195,25 +179,15 @@ char list_spells(void) if (ki >= 'A' && ki <= 'z') { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif return (ki); } if (ki == 0) ki = getch(); -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return (anything); } -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif // was 35 ki = getch(); diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index 75364a312d..0c492f03ee 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -62,13 +62,6 @@ #include "skills2.h" #include "view.h" - -// required for stuff::coinflip() and cf_setseed() -unsigned long cfseed; - -// unfortunately required for near_stairs(ugh!): -extern unsigned char (*mapch) (unsigned char); - // Crude, but functional. char *const make_time_string( time_t abs_time, char *const buff, int buff_size, bool terse ) @@ -171,12 +164,8 @@ unsigned char get_ch(void) void seed_rng(long seed) { -#ifdef USE_SYSTEM_RAND - srand(seed); -#else // MT19937 -- see mt19937ar.cc for details/licence init_genrand(seed); -#endif } void seed_rng() @@ -188,133 +177,8 @@ void seed_rng() #endif seed_rng(seed); -#ifdef USE_SYSTEM_RAND - cf_setseed(); -#endif -} - -#ifdef USE_SYSTEM_RAND -int random2(int max) -{ -#ifdef USE_NEW_RANDOM - //return (int) ((((float) max) * rand()) / RAND_MAX); - this is bad! - // Uses FP, so is horribly slow on computers without coprocessors. - // Taken from comp.lang.c FAQ. May have problems as max approaches - // RAND_MAX, but this is rather unlikely. - // We've used rand() rather than random() for the portability, I think. - - if (max < 1 || max >= RAND_MAX) - return 0; - else - return (int) rand() / (RAND_MAX / max + 1); -#else - - if (max < 1) - return 0; - - return rand() % max; -#endif -} - -// required for stuff::coinflip() -#define IB1 1 -#define IB2 2 -#define IB5 16 -#define IB18 131072 -#define MASK (IB1 + IB2 + IB5) -// required for stuff::coinflip() - -// I got to thinking a bit more about how much people talk -// about RNGs and RLs and also about the issue of performance -// when it comes to Crawl's RNG ... turning to *Numerical -// Recipies in C* (Chapter 7-4, page 298), I hit upon what -// struck me as a fine solution. - -// You can read all the details about this function (pretty -// much stolen shamelessly from NRinC) elsewhere, but having -// tested it out myself I think it satisfies Crawl's incessant -// need to decide things on a 50-50 flip of the coin. No call -// to random2() required -- along with all that wonderful math -// and type casting -- and only a single variable its pointer, -// and some bitwise operations to randomly generate 1s and 0s! -// No parameter passing, nothing. Too good to be true, but it -// works as long as cfseed is not set to absolute zero when it -// is initialized ... good for 2**n-1 random bits before the -// pattern repeats (n = long's bitlength on your platform). -// It also avoids problems with poor implementations of rand() -// on some platforms in regards to low-order bits ... a big -// problem if one is only looking for a 1 or a 0 with random2()! - -// Talk about a hard sell! Anyway, it returns bool, so please -// use appropriately -- I set it to bool to prevent such -// tomfoolery, as I think that pure RNG and quickly grabbing -// either a value of 1 or 0 should be separated where possible -// to lower overhead in Crawl ... at least until it assembles -// itself into something a bit more orderly :P 16jan2000 {dlb} - -// NB(1): cfseed is defined atop stuff.cc -// NB(2): IB(foo) and MASK are defined somewhere in defines.h -// NB(3): the function assumes that cf_setseed() has been called -// beforehand - the call is presently made in acr::initialise() -// right after srandom() and srand() are called (note also -// that cf_setseed() requires rand() - random2 returns int -// but a long can't hurt there). -bool coinflip(void) -{ - extern unsigned long cfseed; // defined atop stuff.cc - unsigned long *ptr_cfseed = &cfseed; - - if (*ptr_cfseed & IB18) - { - *ptr_cfseed = ((*ptr_cfseed ^ MASK) << 1) | IB1; - return true; - } - else - { - *ptr_cfseed <<= 1; - return false; - } -} // end coinflip() - -// cf_setseed should only be called but once in all of Crawl!!! {dlb} -void cf_setseed(void) -{ - extern unsigned long cfseed; // defined atop stuff.cc - unsigned long *ptr_cfseed = &cfseed; - - do - { - // using rand() here makes these predictable -- bwr - *ptr_cfseed = rand(); - } - while (*ptr_cfseed == 0); -} - -static std::stack rng_states; -void push_rng_state() -{ - // XXX: Does this even work? randart.cc uses it, but I can't find anything - // that says this will restore the RNG to its original state. Anyway, we're - // now using MT with a deterministic push/pop. - rng_states.push(rand()); } -void pop_rng_state() -{ - if (!rng_states.empty()) - { - seed_rng(rng_states.top()); - rng_states.pop(); - } -} - -unsigned long random_int( void ) -{ - return rand(); -} - -#else // USE_SYSTEM_RAND - // MT19937 -- see mt19937ar.cc for details unsigned long random_int( void ) { @@ -350,8 +214,6 @@ void pop_rng_state() pop_mt_state(); } -#endif // USE_SYSTEM_RAND - // Attempts to make missile weapons nicer to the player by // reducing the extreme variance in damage done. void scale_dice( dice_def &dice, int threshold ) @@ -508,7 +370,7 @@ void end(int exit_code, bool print_error, const char *format, ...) error = std::string(buffer) + ": " + error; } - if (error.length()) + if (!error.empty()) { if (error[error.length() - 1] != '\n') error += "\n"; @@ -520,9 +382,6 @@ void end(int exit_code, bool print_error, const char *format, ...) void redraw_screen(void) { -#ifdef PLAIN_TERM -// this function is used for systems without gettext/puttext to redraw the -// playing screen after a call to for example inventory. draw_border(); you.redraw_hit_points = 1; @@ -536,7 +395,8 @@ void redraw_screen(void) you.redraw_experience = 1; you.wield_change = true; - set_redraw_status( REDRAW_LINE_1_MASK | REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK ); + set_redraw_status( + REDRAW_LINE_1_MASK | REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK ); print_stats(); @@ -550,7 +410,6 @@ void redraw_screen(void) activate_notes(note_status); viewwindow(1, false); -#endif } // end redraw_screen() // STEPDOWN FUNCTION to replace conditional chains in spells2.cc 12jan2000 {dlb} @@ -902,59 +761,6 @@ void random_in_bounds( int &x_pos, int &y_pos, int terr, bool empty, bool excl ) while (!done); } -// takes rectangle (x1,y1)-(x2,y2) and shifts it somewhere randomly in bounds -void random_place_rectangle( int &x1, int &y1, int &x2, int &y2, bool excl ) -{ - const unsigned int dx = abs( x2 - x1 ); - const unsigned int dy = abs( y2 - y1 ); - - x1 = X_BOUND_1 + random2( X_WIDTH - dx - 2 * excl ) + excl; - y1 = Y_BOUND_1 + random2( Y_WIDTH - dy - 2 * excl ) + excl; - - x2 = x1 + dx; - y2 = y1 + dy; -} - -// returns true if point (px,py) is in rectangle (rx1, ry1) - (rx2, ry2) -bool in_rectangle( int px, int py, int rx1, int ry1, int rx2, int ry2, - bool excl ) -{ - ASSERT( rx1 < rx2 - 1 && ry1 < ry2 - 1 ); - - if (excl) - { - rx1++; - rx2--; - ry1++; - ry2--; - } - - return (px >= rx1 && px <= rx2 && py >= ry1 && py <= ry2); -} - -// XXX: this can be done better -// returns true if rectables a and b overlap -bool rectangles_overlap( int ax1, int ay1, int ax2, int ay2, - int bx1, int by1, int bx2, int by2, - bool excl ) -{ - ASSERT( ax1 < ax2 - 1 && ay1 < ay2 - 1 ); - ASSERT( bx1 < bx2 - 1 && by1 < by2 - 1 ); - - if (excl) - { - ax1++; - ax2--; - ay1++; - ay2--; - } - - return (in_rectangle( ax1, ay1, bx1, by1, bx2, by2, excl ) - || in_rectangle( ax1, ay2, bx1, by1, bx2, by2, excl ) - || in_rectangle( ax2, ay1, bx1, by1, bx2, by2, excl ) - || in_rectangle( ax2, ay2, bx1, by1, bx2, by2, excl )); -} - unsigned char random_colour(void) { return (1 + random2(15)); @@ -1256,9 +1062,8 @@ void zap_los_monsters() continue; #ifdef DEBUG_DIAGNOSTICS - char mname[ITEMNAME_SIZE]; - moname(mon->type, true, DESC_PLAIN, mname); - mprf(MSGCH_DIAGNOSTICS, "Dismissing %s", mname); + mprf(MSGCH_DIAGNOSTICS, "Dismissing %s", + ptr_monam(mon, DESC_PLAIN) ); #endif monster_die(mon, KILL_DISMISSED, 0); } diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 1807dca9d6..6e5de5d843 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -87,17 +87,16 @@ inline int sgn(int x) // would have to travel to get there. Negative distances imply that the point // is a) a trap or hostile terrain or b) only reachable by crossing a trap or // hostile terrain. -short point_distance[GXM][GYM]; +travel_distance_grid_t travel_point_distance; -unsigned char curr_waypoints[GXM][GYM]; - -signed char curr_traps[GXM][GYM]; +static unsigned char curr_waypoints[GXM][GYM]; +static signed char curr_traps[GXM][GYM]; static FixedArray< unsigned short, GXM, GYM > mapshadow; -#define TRAVERSABLE 1 -#define IMPASSABLE 0 -#define FORBIDDEN -1 +const signed char TRAVERSABLE = 1; +const signed char IMPASSABLE = 0; +const signed char FORBIDDEN = -1; // Map of terrain types that are traversable. static signed char traversable_terrain[256]; @@ -165,8 +164,8 @@ bool is_altar(const coord_def &c) inline bool is_player_altar(unsigned char grid) { // An ugly hack, but that's what religion.cc does. - return you.religion - && grid == DNGN_ALTAR_ZIN - 1 + you.religion; + return you.religion != GOD_NO_GOD + && grid_altar_god(grid) == you.religion; } inline bool is_player_altar(const coord_def &c) @@ -255,25 +254,6 @@ static bool is_exclude_root(int x, int y) return false; } -// Determines if the level is fully explored. Clobbers you.run_x/y. -static bool fully_explored() -{ - const int oldrun = you.running; - - if (!you.running.is_explore()) - you.running = RMODE_EXPLORE; - - // Do a second floodfill to check if the level is fully explored. - // Note we're passing in a features vector to force find_travel_pos to - // reseed past traps/deep water/lava. Icky. - - std::vector features_dummy; - find_travel_pos(you.x_pos, you.y_pos, NULL, NULL, &features_dummy); - you.running = oldrun; - - return !(you.running.x > 0 && you.running.y > 0); -} - const char *run_mode_name(int runmode) { return runmode == RMODE_TRAVEL? "travel" : @@ -372,7 +352,7 @@ void forget_square(int x, int y) static bool is_reseedable(int x, int y) { if (is_excluded(x, y)) - return true; + return (true); unsigned char grid = grd[x][y]; return (grid == DNGN_DEEP_WATER || grid == DNGN_SHALLOW_WATER || grid == DNGN_LAVA || is_trap(x, y)); @@ -385,11 +365,11 @@ static bool is_reseedable(int x, int y) */ static bool is_travel_ok(int x, int y, bool ignore_hostile) { - const int grid = grd[x][y]; - if (!is_terrain_known(x, y)) return (false); + const int grid = grd[x][y]; + // Special-case secret doors so that we don't run into awkwardness when // a monster opens a secret door without the hero seeing it, but the travel // code paths through the secret door because it looks at the actual grid, @@ -413,14 +393,7 @@ static bool is_travel_ok(int x, int y, bool ignore_hostile) if (player_monster_visible(&menv[mon]) && mons_class_flag( menv[mon].type, M_NO_EXP_GAIN )) { - extern short point_distance[GXM][GYM]; - - // We have to set the point_distance array if the level map is - // to be properly coloured. The caller isn't going to do it because - // we say this square is inaccessible, so in a horrible hack, we - // do it ourselves. Ecch. - point_distance[x][y] = ignore_hostile? -42 : 42; - return false; + return (false); } } @@ -486,16 +459,17 @@ static void set_pass_feature(unsigned char grid, signed char pass) */ static void init_terrain_check() { - // Merfolk get deep water. - signed char water = you.species == SP_MERFOLK? TRAVERSABLE : IMPASSABLE; + // Swimmers get deep water. + signed char water = player_can_swim()? TRAVERSABLE : IMPASSABLE; + // If the player has overridden deep water already, we'll respect that. set_pass_feature(DNGN_DEEP_WATER, water); // Permanently levitating players can cross most hostile terrain. signed char trav = player_is_permalevitating()? TRAVERSABLE : IMPASSABLE; - if (you.species != SP_MERFOLK) - set_pass_feature(DNGN_DEEP_WATER, trav); + + set_pass_feature(DNGN_DEEP_WATER, trav); set_pass_feature(DNGN_LAVA, trav); set_pass_feature(DNGN_TRAP_MECHANICAL, trav); } @@ -706,7 +680,7 @@ bool is_travelable_stair(unsigned gridc) bool prompt_stop_explore(int es_why) { return (!(Options.explore_stop_prompt & es_why) - || yesno("Stop exploring?", true, 'n', true, false)); + || yesno("Stop exploring?", true, 'y', true, false)); } #define ES_item (Options.explore_stop & ES_ITEM) @@ -794,6 +768,79 @@ static bool is_valid_explore_target(int x, int y) return (false); } +enum explore_status_type +{ + EST_FULLY_EXPLORED = 0, + + // Could not explore because of hostile terrain + EST_PARTLY_EXPLORED = 1, + + // Could not pick up interesting items because of hostile terrain. Note + // that this and EST_PARTLY_EXPLORED are not mutually exclusive. + EST_GREED_UNFULFILLED = 2 +}; + +// Determines if the level is fully explored. +static int find_explore_status(const travel_pathfind &tp) +{ + int explore_status = 0; + + const coord_def greed = tp.greedy_square(); + if (greed.x || greed.y) + explore_status |= EST_GREED_UNFULFILLED; + + const coord_def unexplored = tp.unexplored_square(); + if (unexplored.x || unexplored.y) + explore_status |= EST_PARTLY_EXPLORED; + + return (explore_status); +} + +static void explore_find_target_square() +{ + travel_pathfind tp; + tp.set_floodseed(coord_def(you.x_pos, you.y_pos), true); + + coord_def whereto = + tp.pathfind( static_cast(you.running.runmode) ); + + if (whereto.x || whereto.y) + { + // Make sure this is a square that is reachable, since we asked + // travel_pathfind to give us even unreachable squares. + if (travel_point_distance[whereto.x][whereto.y] <= 0) + whereto.reset(); + } + + if (whereto.x || whereto.y) + { + you.running.x = whereto.x; + you.running.y = whereto.y; + } + else + { + // No place to go? Report to the player. + const int estatus = find_explore_status(tp); + + if (!estatus) + mpr("Done exploring."); + else + { + std::vector inacc; + if (estatus & EST_GREED_UNFULFILLED) + inacc.push_back("items"); + if (estatus & EST_PARTLY_EXPLORED) + inacc.push_back("places"); + + mprf("Partly explored, can't reach some %s.", + comma_separated_line( + inacc.begin(), + inacc.end()).c_str()); + } + stop_running(); + } +} + /* * Top-level travel control (called from input() in acr.cc). * @@ -865,18 +912,7 @@ command_type travel() || (you.running.x == you.x_pos && you.running.y == you.y_pos) || !is_valid_explore_target(you.running.x, you.running.y)) { - you.running.x = 0; - find_travel_pos(you.x_pos, you.y_pos, NULL, NULL); - // No place to go? - if (!you.running.x) - { - // Do fully_explored() *before* stop_running! - if (fully_explored()) - mpr("Done exploring."); - else - mpr("Partly explored, some areas are inaccessible."); - stop_running(); - } + explore_find_target_square(); } } @@ -1028,335 +1064,460 @@ static void fill_exclude_radius(const coord_def &c) for (int x = c.x - radius; x <= c.x + radius; ++x) { if (!map_bounds(x, y) || !is_terrain_known(x, y) - || point_distance[x][y]) + || travel_point_distance[x][y]) continue; if (is_exclude_root(x, y)) - point_distance[x][y] = PD_EXCLUDED; + travel_point_distance[x][y] = PD_EXCLUDED; else if (is_excluded(x, y)) - point_distance[x][y] = PD_EXCLUDED_RADIUS; + travel_point_distance[x][y] = PD_EXCLUDED_RADIUS; } } } -static bool is_greed_inducing_square(const LevelStashes *ls, int x, int y) +///////////////////////////////////////////////////////////////////////////// +// travel_pathfind + +FixedVector travel_pathfind::circumference[2]; + +const int travel_pathfind::UNFOUND_DIST; +const int travel_pathfind::INFINITE_DIST; + +travel_pathfind::travel_pathfind() + : runmode(RMODE_NOT_RUNNING), start(), dest(), next_travel_move(), + floodout(false), double_flood(false), ignore_hostile(false), + annotate_map(false), ls(NULL), need_for_greed(false), + unexplored_place(), greedy_place(), unexplored_dist(0), + greedy_dist(0), refdist(NULL), reseed_points(), + features(NULL), point_distance(travel_point_distance), + points(0), next_iter_points(0), traveled_distance(0), + circ_index(0) { - return (ls && ls->needs_visit(x, y)); } -/* - * The travel algorithm is based on the NetHack travel code written by Warwick - * Allison - used with his permission. - */ -void find_travel_pos(int youx, int youy, - char *move_x, char *move_y, - std::vector* features) +bool travel_pathfind::is_greed_inducing_square(const coord_def &c) const { - init_terrain_check(); + return (ls && ls->needs_visit(c.x, c.y)); +} - int start_x = you.running.x, start_y = you.running.y; - int dest_x = youx, dest_y = youy; - bool floodout = false; - unsigned char feature; - const LevelStashes *lev = stashes.find_current_level(); - const bool need_for_greed = - you.running == RMODE_EXPLORE_GREEDY && can_autopickup(); +void travel_pathfind::set_src_dst(const coord_def &src, const coord_def &dst) +{ + // Yes, this is backwards - for travel, we always start from the destination + // and search outwards for the starting position. + start = dst; + dest = src; - // For greedy explore, keep track of the closest unexplored - // territory and the closest greedy square. - int e_x = 0, e_y = 0; // Unexplored - int i_x = 0, i_y = 0; // Square with interesting item. - // Use these weird defaults to handle negative item greeds. - int ex_dist = -10000, ix_dist = -10000; + floodout = double_flood = false; +} - // Normally we start from the destination and floodfill outwards, looking - // for the character's current position. If we're merely trying to populate - // the point_distance array (or exploring), we'll want to start from the - // character's current position and fill outwards - if (!move_x || !move_y) - { - start_x = youx; - start_y = youy; +void travel_pathfind::set_floodseed(const coord_def &seed, bool dblflood) +{ + start = seed; + dest.reset(); - dest_x = dest_y = -1; + floodout = true; + double_flood = dblflood; +} - floodout = true; - } +void travel_pathfind::set_annotate_map(bool annotate) +{ + annotate_map = annotate; +} + +void travel_pathfind::set_distance_grid(travel_distance_grid_t grid) +{ + point_distance = grid; +} + +void travel_pathfind::set_feature_vector(std::vector *feats) +{ + features = feats; - // Abort run if we're trying to go someplace evil - if (dest_x != -1 && !is_travel_ok(start_x, start_y, false) && - !is_trap(start_x, start_y)) + if (features) { - you.running = RMODE_NOT_RUNNING; - return ; + double_flood = true; + annotate_map = true; } +} + +const coord_def travel_pathfind::travel_move() const +{ + return (next_travel_move); +} + +const coord_def travel_pathfind::explore_target() const +{ + if (unexplored_dist != UNFOUND_DIST && greedy_dist != UNFOUND_DIST) + return (unexplored_dist < greedy_dist? unexplored_place : greedy_place); + else if (unexplored_dist != UNFOUND_DIST) + return (unexplored_place); + else if (greedy_dist != UNFOUND_DIST) + return (greedy_place); + + return coord_def(0, 0); +} + +const coord_def travel_pathfind::greedy_square() const +{ + return (greedy_place); +} + +const coord_def travel_pathfind::unexplored_square() const +{ + return (unexplored_place); +} + +/* + * The travel algorithm is based on the NetHack travel code written by Warwick + * Allison - used with his permission. + */ +const coord_def travel_pathfind::pathfind(run_mode_type rmode) +{ + if (rmode == RMODE_INTERLEVEL) + rmode = RMODE_TRAVEL; + + runmode = rmode; + + // Check whether species or levitation permits travel through terrain such + // as deep water. + init_terrain_check(); - // Abort run if we're going nowhere. - if (start_x == dest_x && start_y == dest_y) + need_for_greed = + (rmode == RMODE_EXPLORE_GREEDY && can_autopickup()); + + if (!ls && (annotate_map || need_for_greed)) + ls = stashes.find_current_level(); + + next_travel_move.reset(); + + // For greedy explore, keep track of the closest unexplored territory and + // the closest greedy square. Exploring to the nearest (unexplored / greedy) + // square is easier, but it produces unintuitive explore behaviour where + // grabbing items is not favoured over simple exploring. + // + // Greedy explore instead uses the explore_item_greed option to weight + // greedy explore towards grabbing items over exploring. An + // explore_item_greed set to 10, for instance, forces explore to prefer + // items that are less than 10 squares farther away from the player than the + // nearest unmapped square. Negative explore_item_greed values force greedy + // explore to favour unexplored territory over picking up items. For the + // most natural greedy explore behaviour, explore_item_greed should be set + // to 10 or more. + // + unexplored_place = greedy_place = coord_def(0, 0); + unexplored_dist = greedy_dist = UNFOUND_DIST; + + refdist = Options.explore_item_greed > 0? &unexplored_dist: &greedy_dist; + + // Abort run if we're trying to go someplace evil. Travel to traps is + // specifically allowed here if the player insists on it. + if (!floodout + && !is_travel_ok(start.x, start.y, false) + && !is_trap(start.x, start.y)) // The player likes pain { - you.running = RMODE_NOT_RUNNING; - return ; + return coord_def(0, 0); } + // Nothing to do? + if (!floodout && start == dest) + return (start); + // How many points are we currently considering? We start off with just one // point, and spread outwards like a flood-filler. - int points = 1; + points = 1; // How many points we'll consider next iteration. - int next_iter_points = 0; + next_iter_points = 0; // How far we've traveled from (start_x, start_y), in moves (a diagonal move // is no longer than an orthogonal move). - int traveled_distance = 1; + traveled_distance = 1; // Which index of the circumference array are we currently looking at? - int circ_index = 0; - - // The circumference points of the floodfilled area, for this iteration - // and the next (this iteration's points being circ_index amd the next one's - // being !circ_index). - static FixedVector circumference[2]; - - // Coordinates of all discovered traps. If we're exploring instead of - // travelling, we'll reseed from these points after we've explored the map - std::vector trap_seeds; - - // When set to true, the travel code ignores features, traps and hostile - // terrain, and simply tries to map contiguous floorspace. Will only be set - // to true if we're exploring, instead of travelling. - bool ignore_hostile = false; + circ_index = 0; + + ignore_hostile = false; // Set the seed point - circumference[circ_index][0].x = start_x; - circumference[circ_index][0].y = start_y; + circumference[circ_index][0] = start; // Zap out previous distances array - memset(point_distance, 0, sizeof point_distance); + memset(point_distance, 0, sizeof(travel_distance_grid_t)); for ( ; points > 0; ++traveled_distance, circ_index = !circ_index, points = next_iter_points, next_iter_points = 0) { for (int i = 0; i < points; ++i) { - int x = circumference[circ_index][i].x, - y = circumference[circ_index][i].y; - - // (x,y) is a known (explored) location - we never put unknown - // points in the circumference vector, so we don't need to examine - // the map array, just the grid array. - feature = grd[x][y]; - - // If this is a feature that'll take time to travel past, we - // simulate that extra turn by taking this feature next turn, - // thereby artificially increasing traveled_distance. - // - // Note: I don't know how slow walking through shallow water and - // opening closed doors is - right now it's considered to have - // the cost of two normal moves. - int feat_cost = feature_traverse_cost(feature); - if (feat_cost > 1 - && point_distance[x][y] > traveled_distance - feat_cost) + if (path_examine_point(circumference[circ_index][i])) { - circumference[!circ_index][next_iter_points].x = x; - circumference[!circ_index][next_iter_points].y = y; - next_iter_points++; - continue; + return (runmode == RMODE_TRAVEL? travel_move() + : explore_target()); } + } - // For each point, we look at all surrounding points. Take them - // orthogonals first so that the travel path doesn't zigzag all over - // the map. Note the (dir = 1) is intentional assignment. - for (int dir = 0; dir < 8; (dir += 2) == 8 && (dir = 1)) + if (next_iter_points == 0) + { + // Don't reseed unless we've found no target for explore, OR + // we're doing map annotation or feature tracking. + if ((runmode == RMODE_EXPLORE || runmode == RMODE_EXPLORE_GREEDY) + && double_flood + && !ignore_hostile + && !features + && !annotate_map + && (unexplored_dist != UNFOUND_DIST + || greedy_dist != UNFOUND_DIST)) { - int dx = x + Compass[dir].x, dy = y + Compass[dir].y; + break; + } - if (!in_bounds(dx, dy)) - continue; + if (double_flood + && !ignore_hostile + && !reseed_points.empty()) + { + // Reseed here + for (unsigned i = 0, size = reseed_points.size(); i < size; ++i) + circumference[!circ_index][i] = reseed_points[i]; + next_iter_points = reseed_points.size(); + ignore_hostile = true; + } + } + } // for ( ; points > 0 ... - unsigned char envf = env.map[dx - 1][dy - 1]; + if (features && floodout) + { + for (int i = 0, size = curr_excludes.size(); i < size; ++i) + { + const coord_def &exc = curr_excludes[i]; + // An exclude - wherever it is - is always a feature. + if (std::find(features->begin(), features->end(), exc) + == features->end()) + features->push_back(exc); - if (floodout && you.running.is_explore()) - { - if (!is_player_mapped(envf)) - { - if (!need_for_greed) - { - you.running.x = x; - you.running.y = y; - return; - } - - if (ex_dist == -10000) - { - e_x = x; - e_y = y; - ex_dist = - traveled_distance + Options.explore_item_greed; - } - } - else if (need_for_greed - && ix_dist == -10000 - && is_greed_inducing_square(lev, dx, dy) - && is_travel_ok(dx, dy, ignore_hostile)) - { - i_x = dx; - i_y = dy; - ix_dist = traveled_distance + 1; - } + fill_exclude_radius(exc); + } + } - // Short-circuit if we can. - if (need_for_greed) - { - const int refdist = - Options.explore_item_greed > 0? ex_dist: ix_dist; - - if (refdist != -10000 - && traveled_distance > refdist) - { - if (Options.explore_item_greed > 0) - ix_dist = 10000; - else - ex_dist = 10000; - } - } - - // ex_dist/ix_dist are only ever set in - // greedy-explore so this check implies - // greedy-explore. - if (ex_dist != -10000 && ix_dist != -10000) - { - if (ex_dist < ix_dist) - { - you.running.x = e_x; - you.running.y = e_y; - } - else - { - you.running.x = i_x; - you.running.y = i_y; - } - return; - } - - } + return (rmode == RMODE_TRAVEL? travel_move() + : explore_target()); +} - if ((dx != dest_x || dy != dest_y) - && !is_travel_ok(dx, dy, ignore_hostile)) - { - // This point is not okay to travel on, but if this is a - // trap, we'll want to put it on the feature vector anyway. - if (is_reseedable(dx, dy) - && !point_distance[dx][dy] - && (dx != start_x || dy != start_y)) - { - if (features) - { - const coord_def c(dx, dy); - if (is_trap(dx, dy) || is_exclude_root(dx, dy)) - features->push_back(c); - trap_seeds.push_back(c); - } - - // Appropriate mystic number. Nobody else should check - // this number, since this square is unsafe for travel. - point_distance[dx][dy] = - is_exclude_root(dx, dy)? PD_EXCLUDED : - is_excluded(dx, dy) ? PD_EXCLUDED_RADIUS : - PD_TRAP; - } - continue; - } +bool travel_pathfind::square_slows_movement(const coord_def &c) +{ + // c is a known (explored) location - we never put unknown points in the + // circumference vector, so we don't need to examine the map array, just the + // grid array. + const int feature = grd(c); - if (dx == dest_x && dy == dest_y) - { - // Hallelujah, we're home! - if (is_safe_move(x, y) && move_x && move_y) - { - *move_x = sgn(x - dest_x); - *move_y = sgn(y - dest_y); - } - return ; - } - else if (!point_distance[dx][dy]) - { - // This point is going to be on the agenda for the next - // iteration - circumference[!circ_index][next_iter_points].x = dx; - circumference[!circ_index][next_iter_points].y = dy; - next_iter_points++; + // If this is a feature that'll take time to travel past, we simulate that + // extra turn by taking this feature next turn, thereby artificially + // increasing traveled_distance. + // + // Walking through shallow water and opening closed doors is considered to + // have the cost of two normal moves for travel purposes. + const int feat_cost = feature_traverse_cost(feature); + if (feat_cost > 1 + && point_distance[c.x][c.y] > traveled_distance - feat_cost) + { + circumference[!circ_index][next_iter_points++] = c; + return (true); + } - point_distance[dx][dy] = traveled_distance; + return (false); +} - // Negative distances here so that show_map can colour - // the map differently for these squares. - if (ignore_hostile) - { - point_distance[dx][dy] = -point_distance[dx][dy]; - if (is_exclude_root(dx, dy)) - point_distance[dx][dy] = PD_EXCLUDED; - else if (is_excluded(dx, dy)) - point_distance[dx][dy] = PD_EXCLUDED_RADIUS; - } +void travel_pathfind::check_square_greed(const coord_def &c) +{ + if (greedy_dist == UNFOUND_DIST + && is_greed_inducing_square(c) + && is_travel_ok(c.x, c.y, ignore_hostile)) + { + greedy_place = c; + greedy_dist = traveled_distance; + } +} - feature = grd[dx][dy]; - if (features && !ignore_hostile - && ((feature != DNGN_FLOOR - && feature != DNGN_SHALLOW_WATER - && feature != DNGN_DEEP_WATER - && feature != DNGN_LAVA) - || is_waypoint(dx, dy) - || is_stash(lev, dx, dy)) - && (dx != start_x || dy != start_y)) - { - const coord_def c(dx, dy); - features->push_back(c); - } +bool travel_pathfind::path_flood(const coord_def &c, const coord_def &dc) +{ + if (!in_bounds(dc)) + return (false); - if (features && is_exclude_root(dx, dy) && dx != start_x - && dy != start_y) - { - const coord_def c(dx, dy); - features->push_back(c); - } - } - } // for (dir = 0; dir < 8 ... - } // for (i = 0; i < points ... + if (floodout + && (runmode == RMODE_EXPLORE || runmode == RMODE_EXPLORE_GREEDY)) + { + if (!is_terrain_seen(dc)) + { + if (!need_for_greed) + { + // Found explore target! + unexplored_place = c; + unexplored_dist = traveled_distance; + return (true); + } + + if (unexplored_dist == UNFOUND_DIST) + { + unexplored_place = c; + unexplored_dist = + traveled_distance + Options.explore_item_greed; + } + } - if (!next_iter_points && features && !move_x && !ignore_hostile - && trap_seeds.size()) + // Short-circuit if we can. If traveled_distance (the current + // distance from the center of the floodfill) is greater + // than the adjusted distance to the nearest greedy explore + // target, we have a target. Note the adjusted distance is + // the distance with explore_item_greed applied (if + // explore_item_greed > 0, it is added to the distance to + // unexplored terrain, if explore_item_greed < 0, it is + // added to the distance to interesting items. + // + // We never short-circuit if ignore_hostile is true. This is + // important so we don't need to do multiple floods to work out + // whether explore is complete. + if (need_for_greed + && !ignore_hostile + && *refdist != UNFOUND_DIST + && traveled_distance > *refdist) { - // Reseed here - for (unsigned i = 0; i < trap_seeds.size(); ++i) - circumference[!circ_index][i] = trap_seeds[i]; - next_iter_points = trap_seeds.size(); - ignore_hostile = true; + if (Options.explore_item_greed > 0) + greedy_dist = INFINITE_DIST; + else + unexplored_dist = INFINITE_DIST; } - } // for ( ; points > 0 ... + + // greedy_dist is only ever set in greedy-explore so this check + // implies greedy-explore. + if (unexplored_dist != UNFOUND_DIST && greedy_dist != UNFOUND_DIST) + return (true); + } - if (features && floodout) + if (dc != dest && !is_travel_ok(dc.x, dc.y, ignore_hostile)) { - for (int i = 0, size = curr_excludes.size(); i < size; ++i) + // This point is not okay to travel on, but if this is a + // trap, we'll want to put it on the feature vector anyway. + if (is_reseedable(dc.x, dc.y) + && !point_distance[dc.x][dc.y] + && dc != start) { - const coord_def &exc = curr_excludes[i]; - // An exclude - wherever it is - is always a feature. - if (std::find(features->begin(), features->end(), exc) - == features->end()) - features->push_back(exc); + if (features && + (is_trap(dc.x, dc.y) || is_exclude_root(dc.x, dc.y))) + { + features->push_back(dc); + } - fill_exclude_radius(exc); + if (double_flood) + reseed_points.push_back(dc); + + // Appropriate mystic number. Nobody else should check + // this number, since this square is unsafe for travel. + point_distance[dc.x][dc.y] = + is_exclude_root(dc.x, dc.y)? PD_EXCLUDED : + is_excluded(dc.x, dc.y) ? PD_EXCLUDED_RADIUS : + PD_TRAP; } + return (false); } - if (need_for_greed && (ex_dist != -10000 || ix_dist != -10000)) + if (dc == dest) + { + // Hallelujah, we're home! + if (is_safe_move(c.x, c.y)) + next_travel_move = c; + return (true); + } + else if (!point_distance[dc.x][dc.y]) { - if (ix_dist != -10000) + // This point is going to be on the agenda for the next + // iteration + circumference[!circ_index][next_iter_points++] = dc; + point_distance[dc.x][dc.y] = traveled_distance; + + // Negative distances here so that show_map can colour + // the map differently for these squares. + if (ignore_hostile) { - e_x = i_x; - e_y = i_y; + point_distance[dc.x][dc.y] = -point_distance[dc.x][dc.y]; + if (is_exclude_root(dc.x, dc.y)) + point_distance[dc.x][dc.y] = PD_EXCLUDED; + else if (is_excluded(dc.x, dc.y)) + point_distance[dc.x][dc.y] = PD_EXCLUDED_RADIUS; } - you.running.x = e_x; - you.running.y = e_y; + if (features && !ignore_hostile) + { + const int feature = grd(dc); + + if (((feature != DNGN_FLOOR + && feature != DNGN_SHALLOW_WATER + && feature != DNGN_DEEP_WATER + && feature != DNGN_LAVA) + || is_waypoint(dc.x, dc.y) + || is_stash(ls, dc.x, dc.y)) + && dc != start) + { + features->push_back(dc); + } + } + + if (features && dc != start && is_exclude_root(dc.x, dc.y)) + features->push_back(dc); + } + + return (false); +} + +bool travel_pathfind::path_examine_point(const coord_def &c) +{ + if (square_slows_movement(c)) + return (false); + + // Greedy explore check should happen on (x,y), not (dx,dy) as for + // regular explore. + if (need_for_greed) + check_square_greed(c); + + // For each point, we look at all surrounding points. Take them orthogonals + // first so that the travel path doesn't zigzag all over the map. Note the + // (dir = 1) is intentional assignment. + for (int dir = 0; dir < 8; (dir += 2) == 8 && (dir = 1)) + { + if (path_flood(c, c + Compass[dir])) + return (true); + } + + return (false); +} + +///////////////////////////////////////////////////////////////////////////// + +void find_travel_pos(int youx, int youy, + char *move_x, char *move_y, + std::vector* features) +{ + travel_pathfind tp; + + if (move_x && move_y) + tp.set_src_dst(coord_def(youx, youy), + coord_def(you.running.x, you.running.y)); + else + tp.set_floodseed(coord_def(youx, youy)); + + tp.set_feature_vector(features); + + run_mode_type rmode = move_x && move_y? RMODE_TRAVEL : RMODE_NOT_RUNNING; + + const coord_def dest = tp.pathfind( rmode ); + + if (dest.x == 0 && dest.y == 0) + { + if (move_x && move_y) + you.running = RMODE_NOT_RUNNING; + } + else if (move_x && move_y) + { + *move_x = dest.x - youx; + *move_y = dest.y - youy; } } @@ -1915,8 +2076,9 @@ static int target_distance_from(const coord_def &pos) * travel-safe path between the player's current level and the target level OR * the player's current level *is* the target level. * - * This function relies on the point_distance array being correctly populated - * with a floodout call to find_travel_pos starting from the player's location. + * This function relies on the travel_point_distance array being correctly + * populated with a floodout call to find_travel_pos starting from the player's + * location. */ static int find_transtravel_stair( const level_id &cur, const level_pos &target, @@ -1958,8 +2120,8 @@ static int find_transtravel_stair( const level_id &cur, // populate_stair_distances. Assuming we're not on stairs, that // situation can arise only if interlevel travel has been triggered // for a location on the same level. If that's the case, we can get - // the distance off the point_distance matrix. - deltadist = point_distance[target.pos.x][target.pos.y]; + // the distance off the travel_point_distance matrix. + deltadist = travel_point_distance[target.pos.x][target.pos.y]; if (!deltadist && (stair.x != target.pos.x || stair.y != target.pos.y)) deltadist = -1; @@ -2012,7 +2174,7 @@ static int find_transtravel_stair( const level_id &cur, int deltadist = li.distance_between(this_stair, &si); if (!this_stair) { - deltadist = point_distance[si.position.x][si.position.y]; + deltadist = travel_point_distance[si.position.x][si.position.y]; if (!deltadist && (you.x_pos != si.position.x || you.y_pos != si.position.y)) deltadist = -1; @@ -2128,7 +2290,7 @@ static bool loadlev_populate_stair_distances(const level_pos &target) static void populate_stair_distances(const level_pos &target) { - // Populate point_distance. + // Populate travel_point_distance. find_travel_pos(target.pos.x, target.pos.y, NULL, NULL, NULL); LevelInfo &li = travel_cache.get_level_info(target.id); @@ -2138,7 +2300,7 @@ static void populate_stair_distances(const level_pos &target) for (int i = 0, count = stairs.size(); i < count; ++i) { stair_info si = stairs[i]; - si.distance = point_distance[si.position.x][si.position.y]; + si.distance = travel_point_distance[si.position.x][si.position.y]; if (!si.distance && target.pos != si.position) si.distance = -1; if (si.distance < -1) @@ -2200,8 +2362,8 @@ void start_travel(int x, int y) // Start running you.running = RMODE_TRAVEL; - you.running.x = x; - you.running.y = y; + you.running.x = x; + you.running.y = y; // Remember where we're going so we can easily go back if interrupted. you.travel_x = x; @@ -2210,7 +2372,7 @@ void start_travel(int x, int y) // Check whether we can get to the square. find_travel_pos(you.x_pos, you.y_pos, NULL, NULL, NULL); - if (point_distance[x][y] == 0 + if (travel_point_distance[x][y] == 0 && (x != you.x_pos || you.running.y != you.y_pos) && is_travel_ok(x, y, false) && can_travel_interlevel()) @@ -2462,7 +2624,7 @@ void LevelInfo::update_stair_distances() { int ox = stairs[other].position.x, oy = stairs[other].position.y; - int dist = point_distance[ox][oy]; + int dist = travel_point_distance[ox][oy]; // Note dist == 0 is illegal because we can't have two stairs on // the same square. @@ -3225,7 +3387,9 @@ void explore_discoveries::found_feature(const coord_def &pos, int grid) cleaned_feature_description(grid), grid ) ); es_flags |= ES_STAIR; } - else if (is_altar(grid) && ES_altar) + else if (is_altar(grid) + && ES_altar + && !player_in_branch(BRANCH_ECUMENICAL_TEMPLE)) { altars.push_back( named_thing( @@ -3290,9 +3454,9 @@ bool explore_discoveries::prompt_stop() const return (false); say_any(items, "Found %u items."); - say_any(stairs, "Found %u stairs."); - say_any(altars, "Found %u altars."); say_any(shops, "Found %u shops."); + say_any(altars, "Found %u altars."); + say_any(stairs, "Found %u stairs."); return ((Options.explore_stop_prompt & es_flags) != es_flags || prompt_stop_explore(es_flags)); diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h index 010d8cd626..6493e37209 100644 --- a/crawl-ref/source/travel.h +++ b/crawl-ref/source/travel.h @@ -71,19 +71,26 @@ void prevent_travel_to(const std::string &dungeon_feature_name); // Sort dungeon features as appropriate. void arrange_features(std::vector &features); +struct level_id; +int level_distance(level_id first, level_id second); + +bool can_travel_to(const level_id &lid); +bool can_travel_interlevel(); +bool prompt_stop_explore(int es_why); + // Magic numbers for point_distance: // This square is a trap -#define PD_TRAP -42 +const int PD_TRAP = -42; // The user never wants to travel this square -#define PD_EXCLUDED -20099 +const int PD_EXCLUDED = -20099; // This square is within LOS radius of an excluded square -#define PD_EXCLUDED_RADIUS -20100 +const int PD_EXCLUDED_RADIUS = -20100; -// This square is a waypoint -#define PD_WAYPOINT -20200 +typedef int travel_distance_col[GYM]; +typedef travel_distance_col travel_distance_grid_t[GXM]; /* *********************************************************************** * Array of points on the map, each value being the distance the character @@ -93,7 +100,7 @@ void arrange_features(std::vector &features); * *********************************************************************** * referenced in: travel - view * *********************************************************************** */ -extern short point_distance[GXM][GYM]; +extern travel_distance_grid_t travel_point_distance; enum explore_stop_type { @@ -345,7 +352,7 @@ private: friend class TravelCache; }; -#define TRAVEL_WAYPOINT_COUNT 10 +const int TRAVEL_WAYPOINT_COUNT = 10; // Tracks all levels that the player has seen. class TravelCache { @@ -408,11 +415,127 @@ private: level_pos waypoints[TRAVEL_WAYPOINT_COUNT]; }; -int level_distance(level_id first, level_id second); +// Handles travel and explore floodfill pathfinding. Does not do interlevel +// travel pathfinding directly (but is used internally by interlevel travel). +// * All coordinates are grid coords. +// * Do not reuse one travel_pathfind for different runmodes. +class travel_pathfind +{ +public: + travel_pathfind(); -bool can_travel_to(const level_id &lid); -bool can_travel_interlevel(); -bool prompt_stop_explore(int es_why); + // Finds travel direction or explore target. + const coord_def pathfind(run_mode_type rt); + + // For flood-fills (explore), sets starting (seed) square. + void set_floodseed(const coord_def &seed, bool double_flood = false); + + // For regular travel, set starting point (usually the character's current + // position) and destination. + void set_src_dst(const coord_def &src, const coord_def &dst); + + // Request that the point distance array be annotated with magic numbers for + // excludes and waypoints. + void set_annotate_map(bool annotate); + + // Sets the travel_distance_grid_t to use instead of travel_point_distance. + void set_distance_grid(travel_distance_grid_t distgrid); + + // Set feature vector to use; if non-NULL, also sets annotate_map to true. + void set_feature_vector(std::vector *features); + + // The next square to go to to move towards the travel destination. Return + // value is undefined if pathfind was not called with RMODE_TRAVEL. + const coord_def travel_move() const; + + // Square to go to for (greedy) explore. Return value is undefined if + // pathfind was not called with RMODE_EXPLORE or RMODE_EXPLORE_GREEDY. + const coord_def explore_target() const; + + // Nearest greed-inducing square. Return value is undefined if + // pathfind was not called with RMODE_EXPLORE_GREEDY. + const coord_def greedy_square() const; + + // Nearest unexplored territory. Return value is undefined if + // pathfind was not called with RMODE_EXPLORE or + // RMODE_EXPLORE_GREEDY. + const coord_def unexplored_square() const; + +private: + bool is_greed_inducing_square(const coord_def &c) const; + bool path_examine_point(const coord_def &c); + bool path_flood(const coord_def &c, const coord_def &dc); + bool square_slows_movement(const coord_def &c); + void check_square_greed(const coord_def &c); + +private: + static const int UNFOUND_DIST = -10000; + static const int INFINITE_DIST = 10000; + +private: + run_mode_type runmode; + + // Where pathfinding starts, and the destination. Note that dest is not + // relevant for explore! + coord_def start, dest; + + // This is the square adjacent to the starting position to move + // along the shortest path to the destination. Does *not* apply + // for explore! + coord_def next_travel_move; + + // True if flooding outwards from start square for explore. + bool floodout, double_flood; + + // Set true in the second part of a double floodfill to completely ignore + // hostile squares. + bool ignore_hostile; + + // If true, use magic numbers in point distance array which can be + // used to colour the level-map. + bool annotate_map; + + // Stashes on this level (needed for greedy explore and to populate the + // feature vector with stashes on the X level-map). + const LevelStashes *ls; + + // Are we greedy exploring? + bool need_for_greed; + + // Targets for explore and greedy explore. + coord_def unexplored_place, greedy_place; + + // How far from player's location unexplored_place and greedy_place are. + int unexplored_dist, greedy_dist; + + const int *refdist; + + // For double-floods, the points to restart floodfill from at the end of + // the first flood. + std::vector reseed_points; + + std::vector *features; + + travel_distance_col *point_distance; + + // How many points are we currently considering? We start off with just one + // point, and spread outwards like a flood-filler. + int points; + + // How many points we'll consider next iteration. + int next_iter_points; + + // How far we've traveled from (start_x, start_y), in moves (a diagonal move + // is no longer than an orthogonal move). + int traveled_distance; + + // Which index of the circumference array are we currently looking at? + int circ_index; + + // Used by all instances of travel_pathfind. Happily, we do not need to be + // re-entrant or thread-safe. + static FixedVector circumference[2]; +}; extern TravelCache travel_cache; diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index d6c4820850..9802222118 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -70,13 +70,7 @@ static FixedVector Feature; -#if defined(DOS_TERM) -// DOS functions like gettext() and puttext() can only -// work with arrays of characters, not shorts. -typedef unsigned char screen_buffer_t; -#else typedef unsigned short screen_buffer_t; -#endif FixedArray < unsigned int, 20, 19 > Show_Backup; @@ -240,7 +234,7 @@ void clear_envmap( void ) } } -#if defined(WIN32CONSOLE) || defined(DOS) || defined(DOS_TERM) +#if defined(WIN32CONSOLE) || defined(DOS) static unsigned colflag2brand(int colflag) { switch (colflag) @@ -264,7 +258,7 @@ static unsigned fix_colour(unsigned raw_colour) // This order is important - is_element_colour() doesn't want to see the // munged colours returned by dos_brand, so it should always be done // before applying DOS brands. -#if defined(WIN32CONSOLE) || defined(DOS) || defined(DOS_TERM) +#if defined(WIN32CONSOLE) || defined(DOS) const int colflags = raw_colour & 0xFF00; #endif @@ -272,7 +266,7 @@ static unsigned fix_colour(unsigned raw_colour) if (is_element_colour( raw_colour )) raw_colour = element_colour( raw_colour ); -#if defined(WIN32CONSOLE) || defined(DOS) || defined(DOS_TERM) +#if defined(WIN32CONSOLE) || defined(DOS) if (colflags) { unsigned brand = colflag2brand(colflags); @@ -352,7 +346,7 @@ static char get_travel_colour( int x, int y ) if (is_waypoint(x + 1, y + 1)) return LIGHTGREEN; - short dist = point_distance[x + 1][y + 1]; + short dist = travel_point_distance[x + 1][y + 1]; return dist > 0? Options.tc_reachable : dist == PD_EXCLUDED? Options.tc_excluded : dist == PD_EXCLUDED_RADIUS? Options.tc_exclude_circle : @@ -1661,7 +1655,7 @@ bool is_feature(int feature, int x, int y) { switch (feature) { case 'X': - return (point_distance[x][y] == PD_EXCLUDED); + return (travel_point_distance[x][y] == PD_EXCLUDED); case 'F': case 'W': return is_waypoint(x, y); @@ -1892,57 +1886,50 @@ static int get_number_of_lines_levelmap() return get_number_of_lines() - (Options.level_map_title ? 1 : 0); } -static void draw_level_map( - int start_x, int start_y, int screen_y, bool travel_mode) +static void draw_level_map(int start_x, int start_y, bool travel_mode) { int bufcount2 = 0; screen_buffer_t buffer2[GYM * GXM * 2]; const int num_lines = get_number_of_lines_levelmap(); + const int num_cols = get_number_of_cols(); cursor_control cs(false); -#ifdef PLAIN_TERM + int top = 1 + Options.level_map_title; if ( Options.level_map_title ) { - gotoxy(1,1); + gotoxy(1, 1); textcolor(WHITE); cprintf("Level %s", level_description_string().c_str()); - gotoxy(1,2); } - else - gotoxy(1, 1); -#endif - for (int j = 0; j < num_lines; j++) + gotoxy(1, top); + + for (int screen_y = 0; screen_y < num_lines; screen_y++) { - for (int i = 0; i < 80; i++) + for (int screen_x = 0; screen_x < num_cols - 1; screen_x++) { screen_buffer_t colour = DARKGREY; - if (start_y + j >= 65 || start_y + j <= 3 - || start_x + i < 0 || start_x + i >= GXM - 1) + + coord_def c(start_x + screen_x, start_y + screen_y); + + if (!in_bounds(c + coord_def(1, 1))) { buffer2[bufcount2 + 1] = DARKGREY; buffer2[bufcount2] = 0; bufcount2 += 2; -#ifdef PLAIN_TERM goto print_it; -#endif - -#ifdef DOS_TERM - continue; -#endif } - colour = colour_code_map(start_x + i, start_y + j, + colour = colour_code_map(c.x, c.y, Options.item_colour, travel_mode && Options.travel_colour); buffer2[bufcount2 + 1] = colour; - buffer2[bufcount2] = - (unsigned char) env.map[start_x + i][start_y + j]; + buffer2[bufcount2] = (unsigned char) env.map(c); - if (start_x + i + 1 == you.x_pos && start_y + j + 1 == you.y_pos) + if (c.x + 1 == you.x_pos && c.y + 1 == you.y_pos) { // [dshaligram] Draw the @ symbol on the level-map. It's no // longer saved into the env.map, so we need to draw it @@ -1951,15 +1938,16 @@ static void draw_level_map( buffer2[bufcount2] = you.symbol; } - // If we've a waypoint on the current square, *and* the square is - // a normal floor square with nothing on it, show the waypoint - // number. + // If we've a waypoint on the current square, *and* the + // square is a normal floor square with nothing on it, + // show the waypoint number. if (Options.show_waypoints) { // XXX: This is a horrible hack. screen_buffer_t &bc = buffer2[bufcount2]; - int gridx = start_x + i + 1, gridy = start_y + j + 1; - unsigned char ch = is_waypoint(gridx, gridy); + const coord_def gridc = c + coord_def(1, 1); + + unsigned char ch = is_waypoint(gridc.x, gridc.y); if (ch && (bc == get_sightmap_char(DNGN_FLOOR) || bc == get_magicmap_char(DNGN_FLOOR))) bc = ch; @@ -1967,16 +1955,10 @@ static void draw_level_map( bufcount2 += 2; -#ifdef PLAIN_TERM - - print_it: - // avoid line wrap - if (i == 79) - continue; - + print_it: // newline - if (i == 0 && j > 0) - gotoxy( 1, j + 1 ); + if (screen_x == 0 && screen_y > 0) + gotoxy( 1, screen_y + top ); int ch = buffer2[bufcount2 - 2]; #ifdef USE_CURSES @@ -1984,17 +1966,12 @@ static void draw_level_map( #endif textcolor( buffer2[bufcount2 - 1] ); putch(ch); -#endif } } #ifdef USE_CURSES set_altcharset(false); #endif - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer2); -#endif } // show_map() now centers the known map along x or y. This prevents @@ -2010,10 +1987,6 @@ void show_map( FixedVector &spec_place, bool travel_mode ) char move_y = 0; char getty = 0; -#ifdef DOS_TERM - char buffer[4800]; -#endif - // Vector to track all features we can travel to, in order of distance. std::vector features; if (travel_mode) @@ -2029,7 +2002,9 @@ void show_map( FixedVector &spec_place, bool travel_mode ) bool found_y = false; const int num_lines = get_number_of_lines_levelmap(); - const int half_screen = num_lines / 2 - 1; + const int half_screen = (num_lines - 1) / 2; + + const int top = 1 + Options.level_map_title; for (j = 0; j < GYM; j++) { @@ -2084,11 +2059,6 @@ void show_map( FixedVector &spec_place, bool travel_mode ) bool map_alive = true; bool redraw_map = true; -#ifdef DOS_TERM - gettext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif - clrscr(); textcolor(DARKGREY); @@ -2097,10 +2067,10 @@ void show_map( FixedVector &spec_place, bool travel_mode ) start_y = screen_y - half_screen; if (redraw_map) - draw_level_map(start_x, start_y, screen_y, travel_mode); + draw_level_map(start_x, start_y, travel_mode); redraw_map = true; - gotoxy(curs_x, curs_y); + gotoxy(curs_x, curs_y + top - 1); getty = unmangle_direction_keys(getchm(KC_LEVELMAP), KC_LEVELMAP); @@ -2350,10 +2320,10 @@ void show_map( FixedVector &spec_place, bool travel_mode ) if (curs_y + move_y < 1) { - // screen_y += (curs_y + move_y) - 1; screen_y += move_y; - if (screen_y < min_y + half_screen) { + if (screen_y < min_y + half_screen) + { move_y = screen_y - (min_y + half_screen); screen_y = min_y + half_screen; } @@ -2361,12 +2331,12 @@ void show_map( FixedVector &spec_place, bool travel_mode ) move_y = 0; } - if (curs_y + move_y > num_lines - 1) + if (curs_y + move_y > num_lines) { - // screen_y += (curs_y + move_y) - num_lines + 1; screen_y += move_y; - if (screen_y > max_y - half_screen) { + if (screen_y > max_y - half_screen) + { move_y = screen_y - (max_y - half_screen); screen_y = max_y - half_screen; } @@ -2381,10 +2351,6 @@ void show_map( FixedVector &spec_place, bool travel_mode ) curs_y += move_y; } -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return; } // end show_map() @@ -2453,17 +2419,30 @@ void magic_mapping(int map_radius, int proportion) if (empty_count > 0) { if (!get_envmap_char(i, j)) + { set_envmap_char(i, j, get_magicmap_char(grd[i][j])); +#ifdef WIZARD + if (map_radius == 1000) + set_envmap_char(i, j, get_sightmap_char(grd[i][j])); +#endif + } + // Hack to give demonspawn Pandemonium mutation the ability // to detect exits magically. if ((you.mutation[MUT_PANDEMONIUM] > 1 && grd[i][j] == DNGN_EXIT_PANDEMONIUM) - // Wizmode - || map_radius == 1000) +#ifdef WIZARD + || map_radius == 1000 +#endif + ) + { set_terrain_seen( i, j ); + } else + { set_terrain_mapped( i, j ); + } } } } @@ -3460,11 +3439,6 @@ void viewwindow(bool draw_it, bool do_updates) // and this simply works without requiring a stack. you.flash_colour = BLACK; -#ifdef DOS_TERM - puttext( 2, 1, X_SIZE + 1, Y_SIZE, buffy.buffer() ); -#endif - -#ifdef PLAIN_TERM // avoiding unneeded draws when running if (!you.running || (you.running < 0 && Options.travel_delay > -1)) { @@ -3489,8 +3463,6 @@ void viewwindow(bool draw_it, bool do_updates) #ifdef USE_CURSES set_altcharset( false ); -#endif - #endif } } // end viewwindow() diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h index 9175f46e95..a4eba7d894 100644 --- a/crawl-ref/source/view.h +++ b/crawl-ref/source/view.h @@ -127,6 +127,11 @@ bool is_terrain_known( int x, int y ); bool is_terrain_seen( int x, int y ); bool is_terrain_changed( int x, int y ); +inline bool is_terrain_seen(const coord_def &c) +{ + return (is_terrain_seen(c.x, c.y)); +} + void clear_feature_overrides(); void add_feature_override(const std::string &text); void clear_cset_overrides(); -- cgit v1.2.3-54-g00ecf