summaryrefslogblamecommitdiffstats
path: root/crawl-ref/source/stuff.cc
blob: 69b9e278ff949520f51ea5e1f307b40a8f6e7878 (plain) (tree)
1
2
3
4
5
6
7
8



                              


                   
 


                  
                 
                
                  
                    
                     
                    
                
                
                    
                 
                      

                      
                  
                   
                 

                     
 
                  

                  
                    
 
                  



                   



                 
           


                     
      
 
                   
                  
                    
                    
                  

                  
                      
                     
                  
                   
                   
                     
                     

                 
                                                                    
 
                                                             

























                                              





                                            



















                                                    
                         
                                                         





                                                

                              


                 
                  
                                 
            
                                                         

     



                                        

 



                                       
                                                        





                                     



                
                                           



                                     
                                                  


                                            
 

                                      
                       
 

                                        
                                 
                                      
                                     


                       
 

                                                   
 

                                    
 
                                                            
                                          
                          
                                                              


                       
 



                                                                  
                               

                           

                                                                    


                                                                          
                           
         

     

                                                
 



                                       
 
                                       
                                                   
 






                                                                           
                                                   
     
                                                  
                                 
                           
     
 




























                                                                               
                                             






                                                                            
         

                                  


     

                      
                                          



                                             
 
                                      





                                    
 
 
               
 
                                 
 
                                       


                         
                                                    


                   
                    

                  
 

                              

                               



                   
                                                                    




                                                                        



                  
                               
               

                     
                     
                   
                          

      
                                                    

                     
 
                                    
                            
                                  
 
 






                                         





                                                                               
                                                                  
 
                                                          
 
                  
                             



                              
                          

                                                      
 





                                                       
                       



                                              
                      
     
 


                                                           

                                                       




                                                      
 
                          
                    



                        

                               
                                                     


                 
 

                  
                                   
                                   
                                   
                                   
                                   
                                   
                                   


                                   
 

                                                                       



                                    
                     
 

                                          
                
                           

                            
                        
                                
 
                      
 

                                                                                
                                                                           
                                                                  
                                       


























                                                                              


                                                                       









                                                                
                               












                                                                           
 
 
                           
 























                                                                        
                                  



                                          
                                                           

                                                                 

                                                            



                                                      
                                  
                                  
                                   



              
                               
                               
                                       



              
                             
                             
                                    
     
 
 
                                                  



                               
                                     
                                                                          
                                                  
              




                                          
                                              
              


                                     

                                    
                                        
              

                                                       
                                        
              

                                             
                                        


                                      
                                        

                
                                         
                                        


                                              
                                        




                                  
                                          
                                        




                                         
 
 














                                                                           
                       
                                    


                       

 

                                                        
                                                                         

                                                 
 
                                                            
                                                 
 
                                                                          
 
                
     
                      
                                              
 
                                      
 








                                                                            


                                                
                      
                                                                  
                                                                        
         
                             
         
 
                                                    
                                
                                                                 







                                 
                           
                            
                          
                           

                                               
 
 













                                                               
 



                                    
 





                                  
 






                                     
 


                
                                                           

                                                             



                                                                     

                                                     

                                                      
 
                    

 


                                                                  
                                                                          
                                                              
 


                                                 



                                                                  
                
     
                                          
 
                                      
 


                                                                               
                      
         
 




                                                                     
                                                                 








                                 
                                                                 
                     







                                                                                    
            
         

                                                                                
         
     
 
 
                                        
 
                                                  
 
 


                                                               
 









                                                    

                        
 


                                                         

                                                                   
 
                                                                
     
                                                   
                                
         
                                                   
                                           
                         
 
                                                 
 

                                                  
             
                                                     
                 






                                                         
                 
             
                                              
         
     
 
                   
 
 
                                              
 
                                                                            



                                                                           
                                      
 



                                                          
 
                                            
     
                       
         
                                 






                                                             

                                                                     
                     
 
                             
                                                   
 
                                                                    
                                    
                                                                           
                               
                                                                  
     
 
 




















                                                       

                        
                                                                   
 

























                                    
/*
 *  File:       stuff.cc
 *  Summary:    Misc stuff.
 *  Written by: Linley Henzell
 */

#include "AppHdr.h"

#include "stuff.h"

#include "areas.h"
#include "beam.h"
#include "cio.h"
#include "coord.h"
#include "coordit.h"
#include "database.h"
#include "directn.h"
#include "env.h"
#include "los.h"
#include "message.h"
#include "misc.h"
#include "mon-place.h"
#include "terrain.h"
#include "mgen_data.h"
#include "state.h"
#include "travel.h"
#include "view.h"
#include "viewchar.h"
#include "viewgeom.h"

#include <cstdarg>
#include <sstream>
#include <iomanip>
#include <algorithm>

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#include <stack>

#ifdef UNIX
 #ifndef USE_TILE
 #include "libunix.h"
 #endif
#endif

#include "branch.h"
#include "delay.h"
#include "externs.h"
#include "options.h"
#include "items.h"
#include "macro.h"
#include "misc.h"
#include "mon-stuff.h"
#include "mon-util.h"
#include "notes.h"
#include "output.h"
#include "player.h"
#include "religion.h"
#include "tutorial.h"
#include "view.h"

stack_iterator::stack_iterator(const coord_def& pos, bool accesible)
{
    cur_link = accesible ? you.visible_igrd(pos) : igrd(pos);
    if ( cur_link != NON_ITEM )
        next_link = mitm[cur_link].link;
    else
        next_link = NON_ITEM;
}

stack_iterator::stack_iterator(int start_link)
{
    cur_link = start_link;
    if ( cur_link != NON_ITEM )
        next_link = mitm[cur_link].link;
    else
        next_link = NON_ITEM;
}

stack_iterator::operator bool() const
{
    return ( cur_link != NON_ITEM );
}

item_def& stack_iterator::operator*() const
{
    ASSERT( cur_link != NON_ITEM );
    return mitm[cur_link];
}

item_def* stack_iterator::operator->() const
{
    ASSERT( cur_link != NON_ITEM );
    return &mitm[cur_link];
}

int stack_iterator::link() const
{
    return cur_link;
}

const stack_iterator& stack_iterator::operator ++ ()
{
    cur_link = next_link;
    if ( cur_link != NON_ITEM )
        next_link = mitm[cur_link].link;
    return *this;
}

stack_iterator stack_iterator::operator++(int dummy)
{
    const stack_iterator copy = *this;
    ++(*this);
    return copy;
}

// Crude, but functional.
std::string make_time_string(time_t abs_time, bool terse)
{
    const int days  = abs_time / 86400;
    const int hours = (abs_time % 86400) / 3600;
    const int mins  = (abs_time % 3600) / 60;
    const int secs  = abs_time % 60;

    std::ostringstream buff;
    buff << std::setfill('0');

    if (days > 0)
    {
        if (terse)
            buff << days << ", ";
        else
            buff << days << (days > 1 ? " days" : "day");
    }

    buff << std::setw(2) << hours << ':'
         << std::setw(2) << mins << ':'
         << std::setw(2) << secs;
    return buff.str();
}

std::string make_file_time(time_t when)
{
    if (tm *loc = TIME_FN(&when))
    {
        return make_stringf("%04d%02d%02d-%02d%02d%02d",
                 loc->tm_year + 1900,
                 loc->tm_mon + 1,
                 loc->tm_mday,
                 loc->tm_hour,
                 loc->tm_min,
                 loc->tm_sec);
    }
    return ("");
}

void set_redraw_status(unsigned long flags)
{
    you.redraw_status_flags |= flags;
}

static bool _tag_follower_at(const coord_def &pos)
{
    if (!in_bounds(pos) || pos == you.pos())
        return (false);

    monsters *fmenv = monster_at(pos);
    if (fmenv == NULL)
        return (false);

    if (fmenv->type == MONS_PLAYER_GHOST
        || !fmenv->alive()
        || fmenv->incapacitated()
        || !mons_can_use_stairs(fmenv)
        || mons_is_stationary(fmenv))
    {
        return (false);
    }

    if (!monster_habitable_grid(fmenv, DNGN_FLOOR))
        return (false);

    if (fmenv->speed_increment < 50)
        return (false);

    // Only friendly monsters, or those actively seeking the
    // player, will follow up/down stairs.
    if (!fmenv->friendly()
        && (!mons_is_seeking(fmenv) || fmenv->foe != MHITYOU))
    {
        return (false);
    }

    // Monsters that are not directly adjacent are subject to more
    // stringent checks.
    if ((pos - you.pos()).abs() > 2)
    {
        if (!fmenv->friendly())
            return (false);

        // Undead will follow Yredelemnul worshippers, and orcs will
        // follow Beogh worshippers.
        if ((you.religion != GOD_YREDELEMNUL && you.religion != GOD_BEOGH)
            || !is_follower(fmenv))
        {
            return (false);
        }
    }

    // Monster is chasing player through stairs.
    fmenv->flags |= MF_TAKING_STAIRS;

    // Clear patrolling/travel markers.
    fmenv->patrol_point.reset();
    fmenv->travel_path.clear();
    fmenv->travel_target = MTRAV_NONE;

    dprf("%s is marked for following.",
         fmenv->name(DESC_CAP_THE, true).c_str() );

    return (true);
}

static int follower_tag_radius2()
{
    // If only friendlies are adjacent, we set a max radius of 6, otherwise
    // only adjacent friendlies may follow.
    for (adjacent_iterator ai(you.pos()); ai; ++ai)
    {
        if (const monsters *mon = monster_at(*ai))
            if (!mon->friendly())
                return (2);
    }

    return (6 * 6);
}

void tag_followers()
{
    const int radius2 = follower_tag_radius2();
    int n_followers = 18;

    std::vector<coord_def> places[2];
    int place_set = 0;

    places[place_set].push_back(you.pos());
    memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
    while (!places[place_set].empty())
    {
        for (int i = 0, size = places[place_set].size(); i < size; ++i)
        {
            const coord_def &p = places[place_set][i];

            coord_def fp;
            for (fp.x = p.x - 1; fp.x <= p.x + 1; ++fp.x)
                for (fp.y = p.y - 1; fp.y <= p.y + 1; ++fp.y)
                {
                    if (fp == p || (fp - you.pos()).abs() > radius2
                        || !in_bounds(fp) || travel_point_distance[fp.x][fp.y])
                    {
                        continue;
                    }
                    travel_point_distance[fp.x][fp.y] = 1;
                    if (_tag_follower_at(fp))
                    {
                        // If we've run out of our follower allowance, bail.
                        if (--n_followers <= 0)
                            return;
                        places[!place_set].push_back(fp);
                    }
                }
        }
        places[place_set].clear();
        place_set = !place_set;
    }
}

void untag_followers()
{
    for (int m = 0; m < MAX_MONSTERS; ++m)
        menv[m].flags &= (~MF_TAKING_STAIRS);
}

unsigned char get_ch()
{
    mouse_control mc(MOUSE_MODE_MORE);
    unsigned char gotched = getch();

    if (gotched == 0)
        gotched = getch();

    return gotched;
}

void cio_init()
{
    crawl_state.io_inited = true;

#if defined(UNIX) && !defined(USE_TILE)
    unixcurses_startup();
#endif

#if defined(TARGET_OS_WINDOWS) && !defined(USE_TILE)
    init_libw32c();
#endif

#ifdef TARGET_OS_DOS
    init_libdos();
#endif

    set_cursor_enabled(false);

    crawl_view.init_geometry();

#ifdef USE_TILE
    tiles.resize();
#endif

    if (Options.char_set == CSET_UNICODE && !crawl_state.unicode_ok)
    {
        crawl_state.add_startup_error(
            "Unicode glyphs are not available, falling back to ASCII.");
        Options.char_set = CSET_ASCII;
    }
}

void cio_cleanup()
{
    if (!crawl_state.io_inited)
        return;

#if defined(USE_TILE)
    tiles.shutdown();
#elif defined(UNIX)
    unixcurses_shutdown();
#endif

#if defined(TARGET_OS_WINDOWS) && !defined(USE_TILE)
    deinit_libw32c();
#endif

    msg::deinitialise_mpr_streams();
    clear_globals_on_exit();
    crawl_state.io_inited = false;
}

// Clear some globally defined variables.
void clear_globals_on_exit()
{
    clear_rays_on_exit();
    clear_zap_info_on_exit();
}

// Used by do_crash_dump() to tell if the crash happened during exit() hooks.
// Not a part of crawl_state, since that's a global C++ instance which is
// free'd by exit() hooks when exit() is called, and we don't want to reference
// free'd memory.
bool CrawlIsExiting = false;

void end(int exit_code, bool print_error, const char *format, ...)
{
    std::string error = print_error? strerror(errno) : "";

    cio_cleanup();
    databaseSystemShutdown();
    if (format)
    {
        va_list arg;
        va_start(arg, format);
        char buffer[1024];
        vsnprintf(buffer, sizeof buffer, format, arg);
        va_end(arg);

        if (error.empty())
            error = std::string(buffer);
        else
            error = std::string(buffer) + ": " + error;
    }

    if (!error.empty())
    {
        if (error[error.length() - 1] != '\n')
            error += "\n";
        fprintf(stderr, "%s", error.c_str());
        error.clear();
    }

#if (defined(TARGET_OS_WINDOWS) && !defined(USE_TILE)) || \
     defined(TARGET_OS_DOS) || \
     defined(DGL_PAUSE_AFTER_ERROR)
    if (exit_code && !crawl_state.arena
        && !crawl_state.seen_hups && !crawl_state.test)
    {
        fprintf(stderr, "Hit Enter to continue...\n");
        getchar();
    }
#endif

    CrawlIsExiting = true;
    exit(exit_code);
}

void redraw_screen(void)
{
    if (!crawl_state.need_save)
    {
        // If the game hasn't started, don't do much.
        clrscr();
        return;
    }

    draw_border();

    you.redraw_hit_points   = true;
    you.redraw_magic_points = true;
    you.redraw_strength     = true;
    you.redraw_intelligence = true;
    you.redraw_dexterity    = true;
    you.redraw_armour_class = true;
    you.redraw_evasion      = true;
    you.redraw_experience   = true;
    you.wield_change        = true;
    you.redraw_quiver       = true;

    set_redraw_status(
        REDRAW_LINE_1_MASK | REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK );

    print_stats();

    if (Options.delay_message_clear)
        mesclr(true);

    bool note_status = notes_are_active();
    activate_notes(false);
    new_level();
#ifdef DGL_SIMPLE_MESSAGING
    update_message_status();
#endif
    update_turn_count();
    activate_notes(note_status);

    viewwindow(false);
}

// STEPDOWN FUNCTION to replace conditional chains in spells2.cc 12jan2000 {dlb}
// it is a bit more extensible and optimises the logical structure, as well
// usage: cast_summon_swarm() cast_haunt() cast_summon_scorpions()
//        cast_summon_horrible_things()
// ex(1): stepdown_value (foo, 2, 2, 6, 8) replaces the following block:
//

/*
   if (foo > 2)
     foo = (foo - 2) / 2 + 2;
   if (foo > 4)
     foo = (foo - 4) / 2 + 4;
   if (foo > 6)
     foo = (foo - 6) / 2 + 6;
   if (foo > 8)
     foo = 8;
 */

//
// ex(2): bar = stepdown_value(bar, 2, 2, 6, -1) replaces the following block:
//

/*
   if (bar > 2)
     bar = (bar - 2) / 2 + 2;
   if (bar > 4)
     bar = (bar - 4) / 2 + 4;
   if (bar > 6)
     bar = (bar - 6) / 2 + 6;
 */

// I hope this permits easier/more experimentation with value stepdowns
// in the code.  It really needs to be rewritten to accept arbitrary
// (unevenly spaced) steppings.
int stepdown_value(int base_value, int stepping, int first_step,
                   int last_step, int ceiling_value)
{
    int return_value = base_value;

    // values up to the first "step" returned unchanged:
    if (return_value <= first_step)
        return return_value;

    for (int this_step = first_step; this_step <= last_step;
         this_step += stepping)
    {
        if (return_value > this_step)
            return_value = ((return_value - this_step) / 2) + this_step;
        else
            break;              // exit loop iff value fully "stepped down"
    }

    // "no final ceiling" == -1
    if (ceiling_value != -1 && return_value > ceiling_value)
        return ceiling_value;   // highest value to return is "ceiling"
    else
        return return_value;    // otherwise, value returned "as is"

}

int skill_bump( int skill )
{
    return ((you.skills[skill] < 3) ? you.skills[skill] * 2
                                    : you.skills[skill] + 3);
}

// This gives (default div = 20, shift = 3):
// - shift/div% @ stat_level = 0; (default 3/20 = 15%, or 20% at stat 1)
// - even (100%) @ stat_level = div - shift; (default 17)
// - 1/div% per stat_level (default 1/20 = 5%)
int stat_mult( int stat_level, int value, int div, int shift )
{
    return (((stat_level + shift) * value) / ((div > 1) ? div : 1));
}

// As above but inverted (ie 5x penalty at stat 1)
int stat_div( int stat_level, int value, int mult, int shift )
{
    int div = stat_level + shift;

    if (div < 1)
        div = 1;

    return ((mult * value) / div);
}

int div_round_up(int num, int den)
{
    return (num / den + (num % den != 0));
}

// Simple little function to quickly modify all three stats
// at once - does check for '0' modifiers to prevent needless
// adding .. could use checking for sums less than zero, I guess.
// Used in conjunction with newgame::species_stat_init() and
// newgame::job_stat_init() routines 24jan2000. {dlb}
void modify_all_stats(int STmod, int IQmod, int DXmod)
{
    if (STmod)
    {
        you.strength     += STmod;
        you.max_strength += STmod;
        you.redraw_strength = true;
    }

    if (IQmod)
    {
        you.intel     += IQmod;
        you.max_intel += IQmod;
        you.redraw_intelligence = true;
    }

    if (DXmod)
    {
        you.dex     += DXmod;
        you.max_dex += DXmod;
        you.redraw_dexterity = true;
    }
}

void canned_msg(canned_message_type which_message)
{
    switch (which_message)
    {
    case MSG_SOMETHING_APPEARS:
        mprf("Something appears %s!",
             (you.species == SP_NAGA || player_mutation_level(MUT_HOOVES))
                 ? "before you" : "at your feet");
        break;
    case MSG_NOTHING_HAPPENS:
        mpr("Nothing appears to happen.");
        break;
    case MSG_YOU_RESIST:
        mpr("You resist.");
        learned_something_new(TUT_YOU_RESIST);
        break;
    case MSG_YOU_PARTIALLY_RESIST:
        mpr("You partially resist.");
        break;
    case MSG_TOO_BERSERK:
        mpr("You are too berserk!");
        crawl_state.cancel_cmd_repeat();
        break;
    case MSG_PRESENT_FORM:
        mpr("You can't do that in your present form.");
        crawl_state.cancel_cmd_repeat();
        break;
    case MSG_NOTHING_CARRIED:
        mpr("You aren't carrying anything.");
        crawl_state.cancel_cmd_repeat();
        break;
    case MSG_CANNOT_DO_YET:
        mpr("You can't do that yet.");
        crawl_state.cancel_cmd_repeat();
        break;
    case MSG_OK:
        mpr("Okay, then.", MSGCH_PROMPT);
        crawl_state.cancel_cmd_repeat();
        break;
    case MSG_UNTHINKING_ACT:
        mpr("Why would you want to do that?");
        crawl_state.cancel_cmd_repeat();
        break;
    case MSG_SPELL_FIZZLES:
        mpr("The spell fizzles.");
        break;
    case MSG_HUH:
        mpr("Huh?", MSGCH_EXAMINE_FILTER);
        crawl_state.cancel_cmd_repeat();
        break;
    case MSG_EMPTY_HANDED:
        mpr("You are now empty-handed.");
        break;
    }
}

// Like yesno, but requires a full typed answer.
// Unlike yesno, prompt should have no trailing space.
// Returns true if the user typed "yes", false if something else or cancel.
bool yes_or_no( const char* fmt, ... )
{
    char buf[200];
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof buf, fmt, args);
    va_end(args);
    buf[sizeof(buf)-1] = 0;

    mprf(MSGCH_PROMPT, "%s? (Confirm with \"yes\".) ", buf);

    if (cancelable_get_line(buf, sizeof buf))
        return (false);
    if (strcasecmp(buf, "yes") != 0)
        return (false);

    return (true);
}

// jmf: general helper (should be used all over in code)
//      -- idea borrowed from Nethack
bool yesno( const char *str, bool safe, int safeanswer, bool clear_after,
            bool interrupt_delays, bool noprompt,
            const explicit_keymap *map )
{
    if (interrupt_delays && !crawl_state.is_repeating_cmd())
        interrupt_activity( AI_FORCE_INTERRUPT );

    std::string prompt = make_stringf("%s ", str ? str : "Buggy prompt?");

    while (true)
    {
        if (!noprompt)
            mpr(prompt.c_str(), MSGCH_PROMPT);

        int tmp = getchm(KMC_CONFIRM);

#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES)
        // Prevent infinite loop if Curses HUP signal handling happens;
        // if there is no safe answer, then just save-and-exit immediately,
        // since there's no way to know if it would be better to return
        // true or false.
        if (crawl_state.seen_hups && !safeanswer)
            sighup_save_and_exit();
#endif

        if (map && map->find(tmp) != map->end())
            tmp = map->find(tmp)->second;

        if (safeanswer
            && (tmp == ' ' || tmp == ESCAPE || tmp == CONTROL('G')
                || tmp == '\r' || tmp == '\n' || crawl_state.seen_hups))
        {
            tmp = safeanswer;
        }

        if (Options.easy_confirm == CONFIRM_ALL_EASY
            || tmp == safeanswer
            || Options.easy_confirm == CONFIRM_SAFE_EASY && safe)
        {
            tmp = toupper( tmp );
        }

        if (clear_after)
            mesclr();

        if (tmp == 'N')
            return (false);
        else if (tmp == 'Y')
            return (true);
        else if (!noprompt)
            mpr("[Y]es or [N]o only, please.");
    }
}

static std::string _list_alternative_yes(char yes1, char yes2,
                                         bool lowered = false,
                                         bool brackets = false)
{
    std::string help = "";
    bool print_yes = false;
    if (yes1 != 'Y')
    {
        if (lowered)
            help += tolower(yes1);
        else
            help += yes1;
        print_yes = true;
    }

    if (yes2 != 'Y' && yes2 != yes1)
    {
        if (print_yes)
            help += "/";

        if (lowered)
            help += tolower(yes2);
        else
            help += yes2;
        print_yes = true;
    }

    if (print_yes)
    {
        if (brackets)
            help = " (" + help + ")";
        else
            help = "/" + help;
    }

    return help;
}

static std::string _list_allowed_keys(char yes1, char yes2,
                                      bool lowered = false,
                                      bool allow_all = false)
{
    std::string result = " [";
                result += (lowered ? "y" : "Y");
                result += _list_alternative_yes(yes1, yes2, lowered);
                if (allow_all)
                    result += (lowered? "/a" : "/A");
                result += (lowered ? "/n/q" : "/N/Q");
                result += "]";

    return (result);
}

// Like yesno(), but returns 0 for no, 1 for yes, and -1 for quit.
// alt_yes and alt_yes2 allow up to two synonyms for 'Y'.
// FIXME: This function is shaping up to be a monster. Help!
int yesnoquit( const char* str, bool safe, int safeanswer, bool allow_all,
               bool clear_after, char alt_yes, char alt_yes2 )
{
    if (!crawl_state.is_repeating_cmd())
        interrupt_activity( AI_FORCE_INTERRUPT );

    std::string prompt =
        make_stringf("%s%s ", str ? str : "Buggy prompt?",
                     _list_allowed_keys(alt_yes, alt_yes2,
                                        safe, allow_all).c_str());
    while (true)
    {
        mpr(prompt.c_str(), MSGCH_PROMPT);

        int tmp = getchm(KMC_CONFIRM);

        if (tmp == CK_ESCAPE || tmp == CONTROL('G') || tmp == 'q' || tmp == 'Q'
            || crawl_state.seen_hups)
        {
            return -1;
        }

        if ((tmp == ' ' || tmp == '\r' || tmp == '\n') && safeanswer)
            tmp = safeanswer;

        if (Options.easy_confirm == CONFIRM_ALL_EASY
            || tmp == safeanswer
            || safe && Options.easy_confirm == CONFIRM_SAFE_EASY)
        {
            tmp = toupper( tmp );
        }

        if (clear_after)
            mesclr();

        if (tmp == 'N')
            return 0;
        else if (tmp == 'Y' || tmp == alt_yes || tmp == alt_yes2)
            return 1;
        else if (allow_all)
        {
            if (tmp == 'A')
                return 2;
            else
                mprf("Choose [Y]es%s, [N]o, [Q]uit, or [A]ll!",
                     _list_alternative_yes(alt_yes, alt_yes2, false, true).c_str());
        }
        else
        {
            mprf("[Y]es%s, [N]o or [Q]uit only, please.",
                 _list_alternative_yes(alt_yes, alt_yes2, false, true).c_str());
        }
    }
}

bool player_can_hear(const coord_def& p)
{
    return (!silenced(p) && !silenced(you.pos()));
}

char index_to_letter(int the_index)
{
    return (the_index + ((the_index < 26) ? 'a' : ('A' - 26)));
}

int letter_to_index(int the_letter)
{
    if (the_letter >= 'a' && the_letter <= 'z')
        // returns range [0-25] {dlb}
        the_letter -= 'a';
    else if (the_letter >= 'A' && the_letter <= 'Z')
        // returns range [26-51] {dlb}
        the_letter -= ('A' - 26);

    return (the_letter);
}

// Returns 0 if the point is not near stairs.
// Returns 1 if the point is near unoccupied stairs.
// Returns 2 if the point is near player-occupied stairs.
int near_stairs(const coord_def &p, int max_dist,
                dungeon_char_type &stair_type, branch_type &branch)
{
    for (radius_iterator ri(p, max_dist, true, false); ri; ++ri)
    {
        const dungeon_feature_type feat = grd(*ri);
        if (feat_is_stair(feat))
        {
            // Shouldn't happen for escape hatches.
            if (feat_is_escape_hatch(feat))
                continue;

            stair_type = get_feature_dchar(feat);

            // Is it a branch stair?
            for (int i = 0; i < NUM_BRANCHES; ++i)
            {
                if (branches[i].entry_stairs == feat)
                {
                    branch = branches[i].id;
                    break;
                }
                else if (branches[i].exit_stairs == feat)
                {
                    branch = branches[i].parent_branch;
                    break;
                }
            }
            return (*ri == you.pos()) ? 2 : 1;
        }
    }

    return (false);
}

bool is_trap_square(dungeon_feature_type grid)
{
    return (grid >= DNGN_TRAP_MECHANICAL && grid <= DNGN_UNDISCOVERED_TRAP);
}

// Does the equivalent of KILL_RESET on all monsters in LOS. Should only be
// applied to new games.
void zap_los_monsters(bool items_also)
{
    // Not using player LOS since clouds might temporarily
    // block monsters.
    los_def los(you.pos(), opc_fullyopaque);
    los.update();

    for (radius_iterator ri(&los); ri; ++ri)
    {
        if (items_also)
        {
            int item = igrd(*ri);

            if (item != NON_ITEM && mitm[item].is_valid() )
                destroy_item(item);
        }

        // If we ever allow starting with a friendly monster,
        // we'll have to check here.
        monsters *mon = monster_at(*ri);
        if (mon == NULL || mons_class_flag(mon->type, M_NO_EXP_GAIN))
            continue;

        dprf("Dismissing %s",
             mon->name(DESC_PLAIN, true).c_str() );

        // Do a hard reset so the monster's items will be discarded.
        mon->flags |= MF_HARD_RESET;
        // Do a silent, wizard-mode monster_die() just to be extra sure the
        // player sees nothing.
        monster_die(mon, KILL_DISMISSED, NON_MONSTER, true, true);
    }
}

int integer_sqrt(int value)
{
    if (value <= 0)
        return (value);

    int very_old_retval = -1;
    int old_retval = 0;
    int retval = 1;

    while (very_old_retval != old_retval
        && very_old_retval != retval
        && retval != old_retval)
    {
        very_old_retval = old_retval;
        old_retval = retval;
        retval = (value / old_retval + old_retval) / 2;
    }

    return (retval);
}

int random_rod_subtype()
{
    return STAFF_FIRST_ROD + random2(NUM_STAVES - STAFF_FIRST_ROD);
}

maybe_bool frombool(bool b)
{
    return (b ? B_TRUE : B_FALSE);
}

bool tobool(maybe_bool mb)
{
    ASSERT (mb != B_MAYBE);
    return (mb == B_TRUE);
}

bool tobool(maybe_bool mb, bool def)
{
    switch (mb)
    {
    case B_TRUE:
        return (true);
    case B_FALSE:
        return (false);
    case B_MAYBE:
    default:
        return (def);
    }
}