1 #include "AppHdr.h"
2 
3 #include "branch.h"
4 #include "branch-data.h"
5 
6 #include "item-name.h"
7 #include "player.h"
8 #include "stringutil.h"
9 #include "tag-version.h"
10 #include "travel.h"
11 
12 FixedVector<level_id, NUM_BRANCHES> brentry;
13 FixedVector<int, NUM_BRANCHES> brdepth;
14 FixedVector<int, NUM_BRANCHES> branch_bribe;
15 branch_type root_branch;
16 
17 /// A save-compat ordering for branches.
18 static const branch_type logical_branch_order[] = {
19     BRANCH_DUNGEON,
20     BRANCH_TEMPLE,
21     BRANCH_LAIR,
22     BRANCH_SWAMP,
23     BRANCH_SHOALS,
24     BRANCH_SNAKE,
25     BRANCH_SPIDER,
26     BRANCH_SLIME,
27     BRANCH_ORC,
28     BRANCH_ELF,
29 #if TAG_MAJOR_VERSION == 34
30     BRANCH_DWARF,
31 #endif
32     BRANCH_VAULTS,
33 #if TAG_MAJOR_VERSION == 34
34     BRANCH_BLADE,
35     BRANCH_FOREST,
36 #endif
37     BRANCH_CRYPT,
38     BRANCH_TOMB,
39     BRANCH_DEPTHS,
40     BRANCH_VESTIBULE,
41     BRANCH_DIS,
42     BRANCH_GEHENNA,
43     BRANCH_COCYTUS,
44     BRANCH_TARTARUS,
45     BRANCH_ZOT,
46     BRANCH_ABYSS,
47     BRANCH_PANDEMONIUM,
48     BRANCH_ZIGGURAT,
49 #if TAG_MAJOR_VERSION == 34
50     BRANCH_LABYRINTH,
51 #endif
52     BRANCH_BAZAAR,
53     BRANCH_TROVE,
54     BRANCH_SEWER,
55     BRANCH_OSSUARY,
56     BRANCH_BAILEY,
57     BRANCH_ICE_CAVE,
58     BRANCH_VOLCANO,
59     BRANCH_WIZLAB,
60     BRANCH_DESOLATION,
61     BRANCH_GAUNTLET,
62 };
63 COMPILE_CHECK(ARRAYSZ(logical_branch_order) == NUM_BRANCHES);
64 
65 /// Branches ordered loosely by challenge level.
66 static const branch_type danger_branch_order[] = {
67     BRANCH_TEMPLE,
68     BRANCH_BAZAAR,
69     BRANCH_TROVE,
70     BRANCH_DUNGEON,
71     BRANCH_SEWER,
72     BRANCH_OSSUARY,
73     BRANCH_BAILEY,
74     BRANCH_LAIR,
75     BRANCH_GAUNTLET,
76     BRANCH_ICE_CAVE,
77     BRANCH_VOLCANO,
78     BRANCH_ORC,
79     BRANCH_SWAMP,
80     BRANCH_SHOALS,
81     BRANCH_SNAKE,
82     BRANCH_SPIDER,
83     BRANCH_VAULTS,
84     BRANCH_ELF,
85     BRANCH_CRYPT,
86     BRANCH_DESOLATION,
87     BRANCH_ABYSS,
88     BRANCH_WIZLAB,
89     BRANCH_SLIME,
90     BRANCH_DEPTHS,
91     BRANCH_VESTIBULE,
92     BRANCH_ZOT,
93     BRANCH_PANDEMONIUM,
94     BRANCH_TARTARUS,
95     BRANCH_GEHENNA,
96     BRANCH_COCYTUS,
97     BRANCH_DIS,
98     BRANCH_TOMB,
99     BRANCH_ZIGGURAT,
100 #if TAG_MAJOR_VERSION == 34
101     BRANCH_DWARF,
102     BRANCH_BLADE,
103     BRANCH_FOREST,
104     BRANCH_LABYRINTH,
105 #endif
106 };
107 COMPILE_CHECK(ARRAYSZ(danger_branch_order) == NUM_BRANCHES);
108 
109 static const int number_of_branch_swap_pairs = 2;
110 
111 static const branch_type swap_branches[number_of_branch_swap_pairs][2] =
112 {
113     {BRANCH_SHOALS, BRANCH_SWAMP},
114     {BRANCH_SPIDER, BRANCH_SNAKE}
115 };
116 
branch_iterator(branch_iterator_type type)117 branch_iterator::branch_iterator(branch_iterator_type type) :
118     iter_type(type), i(0)
119 {
120 }
121 
branch_order() const122 const branch_type* branch_iterator::branch_order() const
123 {
124     if (iter_type == branch_iterator_type::danger)
125         return danger_branch_order;
126     return logical_branch_order;
127 }
128 
operator bool() const129 branch_iterator::operator bool() const
130 {
131     return i < NUM_BRANCHES;
132 }
133 
operator *() const134 const Branch* branch_iterator::operator*() const
135 {
136 
137     if (i < NUM_BRANCHES)
138         return &branches[branch_order()[i]];
139     else
140         return nullptr;
141 }
142 
operator ->() const143 const Branch* branch_iterator::operator->() const
144 {
145     return **this;
146 }
147 
operator ++()148 branch_iterator& branch_iterator::operator++()
149 {
150     i++;
151     return *this;
152 }
153 
operator ++(int)154 branch_iterator branch_iterator::operator++(int)
155 {
156     branch_iterator copy = *this;
157     ++(*this);
158     return copy;
159 }
160 
random_choose_disabled_branches()161 vector<branch_type> random_choose_disabled_branches()
162 {
163     // You will get one of Shoals/Swamp and one of Spider/Snake.
164     // This way you get one "water" branch and one "poison" branch.
165     vector<branch_type> disabled_branch;
166 
167     for (int i=0; i < number_of_branch_swap_pairs; i++)
168         disabled_branch.push_back(swap_branches[i][random_choose(0,1)]);
169 
170     return disabled_branch;
171 }
172 
your_branch()173 const Branch& your_branch()
174 {
175     return branches[you.where_are_you];
176 }
177 
at_branch_bottom()178 bool at_branch_bottom()
179 {
180     return brdepth[you.where_are_you] == you.depth;
181 }
182 
current_level_parent()183 level_id current_level_parent()
184 {
185     // Never called from X[], we don't have to support levels you're not on.
186     if (!you.level_stack.empty())
187         return you.level_stack.back().id;
188 
189     return find_up_level(level_id::current());
190 }
191 
is_hell_subbranch(branch_type branch)192 bool is_hell_subbranch(branch_type branch)
193 {
194     return branch >= BRANCH_FIRST_HELL
195            && branch <= BRANCH_LAST_HELL
196            && branch != BRANCH_VESTIBULE; // XX not needed?
197 }
198 
is_hell_branch(branch_type branch)199 bool is_hell_branch(branch_type branch)
200 {
201     return is_hell_subbranch(branch) || branch == BRANCH_VESTIBULE;
202 }
203 
is_random_subbranch(branch_type branch)204 bool is_random_subbranch(branch_type branch)
205 {
206     for (int i=0; i < number_of_branch_swap_pairs; i++)
207     {
208         for (int j=0; j < 2; j++)
209         {
210             if (branch == swap_branches[i][j])
211                 return true;
212         }
213     }
214 
215     return false;
216 }
217 
is_connected_branch(const Branch * branch)218 bool is_connected_branch(const Branch *branch)
219 {
220     return !testbits(branch->branch_flags, brflag::no_x_level_travel);
221 }
222 
is_connected_branch(branch_type branch)223 bool is_connected_branch(branch_type branch)
224 {
225     ASSERT_RANGE(branch, 0, NUM_BRANCHES);
226     return is_connected_branch(&branches[branch]);
227 }
228 
is_connected_branch(level_id place)229 bool is_connected_branch(level_id place)
230 {
231     return is_connected_branch(place.branch);
232 }
233 
branch_by_abbrevname(const string & branch,branch_type err)234 branch_type branch_by_abbrevname(const string &branch, branch_type err)
235 {
236     for (branch_iterator it; it; ++it)
237         if (it->abbrevname && it->abbrevname == branch)
238             return it->id;
239 
240     return err;
241 }
242 
branch_by_shortname(const string & branch)243 branch_type branch_by_shortname(const string &branch)
244 {
245     for (branch_iterator it; it; ++it)
246         if (it->shortname && it->shortname == branch)
247             return it->id;
248 
249     return NUM_BRANCHES;
250 }
251 
ambient_noise(branch_type branch)252 int ambient_noise(branch_type branch)
253 {
254     switch (branches[branch].ambient_noise)
255     {
256     case branch_noise::normal:
257         return 0;
258     case branch_noise::quiet:
259         return -BRANCH_NOISE_AMOUNT;
260     case branch_noise::loud:
261         return BRANCH_NOISE_AMOUNT;
262     default:
263         die("Invalid noise level!");
264     };
265 }
266 
get_branch_at(const coord_def & pos)267 branch_type get_branch_at(const coord_def& pos)
268 {
269     return level_id::current().get_next_level_id(pos).branch;
270 }
271 
branch_is_unfinished(branch_type branch)272 bool branch_is_unfinished(branch_type branch)
273 {
274 #if TAG_MAJOR_VERSION == 34
275     if (branch == BRANCH_DWARF
276         || branch == BRANCH_FOREST
277         || branch == BRANCH_BLADE
278         || branch == BRANCH_LABYRINTH)
279     {
280         return true;
281     }
282 #else
283     UNUSED(branch);
284 #endif
285     return false;
286 }
287 
parent_branch(branch_type branch)288 branch_type parent_branch(branch_type branch)
289 {
290     if (brentry[branch].is_valid())
291         return brentry[branch].branch;
292     // If it's not in the game, use the default parent.
293     return branches[branch].parent_branch;
294 }
295 
runes_for_branch(branch_type branch)296 int runes_for_branch(branch_type branch)
297 {
298     switch (branch)
299     {
300     case BRANCH_VAULTS:   return VAULTS_ENTRY_RUNES;
301     case BRANCH_ZIGGURAT: return ZIG_ENTRY_RUNES;
302     case BRANCH_ZOT:      return ZOT_ENTRY_RUNES;
303     default:              return 0;
304     }
305 }
306 
307 /**
308  * Describe the ambient noise level in this branch.
309  *
310  * @param branch The branch in question.
311  * @returns      A string describing how noisy or quiet the branch is.
312  */
branch_noise_desc(branch_type br)313 string branch_noise_desc(branch_type br)
314 {
315     string desc;
316     const int noise = ambient_noise(br);
317     if (noise != 0)
318     {
319         desc = "This branch is ";
320         if (noise > 0)
321         {
322             desc += make_stringf("very noisy, and so sound travels much less "
323                                  "far.");
324         }
325         else
326         {
327             desc += make_stringf("unnaturally silent, and so sound travels "
328                                  "much further.");
329 
330         }
331     }
332 
333     return desc;
334 }
335 
336 /**
337  * Write a description of the rune(s), if any, this branch contains.
338  *
339  * @param br             the branch in question
340  * @param remaining_only whether to only mention a rune if the player
341  *                       hasn't picked it up yet.
342  * @returns a string mentioning all applicable runes.
343  */
branch_rune_desc(branch_type br,bool remaining_only)344 string branch_rune_desc(branch_type br, bool remaining_only)
345 {
346     string desc;
347     vector<string> rune_names;
348 
349     for (rune_type rune : branches[br].runes)
350         if (!(remaining_only && you.runes[rune]))
351             rune_names.push_back(rune_type_name(rune));
352 
353     if (!rune_names.empty())
354     {
355         desc = make_stringf("This branch contains the %s rune%s of Zot.",
356                             comma_separated_line(begin(rune_names),
357                                                  end(rune_names)).c_str(),
358                             rune_names.size() > 1 ? "s" : "");
359     }
360 
361     return desc;
362 }
363 
rune_location(rune_type rune)364 branch_type rune_location(rune_type rune)
365 {
366     for (const auto& br : branches)
367         if (find(br.runes.begin(), br.runes.end(), rune) != br.runes.end())
368             return br.id;
369 
370     return NUM_BRANCHES;
371 }
372