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