summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/place.cc
blob: 03fffbd3705180bb50094f857bcde6559e2091d4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
 *  File:       place.cc
 *  Summary:    Place related functions.
 *  Written by: Linley Henzell
 */

#include "AppHdr.h"

#include "externs.h"

#include "branch.h"
#include "place.h"
#include "player.h"
#include "travel.h"

// Do not attempt to use level_id if level_type != LEVEL_DUNGEON
std::string short_place_name(level_id id)
{
    return id.describe();
}

int place_branch(unsigned short place)
{
    const unsigned branch = (unsigned) ((place >> 8) & 0xFF);
    const int lev = place & 0xFF;
    return lev == 0xFF? -1 : (int) branch;
}

int place_depth(unsigned short place)
{
    const int lev = place & 0xFF;
    return lev == 0xFF? -1 : lev;
}

int place_type(unsigned short place)
{
    const unsigned type = (unsigned) ((place >> 8) & 0xFF);
    const int lev = place & 0xFF;
    return lev == 0xFF? (int) type : (int) LEVEL_DUNGEON;
}

unsigned short get_packed_place( branch_type branch, int subdepth,
                                 level_area_type level_type )
{
    unsigned short place = (unsigned short)
        ( (static_cast<int>(branch) << 8) | (subdepth & 0xFF) );

    if (level_type != LEVEL_DUNGEON)
        place = (unsigned short) ( (static_cast<int>(level_type) << 8) | 0xFF );

    return place;
}

unsigned short get_packed_place()
{
    return get_packed_place(you.where_are_you,
                            subdungeon_depth(you.where_are_you, you.your_level),
                            you.level_type);
}

bool single_level_branch( branch_type branch )
{
    return (branch >= 0 && branch < NUM_BRANCHES
            && branches[branch].depth == 1);
}

std::string place_name( unsigned short place, bool long_name,
                        bool include_number )
{

    unsigned char branch = (unsigned char) ((place >> 8) & 0xFF);
    int lev = place & 0xFF;

    std::string result;
    if (lev == 0xFF)
    {
        switch (branch)
        {
        case LEVEL_ABYSS:
            return ( long_name ? "The Abyss" : "Abyss" );
        case LEVEL_PANDEMONIUM:
            return ( long_name ? "Pandemonium" : "Pan" );
        case LEVEL_LABYRINTH:
            return ( long_name ? "a Labyrinth" : "Lab" );
        case LEVEL_PORTAL_VAULT:
            // XXX: This was originally in misc.cc:new_level. It really makes
            // no sense for it to be there, as there are instances where portal
            // vaults can use origin elsewhere (death messages, etc), and Note
            // ::describe calls this anyway. (due)
            if (branch == you.level_type
                && !you.level_type_origin.empty())
            {
                std::string desc;

                size_t space = you.level_type_origin.find(" ");
                if (space == std::string::npos)
                    desc += you.level_type_origin;
                else
                    desc += you.level_type_origin.substr(space + 1);

                return long_name ? desc : upcase_first(you.level_type_name_abbrev);
            }
            else
            {
                return long_name ? "a Portal Chamber" : "Port";
            }
        default:
            return ( long_name ? "Buggy Badlands" : "Bug" );
        }
    }

    result = (long_name ?
              branches[branch].longname : branches[branch].abbrevname);

    if (include_number && branches[branch].depth != 1)
    {
        if (long_name)
        {
            // decapitalise 'the'
            if ( result.find("The") == 0 )
                result[0] = 't';
            result = make_stringf("Level %d of %s",
                      lev, result.c_str());
        }
        else if (lev)
            result = make_stringf("%s:%d", result.c_str(), lev);
        else
            result = make_stringf("%s:$", result.c_str());
    }
    return result;
}

// Takes a packed 'place' and returns a compact stringified place name.
// XXX: This is done in several other places; a unified function to
//      describe places would be nice.
std::string short_place_name(unsigned short place)
{
    return place_name( place, false, true );
}

// Prepositional form of branch level name.  For example, "in the
// Abyss" or "on level 3 of the Main Dungeon".
std::string prep_branch_level_name(unsigned short packed_place)
{
    std::string place = place_name( packed_place, true, true );
    if (place.length() && place != "Pandemonium")
        place[0] = tolower(place[0]);
    return (place.find("level") == 0 ? "on " + place
                                     : "in " + place);
}

// Use current branch and depth
std::string prep_branch_level_name()
{
    return prep_branch_level_name( get_packed_place() );
}

int absdungeon_depth(branch_type branch, int subdepth)
{
    if (branch >= BRANCH_VESTIBULE_OF_HELL && branch <= BRANCH_LAST_HELL)
        return subdepth + 27 - (branch == BRANCH_VESTIBULE_OF_HELL);
    else
    {
        --subdepth;
        while (branch != BRANCH_MAIN_DUNGEON)
        {
            subdepth += branches[branch].startdepth;
            branch = branches[branch].parent_branch;
        }
    }
    return subdepth;
}

int subdungeon_depth(branch_type branch, int depth)
{
    return depth - absdungeon_depth(branch, 0);
}

int player_branch_depth()
{
    return subdungeon_depth(you.where_are_you, you.your_level);
}

// Returns true if exits from this type of level involve going upstairs.
bool level_type_exits_up(level_area_type type)
{
    return (type == LEVEL_LABYRINTH || type == LEVEL_PORTAL_VAULT);
}

bool level_type_exits_down(level_area_type type)
{
    return (type == LEVEL_PANDEMONIUM || type == LEVEL_ABYSS);
}

bool level_type_allows_followers(level_area_type type)
{
    return (type == LEVEL_DUNGEON || type == LEVEL_PANDEMONIUM);
}

bool level_type_is_stash_trackable(level_area_type type)
{
    return (type != LEVEL_ABYSS && type != LEVEL_LABYRINTH);
}

std::vector<level_id> all_dungeon_ids()
{
    std::vector<level_id> out;
    for (int i = 0; i < NUM_BRANCHES; i++)
    {
        const Branch &branch = branches[i];

        for (int depth = 1; depth <= branch.depth; depth++)
            out.push_back(level_id(branch.id, depth));
    }
    return (out);
}