1 /**
2 * @file
3 * @brief Initializing non-player-related parts of a new game.
4 **/
5 /* TODO: 'you' shouldn't occur here.
6 * Some of these might fit better elsewhere.
7 */
8
9 #include "AppHdr.h"
10
11 #include "mpr.h"
12 #include "ng-init.h"
13
14 #include "branch.h"
15 #include "describe.h"
16 #include "dungeon.h"
17 #include "end.h"
18 #include "item-name.h"
19 #include "libutil.h"
20 #include "maps.h"
21 #include "ng-init-branches.h"
22 #include "random.h"
23 #include "religion.h"
24 #include "state.h"
25 #include "stringutil.h"
26 #include "tag-version.h"
27 #include "unicode.h"
28
29 #ifdef DEBUG_DIAGNOSTICS
30 #define DEBUG_TEMPLES
31 #endif
32
_random_potion_description()33 static uint8_t _random_potion_description()
34 {
35 int desc;
36
37 desc = random2(PDQ_NQUALS * PDC_NCOLOURS);
38
39 if (coinflip())
40 desc %= PDC_NCOLOURS;
41
42 // nature and colour correspond to primary and secondary in
43 // item-name.cc.
44
45 #if TAG_MAJOR_VERSION == 34
46 if (PCOLOUR(desc) == PDC_CLEAR) // only water can be clear, re-roll
47 return _random_potion_description();
48 #endif
49
50 return desc;
51 }
52
53 // Determine starting depths of branches.
initialise_branch_depths()54 void initialise_branch_depths()
55 {
56 root_branch = BRANCH_DUNGEON;
57
58 // XXX: Should this go elsewhere?
59 branch_bribe.init(0);
60
61 for (branch_iterator it; it; ++it)
62 brentry[it->id].clear();
63
64 if (crawl_state.game_is_sprint())
65 {
66 brdepth.init(-1);
67 brdepth[BRANCH_DUNGEON] = 1;
68 return;
69 }
70
71 for (int branch = 0; branch < NUM_BRANCHES; ++branch)
72 {
73 const Branch *b = &branches[branch];
74 ASSERT(b->id == branch);
75 }
76
77 initialise_brentry();
78 }
79
_use_overflow_temple(vector<god_type> temple_gods)80 static void _use_overflow_temple(vector<god_type> temple_gods)
81 {
82 CrawlVector &overflow_temples
83 = you.props[OVERFLOW_TEMPLES_KEY].get_vector();
84
85 const unsigned int level = random_range(MIN_OVERFLOW_LEVEL,
86 MAX_OVERFLOW_LEVEL);
87
88 // List of overflow temples on this level.
89 CrawlVector &level_temples = overflow_temples[level - 1].get_vector();
90
91 CrawlHashTable temple;
92
93 CrawlVector &gods = temple[TEMPLE_GODS_KEY].new_vector(SV_BYTE);
94
95 for (unsigned int i = 0; i < temple_gods.size(); i++)
96 gods.push_back((char) temple_gods[i]);
97
98 level_temples.push_back(temple);
99 }
100
101 // Determine which altars go into the Ecumenical Temple, which go into
102 // overflow temples, and on what level the overflow temples are.
initialise_temples()103 void initialise_temples()
104 {
105 //////////////////////////////////////////
106 // First determine main temple map to use.
107 level_id ecumenical(BRANCH_TEMPLE, 1);
108
109 map_def *main_temple = nullptr;
110 for (int i = 0; i < 10; i++)
111 {
112 int altar_count = 0;
113
114 main_temple
115 = const_cast<map_def*>(random_map_for_place(ecumenical, false));
116
117 if (main_temple == nullptr)
118 end(1, false, "No temples?!");
119
120 if (main_temple->has_tag("temple_variable"))
121 {
122 vector<int> sizes;
123 for (const auto &tag : main_temple->get_tags())
124 {
125 if (starts_with(tag, "temple_altars_"))
126 {
127 sizes.push_back(
128 atoi(tag_without_prefix(tag,
129 "temple_altars_").c_str()));
130 }
131 }
132 if (sizes.empty())
133 {
134 mprf(MSGCH_ERROR,
135 "Temple %s set as variable but has no sizes.",
136 main_temple->name.c_str());
137 main_temple = nullptr;
138 continue;
139 }
140 altar_count =
141 you.props[TEMPLE_SIZE_KEY].get_int() =
142 sizes[random2(sizes.size())];
143 }
144
145 dgn_map_parameters mp(make_stringf("temple_altars_%d", altar_count));
146
147 // Without all this find_glyph() returns 0.
148 string err;
149 main_temple->load();
150 main_temple->reinit();
151 err = main_temple->run_lua(true);
152
153 if (!err.empty())
154 {
155 mprf(MSGCH_ERROR, "Temple %s: %s", main_temple->name.c_str(),
156 err.c_str());
157 main_temple = nullptr;
158 you.props.erase(TEMPLE_SIZE_KEY);
159 continue;
160 }
161
162 main_temple->fixup();
163 err = main_temple->resolve();
164
165 if (!err.empty())
166 {
167 mprf(MSGCH_ERROR, "Temple %s: %s", main_temple->name.c_str(),
168 err.c_str());
169 main_temple = nullptr;
170 you.props.erase(TEMPLE_SIZE_KEY);
171 continue;
172 }
173 break;
174 }
175
176 if (main_temple == nullptr)
177 end(1, false, "No valid temples.");
178
179 you.props[TEMPLE_MAP_KEY] = main_temple->name;
180
181 const vector<coord_def> altar_coords
182 = main_temple->find_glyph('B');
183 const unsigned int main_temple_size = altar_coords.size();
184
185 if (main_temple_size == 0)
186 {
187 end(1, false, "Main temple '%s' has no altars",
188 main_temple->name.c_str());
189 }
190
191 #ifdef DEBUG_TEMPLES
192 mprf(MSGCH_DIAGNOSTICS, "Chose main temple %s, size %u",
193 main_temple->name.c_str(), main_temple_size);
194 #endif
195
196 ///////////////////////////////////
197 // Now set up the overflow temples.
198
199 vector<god_type> god_list = temple_god_list();
200 shuffle_array(god_list);
201
202 vector<god_type> overflow_gods;
203
204 while (god_list.size() > main_temple_size)
205 {
206 overflow_gods.push_back(god_list.back());
207 god_list.pop_back();
208 }
209
210 #ifdef DEBUG_TEMPLES
211 mprf(MSGCH_DIAGNOSTICS, "%u overflow altars", (unsigned int)overflow_gods.size());
212 #endif
213
214 you.props.erase(TEMPLE_GODS_KEY); // shouldn't be set normally, but
215 you.props.erase(OVERFLOW_TEMPLES_KEY); // may be in tests
216 CrawlVector &temple_gods
217 = you.props[TEMPLE_GODS_KEY].new_vector(SV_BYTE);
218
219 for (unsigned int i = 0; i < god_list.size(); i++)
220 temple_gods.push_back((char) god_list[i]);
221
222 CrawlVector &overflow_temples
223 = you.props[OVERFLOW_TEMPLES_KEY].new_vector(SV_VEC);
224 overflow_temples.resize(MAX_OVERFLOW_LEVEL);
225
226 // Count god overflow temple weights.
227 int overflow_weights[NUM_GODS + 1];
228 overflow_weights[0] = 0;
229
230 for (unsigned int i = 1; i < NUM_GODS; i++)
231 {
232 string mapname = make_stringf("temple_overflow_generic_%d", i);
233 mapref_vector maps = find_maps_for_tag(mapname);
234 if (!maps.empty())
235 {
236 int chance = 0;
237 for (auto map : maps)
238 {
239 // XXX: this should handle level depth better
240 chance += map->weight(level_id(BRANCH_DUNGEON,
241 MAX_OVERFLOW_LEVEL));
242 }
243 overflow_weights[i] = chance;
244 }
245 else
246 overflow_weights[i] = 0;
247 }
248
249 // Check for temple_overflow vaults that specify certain gods.
250 mapref_vector maps;
251 // the >1 range is based on previous code; 1-altar temple_overflow maps
252 // are placed by the next part, though their weight is not used here. There
253 // are currently no such vaults with more than 3 altars, but there's not
254 // much cost to checking a few higher.
255 for (int num = 2; num <= 5; num++)
256 {
257 mapref_vector num_maps = find_maps_for_tag(
258 make_stringf("temple_overflow_%d", num));
259 maps.insert(maps.end(), num_maps.begin(), num_maps.end());
260 }
261
262 for (const map_def *map : maps)
263 {
264 if (overflow_gods.size() < 2)
265 break;
266 unsigned int num = 0;
267 vector<god_type> this_temple_gods;
268 for (const auto &tag : map->get_tags())
269 {
270 if (!starts_with(tag, "temple_overflow_"))
271 continue;
272 string temple_tag = tag_without_prefix(tag, "temple_overflow_");
273 if (temple_tag.empty())
274 {
275 mprf(MSGCH_ERROR, "Malformed temple tag '%s' in map %s",
276 tag.c_str(), map->name.c_str());
277 continue;
278 }
279 int test_num;
280 if (parse_int(temple_tag.c_str(), test_num) && test_num > 0)
281 num = test_num;
282 else
283 {
284 replace(temple_tag.begin(), temple_tag.end(), '_', ' ');
285 god_type this_god = str_to_god(temple_tag);
286 if (this_god == GOD_NO_GOD)
287 {
288 mprf(MSGCH_ERROR, "Malformed temple tag '%s' in map %s",
289 tag.c_str(), map->name.c_str());
290 continue;
291 }
292 this_temple_gods.push_back(this_god);
293 }
294 if (num == 0)
295 {
296 if (this_temple_gods.size() > 0)
297 {
298 mprf(MSGCH_ERROR,
299 "Map %s has temple_overflow_god tags but no count tag",
300 map->name.c_str());
301 }
302 continue;
303 }
304 }
305 // there is one vault that currently triggers this, where it allows
306 // one of two specified gods on a particular altar. This code won't
307 // handle (or error) on that case right now.
308 if (num != this_temple_gods.size())
309 continue;
310
311 // does this temple place only gods that we need to place?
312 bool ok = true;
313 for (auto god : this_temple_gods)
314 if (count(overflow_gods.begin(), overflow_gods.end(), god) == 0)
315 {
316 ok = false;
317 break;
318 }
319 if (!ok)
320 continue;
321 // finally: this overflow vault will place a subset of our current
322 // overflow list. Do we actually place it?
323 // TODO: The weight calculation here is kind of odd, though based on
324 // what it is directly replacing. It should sum all compatible
325 // maps first. But, the end result of this choice isn't a map anyways...
326 // More generally, I wonder if this list should be shuffled before this
327 // step, so that it's not prioritizing smaller vaults?
328 int chance = map->weight(level_id(BRANCH_DUNGEON,
329 MAX_OVERFLOW_LEVEL));
330 if (x_chance_in_y(chance, overflow_weights[num] + chance))
331 {
332 vector<god_type> new_overflow_gods;
333 for (auto god : overflow_gods)
334 if (count(this_temple_gods.begin(), this_temple_gods.end(), god) == 0)
335 new_overflow_gods.push_back(god);
336 _use_overflow_temple(this_temple_gods);
337
338 overflow_gods = new_overflow_gods;
339 }
340 }
341
342 // NOTE: The overflow temples don't have to contain only one
343 // altar; they can contain any number of altars, so long as there's
344 // at least one vault definition with the tag "overflow_temple_num"
345 // (where "num" is the number of altars).
346 for (unsigned int i = 0, size = overflow_gods.size(); i < size; i++)
347 {
348 unsigned int remaining_size = size - i;
349 // At least one god.
350 vector<god_type> this_temple_gods;
351 this_temple_gods.push_back(overflow_gods[i]);
352
353 // Maybe place a larger overflow temple.
354 if (remaining_size > 1 && one_chance_in(remaining_size + 1))
355 {
356 vector<pair<unsigned int, int> > num_weights;
357 unsigned int num_gods = 1;
358
359 // Randomly choose from the sizes which have maps.
360 for (unsigned int j = 2; j <= remaining_size; j++)
361 if (overflow_weights[j] > 0)
362 num_weights.emplace_back(j, overflow_weights[j]);
363
364 if (!num_weights.empty())
365 num_gods = *(random_choose_weighted(num_weights));
366
367 // Add any extra gods (the first was added already).
368 for (; num_gods > 1; i++, num_gods--)
369 this_temple_gods.push_back(overflow_gods[i + 1]);
370 }
371
372 _use_overflow_temple(this_temple_gods);
373 }
374 }
375
initialise_item_descriptions()376 void initialise_item_descriptions()
377 {
378 // Must remember to check for already existing colours/combinations.
379 you.item_description.init(255);
380
381 // The order here must match that of IDESC in describe.h
382 const int max_item_number[6] = { NUM_WANDS,
383 NUM_POTIONS,
384 NUM_SCROLLS,
385 NUM_JEWELLERY,
386 NUM_SCROLLS,
387 NUM_STAVES };
388
389 for (int i = 0; i < NUM_IDESC; i++)
390 {
391 // Only loop until NUM_WANDS etc.
392 for (int j = 0; j < max_item_number[i]; j++)
393 {
394 // Don't override predefines
395 if (you.item_description[i][j] != 255)
396 continue;
397
398 // Pick a new description until it's good.
399 while (true)
400 {
401 switch (i)
402 {
403 case IDESC_WANDS: // wands
404 you.item_description[i][j] = random2(NDSC_WAND_PRI
405 * NDSC_WAND_SEC);
406 if (coinflip())
407 you.item_description[i][j] %= NDSC_WAND_PRI;
408 break;
409
410 case IDESC_POTIONS: // potions
411 you.item_description[i][j] = _random_potion_description();
412 break;
413
414
415 #if TAG_MAJOR_VERSION == 34
416 case IDESC_SCROLLS_II: // unused but validated
417 #endif
418 case IDESC_SCROLLS: // scrolls: random seed for the name
419 {
420 // this is very weird and probably a linleyism.
421 const int seed_1 = random2(151); // why 151?
422 const int seed_2 = random2(151);
423 const int seed_3 = OBJ_SCROLLS; // yes, really
424 you.item_description[i][j] = seed_1
425 | (seed_2 << 8)
426 | (seed_3 << 16);
427 break;
428 }
429
430 case IDESC_RINGS: // rings and amulets
431 you.item_description[i][j] = random2(NDSC_JEWEL_PRI
432 * NDSC_JEWEL_SEC);
433 if (coinflip())
434 you.item_description[i][j] %= NDSC_JEWEL_PRI;
435 break;
436
437 case IDESC_STAVES: // staves
438 you.item_description[i][j] = random2(NDSC_STAVE_PRI
439 * NDSC_STAVE_SEC);
440 break;
441 }
442
443 bool is_ok = true;
444
445 // Test whether we've used this description before.
446 // Don't have p < j because some are preassigned.
447 for (int p = 0; p < max_item_number[i]; p++)
448 {
449 if (p == j)
450 continue;
451
452 if (you.item_description[i][p] == you.item_description[i][j])
453 {
454 is_ok = false;
455 break;
456 }
457 }
458 if (is_ok)
459 break;
460 }
461 }
462 }
463 }
464
fix_up_jiyva_name()465 void fix_up_jiyva_name()
466 {
467 you.jiyva_second_name = make_name(rng::get_uint32(), MNAME_JIYVA);
468 ASSERT(you.jiyva_second_name[0] == 'J');
469 }
470