3 * Summary: Functions used when starting a new game.
4 * Written by: Linley Henzell
36 #include "tilereg-crt.h"
39 static void _choose_gamemode_map(newgame_def
* ng
, newgame_def
* ng_choice
,
40 const newgame_def
& defaults
);
41 static bool _choose_weapon(newgame_def
* ng
, newgame_def
* ng_choice
,
42 const newgame_def
& defaults
);
43 static bool _choose_book(newgame_def
* ng
, newgame_def
* ng_choice
,
44 const newgame_def
& defaults
);
45 static bool _choose_god(newgame_def
* ng
, newgame_def
* ng_choice
,
46 const newgame_def
& defaults
);
47 static bool _choose_wand(newgame_def
* ng
, newgame_def
* ng_choice
,
48 const newgame_def
& defaults
);
50 ////////////////////////////////////////////////////////////////////////
51 // Remember player's startup options
54 newgame_def::newgame_def()
55 : name(), type(GAME_TYPE_NORMAL
),
56 species(SP_UNKNOWN
), job(JOB_UNKNOWN
),
57 weapon(WPN_UNKNOWN
), book(SBT_NONE
),
58 religion(GOD_NO_GOD
), wand(SWT_NO_SELECTION
),
63 void newgame_def::clear_character()
69 religion
= GOD_NO_GOD
;
70 wand
= SWT_NO_SELECTION
;
83 M_DEFAULT_CHOICE
= -9,
86 static bool _is_random_species(species_type sp
)
88 return (sp
== SP_RANDOM
|| sp
== SP_VIABLE
);
91 static bool _is_random_job(job_type job
)
93 return (job
== JOB_RANDOM
|| job
== JOB_VIABLE
);
96 static bool _is_random_choice(const newgame_def
& choice
)
98 return (_is_random_species(choice
.species
)
99 && _is_random_job(choice
.job
));
102 static bool _is_random_viable_choice(const newgame_def
& choice
)
104 return (_is_random_choice(choice
) &&
105 (choice
.job
== JOB_VIABLE
|| choice
.species
== SP_VIABLE
));
108 static bool _char_defined(const newgame_def
& ng
)
110 return (ng
.species
!= SP_UNKNOWN
&& ng
.job
!= JOB_UNKNOWN
);
113 static std::string
_char_description(const newgame_def
& ng
)
115 if (_is_random_viable_choice(ng
))
116 return "Viable character";
117 else if (_is_random_choice(ng
))
118 return "Random character";
119 else if (_is_random_job(ng
.job
))
121 const std::string j
= (ng
.job
== JOB_RANDOM
? "Random " : "Viable ");
122 return (j
+ species_name(ng
.species
));
124 else if (_is_random_species(ng
.species
))
126 const std::string s
= (ng
.species
== SP_RANDOM
? "Random "
128 return (s
+ get_job_name(ng
.job
));
131 return (species_name(ng
.species
) + " " + get_job_name(ng
.job
));
134 static std::string
_welcome(const newgame_def
* ng
)
137 if (ng
->species
!= SP_UNKNOWN
)
138 text
= species_name(ng
->species
);
139 if (ng
->job
!= JOB_UNKNOWN
)
143 text
+= get_job_name(ng
->job
);
145 if (!ng
->name
.empty())
148 text
= " the " + text
;
149 text
= ng
->name
+ text
;
151 else if (!text
.empty())
152 text
= "unnamed " + text
;
155 text
= "Welcome" + text
+ ".";
159 static void _print_character_info(const newgame_def
* ng
)
163 cprintf("%s\n", _welcome(ng
).c_str());
166 // Determines if a species is valid. If 'display' is true, returns if
167 // the species is displayable in the new game screen - this is
168 // primarily used to suppress the display of the draconian variants.
169 static bool _is_species_valid_choice(species_type species
)
171 if (species
< 0 || species
> NUM_SPECIES
)
174 if (species
>= SP_ELF
) // These are all invalid.
177 // Non-base draconians cannot be selected either.
178 if (species
>= SP_RED_DRACONIAN
&& species
< SP_BASE_DRACONIAN
)
185 static bool _species_is_undead(const species_type speci
)
187 return (speci
== SP_MUMMY
|| speci
== SP_GHOUL
|| speci
== SP_VAMPIRE
);
191 undead_state_type
get_undead_state(const species_type sp
)
198 return US_HUNGRY_DEAD
;
200 return US_SEMI_UNDEAD
;
202 ASSERT(!_species_is_undead(sp
));
207 void choose_tutorial_character(newgame_def
* ng_choice
)
209 ng_choice
->species
= SP_HIGH_ELF
;
210 ng_choice
->job
= JOB_FIGHTER
;
211 ng_choice
->weapon
= WPN_MACE
;
214 static void _resolve_species(newgame_def
* ng
, const newgame_def
* ng_choice
)
216 // Don't overwrite existing species.
217 if (ng
->species
!= SP_UNKNOWN
)
220 switch (ng_choice
->species
)
223 ng
->species
= SP_UNKNOWN
;
228 int good_choices
= 0;
229 for (int i
= 0; i
< ng_num_species(); i
++)
231 species_type sp
= get_species(i
);
232 if (is_good_combination(sp
, ng
->job
, true)
233 && one_chance_in(++good_choices
))
241 // intentional fall-through
243 if (ng
->job
== JOB_UNKNOWN
)
245 // any species will do
246 ng
->species
= get_species(random2(ng_num_species()));
250 // Pick a random legal character.
251 int good_choices
= 0;
252 for (int i
= 0; i
< ng_num_species(); i
++)
254 species_type sp
= get_species(i
);
255 if (is_good_combination(sp
, ng
->job
, false)
256 && one_chance_in(++good_choices
))
262 end(1, false, "Failed to find legal species.");
267 ng
->species
= ng_choice
->species
;
272 static void _resolve_job(newgame_def
* ng
, const newgame_def
* ng_choice
)
274 if (ng
->job
!= JOB_UNKNOWN
)
277 switch (ng_choice
->job
)
280 ng
->job
= JOB_UNKNOWN
;
285 int good_choices
= 0;
286 for (int i
= 0; i
< ng_num_jobs(); i
++)
288 job_type job
= get_job(i
);
289 if (is_good_combination(ng
->species
, job
, true)
290 && one_chance_in(++good_choices
))
298 // intentional fall-through
300 if (ng
->species
== SP_UNKNOWN
)
303 ng
->job
= get_job(random2(ng_num_jobs()));
307 // Pick a random legal character.
308 int good_choices
= 0;
309 for (int i
= 0; i
< ng_num_jobs(); i
++)
311 job_type job
= get_job(i
);
312 if (is_good_combination(ng
->species
, job
, false)
313 && one_chance_in(++good_choices
))
319 end(1, false, "Failed to find legal background.");
324 ng
->job
= ng_choice
->job
;
329 static void _resolve_species_job(newgame_def
* ng
, const newgame_def
* ng_choice
)
331 _resolve_species(ng
, ng_choice
);
332 _resolve_job(ng
, ng_choice
);
335 static std::string
_highlight_pattern(const newgame_def
* ng
)
337 if (ng
->species
!= SP_UNKNOWN
)
338 return species_name(ng
->species
) + " ";
340 if (ng
->job
== JOB_UNKNOWN
)
344 for (int i
= 0; i
< ng_num_species(); ++i
)
346 const species_type species
= get_species(i
);
347 if (!_is_species_valid_choice(species
))
350 if (is_good_combination(species
, ng
->job
, true))
351 ret
+= species_name(species
) + " |";
354 ret
.resize(ret
.size() - 1);
358 static void _prompt_species(newgame_def
* ng
, newgame_def
* ng_choice
,
359 const newgame_def
& defaults
);
360 static void _prompt_job(newgame_def
* ng
, newgame_def
* ng_choice
,
361 const newgame_def
& defaults
);
363 static void _choose_species_job(newgame_def
* ng
, newgame_def
* ng_choice
,
364 const newgame_def
& defaults
)
366 _resolve_species_job(ng
, ng_choice
);
368 while (ng_choice
->species
== SP_UNKNOWN
|| ng_choice
->job
== JOB_UNKNOWN
)
370 // Slightly non-obvious behaviour here is due to the fact that
371 // both _prompt_species and _prompt_job can ask for an entirely
372 // random character to be rolled. They will reset relevant fields
373 // in *ng for this purpose.
374 if (ng_choice
->species
== SP_UNKNOWN
)
375 _prompt_species(ng
, ng_choice
, defaults
);
376 _resolve_species_job(ng
, ng_choice
);
377 if (ng_choice
->job
== JOB_UNKNOWN
)
378 _prompt_job(ng
, ng_choice
, defaults
);
379 _resolve_species_job(ng
, ng_choice
);
382 if (!job_allowed(ng
->species
, ng
->job
))
384 // Either an invalid combination was passed in through options,
387 "Incompatible species and background specified in options file.");
391 // For completely random combinations (!, #, or Options.game.fully_random)
392 // reroll characters until the player accepts one of them or quits.
393 static bool _reroll_random(newgame_def
* ng
)
397 std::string specs
= species_name(ng
->species
);
398 if (specs
.length() > 79)
399 specs
= specs
.substr(0, 79);
401 cprintf("You are a%s %s %s.\n",
402 (is_vowel(specs
[0])) ? "n" : "", specs
.c_str(),
403 get_job_name(ng
->job
));
405 cprintf("\nDo you want to play this combination? (ynq) [y]");
407 if (key_is_escape(c
) || tolower(c
) == 'q')
409 return (tolower(c
) == 'n');
412 static void _choose_char(newgame_def
* ng
, newgame_def
* choice
,
413 newgame_def defaults
)
415 const newgame_def ng_reset
= *ng
;
417 if (ng
->type
== GAME_TYPE_TUTORIAL
)
418 choose_tutorial_character(choice
);
419 else if (ng
->type
== GAME_TYPE_HINTS
)
424 _choose_species_job(ng
, choice
, defaults
);
426 if (choice
->fully_random
&& _reroll_random(ng
))
432 if (_choose_weapon(ng
, choice
, defaults
)
433 && _choose_book(ng
, choice
, defaults
)
434 && _choose_god(ng
, choice
, defaults
)
435 && _choose_wand(ng
, choice
, defaults
))
441 // Else choose again, name and type stays same.
448 // Read a choice of game into ng.
449 // Returns false if a game (with name ng->name) should
450 // be restored instead of starting a new character.
451 bool choose_game(newgame_def
* ng
, newgame_def
* choice
,
452 const newgame_def
& defaults
)
456 // XXX: this should be somewhere else.
457 if (!crawl_state
.startup_errors
.empty()
458 && !Options
.suppress_startup_errors
)
460 crawl_state
.show_startup_errors();
464 textcolor(LIGHTGREY
);
466 ng
->name
= choice
->name
;
467 ng
->type
= choice
->type
;
468 ng
->map
= choice
->map
;
470 if (ng
->type
== GAME_TYPE_SPRINT
|| ng
->type
== GAME_TYPE_TUTORIAL
)
471 _choose_gamemode_map(ng
, choice
, defaults
);
473 _choose_char(ng
, choice
, defaults
);
475 // Set these again, since _mark_fully_random may reset *ng.
476 ng
->name
= choice
->name
;
477 ng
->type
= choice
->type
;
480 // New: pick name _after_ character choices.
481 if (choice
->name
.empty())
485 std::string specs
= species_name(ng
->species
);
486 if (specs
.length() > 79)
487 specs
= specs
.substr(0, 79);
489 cprintf("You are a%s %s %s.\n",
490 (is_vowel(specs
[0])) ? "n" : "", specs
.c_str(),
491 get_job_name(ng
->job
));
493 enter_player_name(choice
);
494 ng
->name
= choice
->name
;
496 if (save_exists(choice
->name
))
498 cprintf("\nDo you really want to overwrite your old game? ");
500 if (c
!= 'Y' && c
!= 'y')
506 if (ng
->name
.empty())
507 end(1, false, "No player name specified.");
509 ASSERT(is_good_name(ng
->name
, false, false)
510 && job_allowed(ng
->species
, ng
->job
)
511 && ng
->type
!= NUM_GAME_TYPE
);
513 write_newgame_options_file(*choice
);
518 int start_to_book(int firstbook
, int booktype
)
522 case BOOK_MINOR_MAGIC_I
:
526 return (BOOK_MINOR_MAGIC_I
);
529 return (BOOK_MINOR_MAGIC_II
);
532 return (BOOK_MINOR_MAGIC_III
);
538 case BOOK_CONJURATIONS_I
:
542 return (BOOK_CONJURATIONS_I
);
545 return (BOOK_CONJURATIONS_II
);
556 void make_rod(item_def
&item
, stave_type rod_type
, int ncharges
)
558 item
.base_type
= OBJ_STAVES
;
559 item
.sub_type
= rod_type
;
561 item
.special
= you
.item_description
[IDESC_STAVES
][rod_type
];
564 init_rod_mp(item
, ncharges
);
567 // Set ng_choice to defaults without overwriting name and game type.
568 static void _set_default_choice(newgame_def
* ng
, newgame_def
* ng_choice
,
569 const newgame_def
& defaults
)
571 // Reset *ng so _resolve_species_job will work properly.
572 ng
->clear_character();
574 const std::string name
= ng_choice
->name
;
575 const game_type type
= ng_choice
->type
;
576 *ng_choice
= defaults
;
577 ng_choice
->name
= name
;
578 ng_choice
->type
= type
;
581 static void _mark_fully_random(newgame_def
* ng
, newgame_def
* ng_choice
,
584 // Reset *ng so _resolve_species_job will work properly.
585 ng
->clear_character();
587 ng_choice
->fully_random
= true;
590 ng_choice
->species
= SP_VIABLE
;
591 ng_choice
->job
= JOB_VIABLE
;
595 ng_choice
->species
= SP_RANDOM
;
596 ng_choice
->job
= JOB_RANDOM
;
601 * Helper function for _choose_species
602 * Constructs the menu screen
604 static const int COLUMN_WIDTH
= 25;
605 static const int X_MARGIN
= 4;
606 static const int CHAR_DESC_START_Y
= 17;
607 static const int SPECIAL_KEYS_START_Y
= CHAR_DESC_START_Y
+ 3;
608 static void _construct_species_menu(const newgame_def
* ng
,
609 const newgame_def
& defaults
,
612 ASSERT(menu
!= NULL
);
613 static const int ITEMS_IN_COLUMN
= 8;
614 // Construct the menu, 3 columns
615 TextItem
* tmp
= NULL
;
617 coord_def
min_coord(0,0);
618 coord_def
max_coord(0,0);
620 for (int i
= 0; i
< ng_num_species(); ++i
)
622 const species_type species
= get_species(i
);
623 if (!_is_species_valid_choice(species
))
626 tmp
= new TextItem();
629 if (ng
->job
== JOB_UNKNOWN
630 || job_allowed(species
, ng
->job
) == CC_UNRESTRICTED
)
632 tmp
->set_fg_colour(LIGHTGRAY
);
633 tmp
->set_highlight_colour(GREEN
);
637 tmp
->set_fg_colour(DARKGRAY
);
638 tmp
->set_highlight_colour(YELLOW
);
640 if (ng
->job
!= JOB_UNKNOWN
641 && job_allowed(species
, ng
->job
) == CC_BANNED
)
644 text
+= species_name(species
);
646 tmp
->set_fg_colour(DARKGRAY
);
647 tmp
->set_highlight_colour(RED
);
651 text
= index_to_letter(i
);
653 text
+= species_name(species
);
655 // Fill to column width - 1
656 text
.append(COLUMN_WIDTH
- text
.size() - 1 , ' ');
658 min_coord
.x
= X_MARGIN
+ (i
/ ITEMS_IN_COLUMN
) * COLUMN_WIDTH
;
659 min_coord
.y
= 3 + i
% ITEMS_IN_COLUMN
;
660 max_coord
.x
= min_coord
.x
+ text
.size();
661 max_coord
.y
= min_coord
.y
+ 1;
662 tmp
->set_bounds(min_coord
, max_coord
);
664 tmp
->add_hotkey(index_to_letter(i
));
665 tmp
->set_id(species
);
666 tmp
->set_description_text(getGameStartDescription(species_name(species
)));
667 menu
->attach_item(tmp
);
668 tmp
->set_visible(true);
669 if (defaults
.species
== species
)
671 menu
->set_active_item(tmp
);
675 // Add all the special button entries
676 tmp
= new TextItem();
677 tmp
->set_text("+ - Viable species");
678 min_coord
.x
= X_MARGIN
;
679 min_coord
.y
= SPECIAL_KEYS_START_Y
;
680 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
681 max_coord
.y
= min_coord
.y
+ 1;
682 tmp
->set_bounds(min_coord
, max_coord
);
683 tmp
->set_fg_colour(BROWN
);
684 tmp
->add_hotkey('+');
685 // If the player has a job chosen, use VIABLE, otherwise use RANDOM
686 if (ng
->job
!= JOB_UNKNOWN
)
688 tmp
->set_id(M_VIABLE
);
692 tmp
->set_id(M_RANDOM
);
694 tmp
->set_highlight_colour(LIGHTGRAY
);
695 tmp
->set_description_text("Picks a random viable species based on your current job choice");
696 menu
->attach_item(tmp
);
697 tmp
->set_visible(true);
699 tmp
= new TextItem();
700 tmp
->set_text("# - Viable character");
701 min_coord
.x
= X_MARGIN
;
702 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
703 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
704 max_coord
.y
= min_coord
.y
+ 1;
705 tmp
->set_bounds(min_coord
, max_coord
);
706 tmp
->set_fg_colour(BROWN
);
707 tmp
->add_hotkey('#');
708 tmp
->set_id(M_VIABLE_CHAR
);
709 tmp
->set_highlight_colour(LIGHTGRAY
);
710 tmp
->set_description_text("Shuffles through random viable character combinations "
711 "until you accept one");
712 menu
->attach_item(tmp
);
713 tmp
->set_visible(true);
715 tmp
= new TextItem();
716 tmp
->set_text("% - List aptitudes");
717 min_coord
.x
= X_MARGIN
;
718 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
719 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
720 max_coord
.y
= min_coord
.y
+ 1;
721 tmp
->set_bounds(min_coord
, max_coord
);
722 tmp
->set_fg_colour(BROWN
);
723 tmp
->add_hotkey('%');
724 tmp
->set_id(M_APTITUDES
);
725 tmp
->set_description_text("Lists the numerical skill train aptitudes for all races");
726 tmp
->set_highlight_colour(LIGHTGRAY
);
727 menu
->attach_item(tmp
);
728 tmp
->set_visible(true);
730 tmp
= new TextItem();
731 tmp
->set_text("? - Help");
732 min_coord
.x
= X_MARGIN
;
733 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 3;
734 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
735 max_coord
.y
= min_coord
.y
+ 1;
736 tmp
->set_bounds(min_coord
, max_coord
);
737 tmp
->set_fg_colour(BROWN
);
738 tmp
->add_hotkey('?');
740 tmp
->set_highlight_colour(LIGHTGRAY
);
741 tmp
->set_description_text("Opens the help screen");
742 menu
->attach_item(tmp
);
743 tmp
->set_visible(true);
745 tmp
= new TextItem();
746 tmp
->set_text("* - Random species");
747 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
748 min_coord
.y
= SPECIAL_KEYS_START_Y
;
749 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
750 max_coord
.y
= min_coord
.y
+ 1;
751 tmp
->set_bounds(min_coord
, max_coord
);
752 tmp
->set_fg_colour(BROWN
);
753 tmp
->add_hotkey('*');
754 tmp
->set_id(M_RANDOM
);
755 tmp
->set_highlight_colour(LIGHTGRAY
);
756 tmp
->set_description_text("Picks a random species");
757 menu
->attach_item(tmp
);
758 tmp
->set_visible(true);
760 tmp
= new TextItem();
761 tmp
->set_text("! - Random character");
762 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
763 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
764 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
765 max_coord
.y
= min_coord
.y
+ 1;
766 tmp
->set_bounds(min_coord
, max_coord
);
767 tmp
->set_fg_colour(BROWN
);
768 tmp
->add_hotkey('!');
769 tmp
->set_id(M_RANDOM_CHAR
);
770 tmp
->set_highlight_colour(LIGHTGRAY
);
771 tmp
->set_description_text("Shuffles through random character combinations "
772 "until you accept one");
773 menu
->attach_item(tmp
);
774 tmp
->set_visible(true);
776 // Adjust the end marker to align the - because Space text is longer by 4
777 tmp
= new TextItem();
778 if (ng
->job
!= JOB_UNKNOWN
)
780 tmp
->set_text("Space - Change background");
781 tmp
->set_description_text("Lets you change your background choice");
785 tmp
->set_text("Space - Pick background first");
786 tmp
->set_description_text("Lets you pick your background first");
788 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 4;
789 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
790 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
791 max_coord
.y
= min_coord
.y
+ 1;
792 tmp
->set_bounds(min_coord
, max_coord
);
793 tmp
->set_fg_colour(BROWN
);
794 tmp
->add_hotkey(' ');
795 tmp
->set_id(M_ABORT
);
796 tmp
->set_highlight_colour(LIGHTGRAY
);
797 menu
->attach_item(tmp
);
798 tmp
->set_visible(true);
800 if (_char_defined(defaults
))
802 std::string tmp_string
= "Tab - ";
803 tmp_string
+= _char_description(defaults
).c_str();
804 // Adjust the end marker to aling the - because
805 // Tab text is longer by 2
806 tmp
= new TextItem();
807 tmp
->set_text(tmp_string
);
808 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 2;
809 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 3;
810 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
811 max_coord
.y
= min_coord
.y
+ 1;
812 tmp
->set_bounds(min_coord
, max_coord
);
813 tmp
->set_fg_colour(BROWN
);
814 tmp
->add_hotkey('\t');
815 tmp
->set_id(M_DEFAULT_CHOICE
);
816 tmp
->set_highlight_colour(LIGHTGRAY
);
817 tmp
->set_description_text("Play a new game with your previous choice");
818 menu
->attach_item(tmp
);
819 tmp
->set_visible(true);
823 // Prompt the player for a choice of species.
824 // ng should be const, but we need to reset it for _resolve_species_job
825 // to work correctly in view of fully random characters.
826 static void _prompt_species(newgame_def
* ng
, newgame_def
* ng_choice
,
827 const newgame_def
& defaults
)
830 menu
.set_select_type(PrecisionMenu::PRECISION_SINGLESELECT
);
831 MenuFreeform
* freeform
= new MenuFreeform();
832 freeform
->init(coord_def(0,0), coord_def(get_number_of_cols(),
833 get_number_of_lines()), "freeform");
834 menu
.attach_object(freeform
);
835 menu
.set_active_object(freeform
);
841 // TODO: attach these to the menu in a NoSelectTextItem
843 cprintf("%s", _welcome(ng
).c_str());
846 cprintf(" Please select your species.");
848 _construct_species_menu(ng
, defaults
, freeform
);
849 MenuDescriptor
* descriptor
= new MenuDescriptor(&menu
);
850 descriptor
->init(coord_def(X_MARGIN
, CHAR_DESC_START_Y
),
851 coord_def(get_number_of_cols(), CHAR_DESC_START_Y
+ 2),
853 menu
.attach_object(descriptor
);
855 BoxMenuHighlighter
* highlighter
= new BoxMenuHighlighter(&menu
);
856 highlighter
->init(coord_def(0,0), coord_def(0,0), "highlighter");
857 menu
.attach_object(highlighter
);
859 // Did we have a previous species?
860 if (menu
.get_active_item() == NULL
)
862 freeform
->activate_first_item();
866 tiles
.get_crt()->attach_menu(&menu
);
869 freeform
->set_visible(true);
870 descriptor
->set_visible(true);
871 highlighter
->set_visible(true);
873 textcolor(LIGHTGREY
);
874 // Poll input until we have a conclusive escape or pick
881 // First process all the menu entries available
882 if (!menu
.process_key(keyn
))
884 // Process all the other keys that are not assigned to the menu
888 cprintf("\nGoodbye!");
894 ng_choice
->species
= SP_UNKNOWN
;
897 // if we get this far, we did not get a significant selection
898 // from the menu, nor did we get an escape character
899 // continue the while loop from the beginning and poll a new key
903 // We have had a significant input key event
904 // construct the return vector
905 std::vector
<MenuItem
*> selection
= menu
.get_selected_items();
906 if (selection
.size() > 0)
908 // we have a selection!
909 // we only care about the first selection (there should be only one)
910 int selection_key
= selection
.at(0)->get_id();
913 switch (selection_key
)
917 // intentional fall-through
919 _mark_fully_random(ng
, ng_choice
, viable
);
921 case M_DEFAULT_CHOICE
:
922 if (_char_defined(defaults
))
924 _set_default_choice(ng
, ng_choice
, defaults
);
929 // ignore Tab because we don't have previous start options
933 ng
->species
= ng_choice
->species
= SP_UNKNOWN
;
934 ng
->job
= ng_choice
->job
= JOB_UNKNOWN
;
937 // access to the help files
939 return _prompt_species(ng
, ng_choice
, defaults
);
941 list_commands('%', false, _highlight_pattern(ng
));
942 return _prompt_species(ng
, ng_choice
, defaults
);
944 ng_choice
->species
= SP_VIABLE
;
947 ng_choice
->species
= SP_RANDOM
;
950 // we have a species selection
951 species_type species
= static_cast<species_type
> (selection_key
);
952 if (ng
->job
== JOB_UNKNOWN
953 || job_allowed(species
, ng
->job
) != CC_BANNED
)
955 ng_choice
->species
= species
;
968 * Helper for _choose_job
969 * constructs the menu used and highlights the previous job if there is one
971 static void _construct_backgrounds_menu(const newgame_def
* ng
,
972 const newgame_def
& defaults
,
975 static const int ITEMS_IN_COLUMN
= 10;
976 // Construct the menu, 3 columns
977 TextItem
* tmp
= NULL
;
979 coord_def
min_coord(0,0);
980 coord_def
max_coord(0,0);
982 for (int i
= 0; i
< ng_num_jobs(); ++i
)
984 const job_type job
= get_job(i
);
985 tmp
= new TextItem();
988 if (ng
->species
== SP_UNKNOWN
989 || job_allowed(ng
->species
, job
) == CC_UNRESTRICTED
)
991 tmp
->set_fg_colour(LIGHTGRAY
);
992 tmp
->set_highlight_colour(GREEN
);
996 tmp
->set_fg_colour(DARKGRAY
);
997 tmp
->set_highlight_colour(YELLOW
);
999 if (ng
->species
!= SP_UNKNOWN
1000 && job_allowed(ng
->species
, job
) == CC_BANNED
)
1003 text
+= get_job_name(job
);
1005 tmp
->set_fg_colour(DARKGRAY
);
1006 tmp
->set_highlight_colour(RED
);
1010 text
= index_to_letter(i
);
1012 text
+= get_job_name(job
);
1014 // fill the text entry to end of column - 1
1015 text
.append(COLUMN_WIDTH
- text
.size() - 1 , ' ');
1016 tmp
->set_text(text
);
1017 min_coord
.x
= X_MARGIN
+ (i
/ ITEMS_IN_COLUMN
) * COLUMN_WIDTH
;
1018 min_coord
.y
= 3 + i
% ITEMS_IN_COLUMN
;
1019 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1020 max_coord
.y
= min_coord
.y
+ 1;
1021 tmp
->set_bounds(min_coord
, max_coord
);
1023 tmp
->add_hotkey(index_to_letter(i
));
1025 tmp
->set_description_text(getGameStartDescription(get_job_name(job
)));
1027 menu
->attach_item(tmp
);
1028 tmp
->set_visible(true);
1029 if (defaults
.job
== job
)
1031 menu
->set_active_item(tmp
);
1035 // Add all the special button entries
1036 tmp
= new TextItem();
1037 tmp
->set_text("+ - Viable background");
1038 min_coord
.x
= X_MARGIN
;
1039 min_coord
.y
= SPECIAL_KEYS_START_Y
;
1040 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1041 max_coord
.y
= min_coord
.y
+ 1;
1042 tmp
->set_bounds(min_coord
, max_coord
);
1043 tmp
->set_fg_colour(BROWN
);
1044 tmp
->add_hotkey('+');
1045 // If the player has species chosen, use VIABLE, otherwise use RANDOM
1046 if (ng
->species
!= SP_UNKNOWN
)
1048 tmp
->set_id(M_VIABLE
);
1052 tmp
->set_id(M_RANDOM
);
1054 tmp
->set_highlight_colour(LIGHTGRAY
);
1055 tmp
->set_description_text("Picks a random viable background based on your current species choice");
1056 menu
->attach_item(tmp
);
1057 tmp
->set_visible(true);
1059 tmp
= new TextItem();
1060 tmp
->set_text("# - Viable character");
1061 min_coord
.x
= X_MARGIN
;
1062 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
1063 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1064 max_coord
.y
= min_coord
.y
+ 1;
1065 tmp
->set_bounds(min_coord
, max_coord
);
1066 tmp
->set_fg_colour(BROWN
);
1067 tmp
->add_hotkey('#');
1068 tmp
->set_id(M_VIABLE_CHAR
);
1069 tmp
->set_highlight_colour(LIGHTGRAY
);
1070 tmp
->set_description_text("Shuffles through random viable character combinations "
1071 "until you accept one");
1072 menu
->attach_item(tmp
);
1073 tmp
->set_visible(true);
1075 tmp
= new TextItem();
1076 tmp
->set_text("% - List aptitudes");
1077 min_coord
.x
= X_MARGIN
;
1078 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
1079 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1080 max_coord
.y
= min_coord
.y
+ 1;
1081 tmp
->set_bounds(min_coord
, max_coord
);
1082 tmp
->set_fg_colour(BROWN
);
1083 tmp
->add_hotkey('%');
1084 tmp
->set_id(M_APTITUDES
);
1085 tmp
->set_highlight_colour(LIGHTGRAY
);
1086 tmp
->set_description_text("Lists the numerical skill train aptitudes for all races");
1087 menu
->attach_item(tmp
);
1088 tmp
->set_visible(true);
1090 tmp
= new TextItem();
1091 tmp
->set_text("? - Help");
1092 min_coord
.x
= X_MARGIN
;
1093 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 3;
1094 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1095 max_coord
.y
= min_coord
.y
+ 1;
1096 tmp
->set_bounds(min_coord
, max_coord
);
1097 tmp
->set_fg_colour(BROWN
);
1098 tmp
->add_hotkey('?');
1099 tmp
->set_id(M_HELP
);
1100 tmp
->set_highlight_colour(LIGHTGRAY
);
1101 tmp
->set_description_text("Opens the help screen");
1102 menu
->attach_item(tmp
);
1103 tmp
->set_visible(true);
1105 tmp
= new TextItem();
1106 tmp
->set_text("* - Random background");
1107 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
1108 min_coord
.y
= SPECIAL_KEYS_START_Y
;
1109 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1110 max_coord
.y
= min_coord
.y
+ 1;
1111 tmp
->set_bounds(min_coord
, max_coord
);
1112 tmp
->set_fg_colour(BROWN
);
1113 tmp
->add_hotkey('*');
1114 tmp
->set_id(M_RANDOM
);
1115 tmp
->set_highlight_colour(LIGHTGRAY
);
1116 tmp
->set_description_text("Picks a random background");
1117 menu
->attach_item(tmp
);
1118 tmp
->set_visible(true);
1120 tmp
= new TextItem();
1121 tmp
->set_text("! - Random character");
1122 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
1123 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
1124 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1125 max_coord
.y
= min_coord
.y
+ 1;
1126 tmp
->set_bounds(min_coord
, max_coord
);
1127 tmp
->set_fg_colour(BROWN
);
1128 tmp
->add_hotkey('!');
1129 tmp
->set_id(M_RANDOM_CHAR
);
1130 tmp
->set_highlight_colour(LIGHTGRAY
);
1131 tmp
->set_description_text("Shuffles through random character combinations "
1132 "until you accept one");
1133 menu
->attach_item(tmp
);
1134 tmp
->set_visible(true);
1136 // Adjust the end marker to align the - because Space text is longer by 4
1137 tmp
= new TextItem();
1138 if (ng
->species
!= SP_UNKNOWN
)
1140 tmp
->set_text("Space - Change species");
1141 tmp
->set_description_text("Lets you change your species choice");
1145 tmp
->set_text("Space - Pick species first");
1146 tmp
->set_description_text("Lets you pick your species first");
1149 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 4;
1150 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
1151 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1152 max_coord
.y
= min_coord
.y
+ 1;
1153 tmp
->set_bounds(min_coord
, max_coord
);
1154 tmp
->set_fg_colour(BROWN
);
1155 tmp
->add_hotkey(' ');
1156 tmp
->set_id(M_ABORT
);
1157 tmp
->set_highlight_colour(LIGHTGRAY
);
1158 menu
->attach_item(tmp
);
1159 tmp
->set_visible(true);
1161 if (_char_defined(defaults
))
1165 text
+= _char_description(defaults
).c_str();
1166 // Adjust the end marker to aling the - because
1167 // Tab text is longer by 2
1168 tmp
= new TextItem();
1169 tmp
->set_text(text
);
1170 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 2;
1171 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 3;
1172 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1173 max_coord
.y
= min_coord
.y
+ 1;
1174 tmp
->set_bounds(min_coord
, max_coord
);
1175 tmp
->set_fg_colour(BROWN
);
1176 tmp
->add_hotkey('\t');
1177 tmp
->set_id(M_DEFAULT_CHOICE
);
1178 tmp
->set_highlight_colour(LIGHTGRAY
);
1179 tmp
->set_description_text("Play a new game with your previous choice");
1180 menu
->attach_item(tmp
);
1181 tmp
->set_visible(true);
1187 * Saves the choice to ng_choice, doesn't resolve random choices.
1189 * ng should be const, but we need to reset it for _resolve_species_job
1190 * to work correctly in view of fully random characters.
1192 static void _prompt_job(newgame_def
* ng
, newgame_def
* ng_choice
,
1193 const newgame_def
& defaults
)
1196 menu
.set_select_type(PrecisionMenu::PRECISION_SINGLESELECT
);
1197 MenuFreeform
* freeform
= new MenuFreeform();
1198 freeform
->init(coord_def(0,0), coord_def(get_number_of_cols(),
1199 get_number_of_lines()), "freeform");
1200 menu
.attach_object(freeform
);
1201 menu
.set_active_object(freeform
);
1207 // TODO: attach these to the menu in a NoSelectTextItem
1209 cprintf("%s", _welcome(ng
).c_str());
1212 cprintf(" Please select your background.");
1214 _construct_backgrounds_menu(ng
, defaults
, freeform
);
1215 MenuDescriptor
* descriptor
= new MenuDescriptor(&menu
);
1216 descriptor
->init(coord_def(X_MARGIN
, CHAR_DESC_START_Y
),
1217 coord_def(get_number_of_cols(), CHAR_DESC_START_Y
+ 2),
1219 menu
.attach_object(descriptor
);
1221 BoxMenuHighlighter
* highlighter
= new BoxMenuHighlighter(&menu
);
1222 highlighter
->init(coord_def(0,0), coord_def(0,0), "highlighter");
1223 menu
.attach_object(highlighter
);
1225 // Did we have a previous background?
1226 if (menu
.get_active_item() == NULL
)
1228 freeform
->activate_first_item();
1232 tiles
.get_crt()->attach_menu(&menu
);
1235 freeform
->set_visible(true);
1236 descriptor
->set_visible(true);
1237 highlighter
->set_visible(true);
1239 textcolor(LIGHTGREY
);
1241 // Poll input until we have a conclusive escape or pick
1248 // First process all the menu entries available
1249 if (!menu
.process_key(keyn
))
1251 // Process all the other keys that are not assigned to the menu
1255 cprintf("\nGoodbye!");
1261 ng_choice
->job
= JOB_UNKNOWN
;
1264 // if we get this far, we did not get a significant selection
1265 // from the menu, nor did we get an escape character
1266 // continue the while loop from the beginning and poll a new key
1270 // We have had a significant input key event
1271 // construct the return vector
1272 std::vector
<MenuItem
*> selection
= menu
.get_selected_items();
1273 if (selection
.size() > 0)
1275 // we have a selection!
1276 // we only care about the first selection (there should be only one)
1277 int selection_key
= selection
.at(0)->get_id();
1279 bool viable
= false;
1280 switch (selection_key
)
1284 // intentional fall-through
1286 _mark_fully_random(ng
, ng_choice
, viable
);
1288 case M_DEFAULT_CHOICE
:
1289 if (_char_defined(defaults
))
1291 _set_default_choice(ng
, ng_choice
, defaults
);
1296 // ignore default because we don't have previous start options
1300 ng
->species
= ng_choice
->species
= SP_UNKNOWN
;
1301 ng
->job
= ng_choice
->job
= JOB_UNKNOWN
;
1304 // access to the help files
1306 return _prompt_job(ng
, ng_choice
, defaults
);
1308 list_commands('%', false, _highlight_pattern(ng
));
1309 return _prompt_job(ng
, ng_choice
, defaults
);
1311 ng_choice
->job
= JOB_VIABLE
;
1314 ng_choice
->job
= JOB_RANDOM
;
1317 // we have a job selection
1318 job_type job
= static_cast<job_type
> (selection_key
);
1319 if (ng
->species
== SP_UNKNOWN
1320 || job_allowed(ng
->species
, job
) != CC_BANNED
)
1322 ng_choice
->job
= job
;
1334 typedef std::pair
<weapon_type
, char_choice_restriction
> weapon_choice
;
1336 static weapon_type
_fixup_weapon(weapon_type wp
,
1337 const std::vector
<weapon_choice
>& weapons
)
1339 if (wp
== WPN_UNKNOWN
|| wp
== WPN_RANDOM
|| wp
== WPN_VIABLE
)
1341 for (unsigned int i
= 0; i
< weapons
.size(); ++i
)
1342 if (wp
== weapons
[i
].first
)
1344 return (WPN_UNKNOWN
);
1347 static void _construct_weapon_menu(const weapon_type
& defweapon
,
1348 const std::vector
<weapon_choice
>& weapons
,
1351 static const int ITEMS_START_Y
= 5;
1352 TextItem
* tmp
= NULL
;
1354 coord_def
min_coord(0,0);
1355 coord_def
max_coord(0,0);
1357 for (unsigned int i
= 0; i
< weapons
.size(); ++i
)
1359 tmp
= new TextItem();
1362 if (weapons
[i
].second
== CC_UNRESTRICTED
)
1364 tmp
->set_fg_colour(LIGHTGRAY
);
1365 tmp
->set_highlight_colour(GREEN
);
1369 tmp
->set_fg_colour(DARKGRAY
);
1370 tmp
->set_highlight_colour(YELLOW
);
1372 const char letter
= 'a' + i
;
1373 tmp
->add_hotkey(letter
);
1374 tmp
->set_id(weapons
[i
].first
);
1378 text
+= weapons
[i
].first
== WPN_UNARMED
1379 ? "claws" : weapon_base_name(weapons
[i
].first
);
1380 // Fill to column width to give extra padding for the highlight
1381 text
.append(COLUMN_WIDTH
- text
.size() - 1 , ' ');
1382 tmp
->set_text(text
);
1384 min_coord
.x
= X_MARGIN
;
1385 min_coord
.y
= ITEMS_START_Y
+ i
;
1386 max_coord
.x
= min_coord
.x
+ text
.size();
1387 max_coord
.y
= min_coord
.y
+ 1;
1388 tmp
->set_bounds(min_coord
, max_coord
);
1390 menu
->attach_item(tmp
);
1391 tmp
->set_visible(true);
1392 // Is this item our default weapon?
1393 if (weapons
[i
].first
== defweapon
)
1395 menu
->set_active_item(tmp
);
1398 // Add all the special button entries
1399 tmp
= new TextItem();
1400 tmp
->set_text("+ - Viable random choice");
1401 min_coord
.x
= X_MARGIN
;
1402 min_coord
.y
= SPECIAL_KEYS_START_Y
;
1403 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1404 max_coord
.y
= min_coord
.y
+ 1;
1405 tmp
->set_bounds(min_coord
, max_coord
);
1406 tmp
->set_fg_colour(BROWN
);
1407 tmp
->add_hotkey('+');
1408 tmp
->set_id(M_VIABLE
);
1409 tmp
->set_highlight_colour(LIGHTGRAY
);
1410 tmp
->set_description_text("Picks a random viable weapon");
1411 menu
->attach_item(tmp
);
1412 tmp
->set_visible(true);
1414 tmp
= new TextItem();
1415 tmp
->set_text("% - List aptitudes");
1416 min_coord
.x
= X_MARGIN
;
1417 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
1418 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1419 max_coord
.y
= min_coord
.y
+ 1;
1420 tmp
->set_bounds(min_coord
, max_coord
);
1421 tmp
->set_fg_colour(BROWN
);
1422 tmp
->add_hotkey('%');
1423 tmp
->set_id(M_APTITUDES
);
1424 tmp
->set_highlight_colour(LIGHTGRAY
);
1425 tmp
->set_description_text("Lists the numerical skill train aptitudes for all races");
1426 menu
->attach_item(tmp
);
1427 tmp
->set_visible(true);
1429 tmp
= new TextItem();
1430 tmp
->set_text("? - Help");
1431 min_coord
.x
= X_MARGIN
;
1432 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
1433 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1434 max_coord
.y
= min_coord
.y
+ 1;
1435 tmp
->set_bounds(min_coord
, max_coord
);
1436 tmp
->set_fg_colour(BROWN
);
1437 tmp
->add_hotkey('?');
1438 tmp
->set_id(M_HELP
);
1439 tmp
->set_highlight_colour(LIGHTGRAY
);
1440 tmp
->set_description_text("Opens the help screen");
1441 menu
->attach_item(tmp
);
1442 tmp
->set_visible(true);
1444 tmp
= new TextItem();
1445 tmp
->set_text("* - Random weapon");
1446 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
1447 min_coord
.y
= SPECIAL_KEYS_START_Y
;
1448 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1449 max_coord
.y
= min_coord
.y
+ 1;
1450 tmp
->set_bounds(min_coord
, max_coord
);
1451 tmp
->set_fg_colour(BROWN
);
1452 tmp
->add_hotkey('*');
1453 tmp
->set_id(WPN_RANDOM
);
1454 tmp
->set_highlight_colour(LIGHTGRAY
);
1455 tmp
->set_description_text("Picks a random weapon");
1456 menu
->attach_item(tmp
);
1457 tmp
->set_visible(true);
1459 // Adjust the end marker to align the - because Bksp text is longer by 3
1460 tmp
= new TextItem();
1461 tmp
->set_text("Bksp - Return to character menu");
1462 tmp
->set_description_text("Lets you return back to Character choice menu");
1463 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 3;
1464 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
1465 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1466 max_coord
.y
= min_coord
.y
+ 1;
1467 tmp
->set_bounds(min_coord
, max_coord
);
1468 tmp
->set_fg_colour(BROWN
);
1469 tmp
->add_hotkey(CK_BKSP
);
1470 tmp
->set_id(M_ABORT
);
1471 tmp
->set_highlight_colour(LIGHTGRAY
);
1472 menu
->attach_item(tmp
);
1473 tmp
->set_visible(true);
1475 if (defweapon
!= WPN_UNKNOWN
)
1480 text
+= defweapon
== WPN_RANDOM
? "Random" :
1481 defweapon
== WPN_VIABLE
? "Viable" :
1482 defweapon
== WPN_UNARMED
? "claws" :
1483 weapon_base_name(defweapon
);
1485 // Adjust the end marker to aling the - because
1486 // Tab text is longer by 2
1487 tmp
= new TextItem();
1488 tmp
->set_text(text
);
1489 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 2;
1490 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
1491 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1492 max_coord
.y
= min_coord
.y
+ 1;
1493 tmp
->set_bounds(min_coord
, max_coord
);
1494 tmp
->set_fg_colour(BROWN
);
1495 tmp
->add_hotkey('\t');
1496 tmp
->set_id(M_DEFAULT_CHOICE
);
1497 tmp
->set_highlight_colour(LIGHTGRAY
);
1498 tmp
->set_description_text("Select your old weapon");
1499 menu
->attach_item(tmp
);
1500 tmp
->set_visible(true);
1505 * Returns false if user escapes
1507 static bool _prompt_weapon(const newgame_def
* ng
, newgame_def
* ng_choice
,
1508 const newgame_def
& defaults
,
1509 const std::vector
<weapon_choice
>& weapons
)
1512 menu
.set_select_type(PrecisionMenu::PRECISION_SINGLESELECT
);
1513 MenuFreeform
* freeform
= new MenuFreeform();
1514 freeform
->init(coord_def(1,1), coord_def(get_number_of_cols(),
1515 get_number_of_lines()), "freeform");
1516 menu
.attach_object(freeform
);
1517 menu
.set_active_object(freeform
);
1519 weapon_type defweapon
= _fixup_weapon(defaults
.weapon
, weapons
);
1521 _construct_weapon_menu(defweapon
, weapons
, freeform
);
1523 BoxMenuHighlighter
* highlighter
= new BoxMenuHighlighter(&menu
);
1524 highlighter
->init(coord_def(0,0), coord_def(0,0), "highlighter");
1525 menu
.attach_object(highlighter
);
1527 // Did we have a previous weapon?
1528 if (menu
.get_active_item() == NULL
)
1530 freeform
->activate_first_item();
1532 _print_character_info(ng
); // calls clrscr() so needs to be before attach()
1535 tiles
.get_crt()->attach_menu(&menu
);
1538 freeform
->set_visible(true);
1539 highlighter
->set_visible(true);
1542 cprintf("\nYou have a choice of weapons: ");
1548 int keyn
= getch_ck();
1550 // First process menu entries
1551 if (!menu
.process_key(keyn
))
1553 // Process all the keys that are not attached to items
1557 cprintf("\nGoodbye!");
1564 // if we get this far, we did not get a significant selection
1565 // from the menu, nor did we get an escape character
1566 // continue the while loop from the beginning and poll a new key
1570 // We have a significant key input!
1571 // Construct selection vector
1572 std::vector
<MenuItem
*> selection
= menu
.get_selected_items();
1573 // There should only be one selection, otherwise something broke
1574 if (selection
.size() != 1)
1580 // Get the stored id from the selection
1581 int selection_ID
= selection
.at(0)->get_id();
1582 switch (selection_ID
)
1587 list_commands('%', false, _highlight_pattern(ng
));
1588 return _prompt_weapon(ng
, ng_choice
, defaults
, weapons
);
1591 return _prompt_weapon(ng
, ng_choice
, defaults
, weapons
);
1592 case M_DEFAULT_CHOICE
:
1593 if (defweapon
!= WPN_UNKNOWN
)
1595 ng_choice
->weapon
= defweapon
;
1598 // No default weapon defined.
1599 // This case should never happen in those cases but just in case
1602 ng_choice
->weapon
= WPN_VIABLE
;
1605 ng_choice
->weapon
= WPN_RANDOM
;
1608 // We got an item selection
1609 ng_choice
->weapon
= static_cast<weapon_type
> (selection_ID
);
1613 // This should never happen
1617 static std::vector
<weapon_choice
> _get_weapons(const newgame_def
* ng
)
1619 std::vector
<weapon_choice
> weapons
;
1621 weapon_type startwep
[6] = { WPN_UNARMED
, WPN_SHORT_SWORD
, WPN_MACE
,
1622 WPN_HAND_AXE
, WPN_SPEAR
, WPN_FALCHION
};
1623 for (int i
= 0; i
< 6; ++i
)
1626 wp
.first
= startwep
[i
];
1631 if (ng
->job
== JOB_GLADIATOR
|| !species_has_claws(ng
->species
))
1635 // Non-small gladiators and merfolk get tridents.
1636 if (ng
->job
== JOB_GLADIATOR
1637 && species_size(ng
->species
, PSIZE_BODY
) >= SIZE_MEDIUM
1638 || ng
->species
== SP_MERFOLK
)
1640 wp
.first
= WPN_TRIDENT
;
1644 if (ng
->species
== SP_OGRE
)
1645 wp
.first
= WPN_ANKUS
;
1650 wp
.second
= weapon_restriction(wp
.first
, *ng
);
1651 if (wp
.second
!= CC_BANNED
)
1652 weapons
.push_back(wp
);
1657 static void _resolve_weapon(newgame_def
* ng
, newgame_def
* ng_choice
,
1658 const std::vector
<weapon_choice
>& weapons
)
1660 switch (ng_choice
->weapon
)
1663 ng
->weapon
= WPN_UNKNOWN
;
1668 int good_choices
= 0;
1669 for (unsigned int i
= 0; i
< weapons
.size(); i
++)
1671 if (weapons
[i
].second
== CC_UNRESTRICTED
1672 && one_chance_in(++good_choices
))
1674 ng
->weapon
= weapons
[i
].first
;
1680 // intentional fall-through
1682 ng
->weapon
= weapons
[random2(weapons
.size())].first
;
1686 // Check this is a legal choice, in case it came
1687 // through command line options.
1688 ng
->weapon
= _fixup_weapon(ng_choice
->weapon
, weapons
);
1689 if (ng
->weapon
== WPN_UNKNOWN
)
1691 // Either an invalid combination was passed in through options,
1694 "Incompatible weapon specified in options file.");
1700 // Returns false if aborted, else an actual weapon choice
1701 // is written to ng->weapon for the jobs that call
1702 // _update_weapon() later.
1703 static bool _choose_weapon(newgame_def
* ng
, newgame_def
* ng_choice
,
1704 const newgame_def
& defaults
)
1706 // No weapon use at all. The actual item will be removed later.
1707 if (ng
->species
== SP_CAT
)
1714 case JOB_CHAOS_KNIGHT
:
1723 std::vector
<weapon_choice
> weapons
= _get_weapons(ng
);
1725 ASSERT(!weapons
.empty());
1726 if (weapons
.size() == 1)
1728 ng
->weapon
= ng_choice
->weapon
= weapons
[0].first
;
1732 if (ng_choice
->weapon
== WPN_UNKNOWN
)
1733 if (!_prompt_weapon(ng
, ng_choice
, defaults
, weapons
))
1736 _resolve_weapon(ng
, ng_choice
, weapons
);
1740 static startup_book_type
_fixup_book(startup_book_type book
, int numbooks
)
1742 if (book
== SBT_RANDOM
)
1743 return (SBT_RANDOM
);
1744 else if (book
== SBT_VIABLE
)
1745 return (SBT_VIABLE
);
1746 else if (book
>= 0 && book
< numbooks
)
1752 static std::string
_startup_book_name(startup_book_type book
)
1771 static void _construct_book_menu(const newgame_def
& ng
,
1772 const book_type
& firstbook
,
1773 const startup_book_type
& defbook
,
1777 static const int ITEMS_START_Y
= 5;
1778 TextItem
* tmp
= NULL
;
1780 coord_def
min_coord(0,0);
1781 coord_def
max_coord(0,0);
1784 book
.base_type
= OBJ_BOOKS
;
1790 for (int i
= 0; i
< numbooks
; ++i
)
1792 tmp
= new TextItem();
1795 book
.sub_type
= firstbook
+ i
;
1796 startup_book_type sb
= static_cast<startup_book_type
>(i
);
1797 if (book_restriction(sb
, ng
) == CC_UNRESTRICTED
)
1799 tmp
->set_fg_colour(LIGHTGREY
);
1800 tmp
->set_highlight_colour(GREEN
);
1804 tmp
->set_fg_colour(DARKGREY
);
1805 tmp
->set_highlight_colour(YELLOW
);
1807 const char letter
= 'a' + i
;
1810 text
+= book
.name(DESC_PLAIN
, false, true);
1812 //book name is longer than COLUMN_WIDTH
1813 //text.append(COLUMN_WIDTH - text.size() - 1 , ' ');
1814 tmp
->set_text(text
);
1816 tmp
->add_hotkey(letter
);
1819 min_coord
.x
= X_MARGIN
;
1820 min_coord
.y
= ITEMS_START_Y
+ i
;
1821 max_coord
.x
= min_coord
.x
+ text
.size();
1822 max_coord
.y
= min_coord
.y
+ 1;
1823 tmp
->set_bounds(min_coord
, max_coord
);
1825 menu
->attach_item(tmp
);
1826 tmp
->set_visible(true);
1827 // Is this item our default book?
1830 menu
->set_active_item(tmp
);
1835 // Add all the special button entries
1836 tmp
= new TextItem();
1837 tmp
->set_text("+ - Viable random choice");
1838 min_coord
.x
= X_MARGIN
;
1839 min_coord
.y
= SPECIAL_KEYS_START_Y
;
1840 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1841 max_coord
.y
= min_coord
.y
+ 1;
1842 tmp
->set_bounds(min_coord
, max_coord
);
1843 tmp
->set_fg_colour(BROWN
);
1844 tmp
->add_hotkey('+');
1845 tmp
->set_id(M_VIABLE
);
1846 tmp
->set_highlight_colour(LIGHTGRAY
);
1847 tmp
->set_description_text("Picks a random viable book");
1848 menu
->attach_item(tmp
);
1849 tmp
->set_visible(true);
1851 tmp
= new TextItem();
1852 tmp
->set_text("% - List aptitudes");
1853 min_coord
.x
= X_MARGIN
;
1854 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
1855 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1856 max_coord
.y
= min_coord
.y
+ 1;
1857 tmp
->set_bounds(min_coord
, max_coord
);
1858 tmp
->set_fg_colour(BROWN
);
1859 tmp
->add_hotkey('%');
1860 tmp
->set_id(M_APTITUDES
);
1861 tmp
->set_highlight_colour(LIGHTGRAY
);
1862 tmp
->set_description_text("Lists the numerical skill train aptitudes for all races");
1863 menu
->attach_item(tmp
);
1864 tmp
->set_visible(true);
1866 tmp
= new TextItem();
1867 tmp
->set_text("? - Help");
1868 min_coord
.x
= X_MARGIN
;
1869 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
1870 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1871 max_coord
.y
= min_coord
.y
+ 1;
1872 tmp
->set_bounds(min_coord
, max_coord
);
1873 tmp
->set_fg_colour(BROWN
);
1874 tmp
->add_hotkey('?');
1875 tmp
->set_id(M_HELP
);
1876 tmp
->set_highlight_colour(LIGHTGRAY
);
1877 tmp
->set_description_text("Opens the help screen");
1878 menu
->attach_item(tmp
);
1879 tmp
->set_visible(true);
1881 tmp
= new TextItem();
1882 tmp
->set_text("* - Random book");
1883 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
1884 min_coord
.y
= SPECIAL_KEYS_START_Y
;
1885 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1886 max_coord
.y
= min_coord
.y
+ 1;
1887 tmp
->set_bounds(min_coord
, max_coord
);
1888 tmp
->set_fg_colour(BROWN
);
1889 tmp
->add_hotkey('*');
1890 tmp
->set_id(M_RANDOM
);
1891 tmp
->set_highlight_colour(LIGHTGRAY
);
1892 tmp
->set_description_text("Picks a random book");
1893 menu
->attach_item(tmp
);
1894 tmp
->set_visible(true);
1896 // Adjust the end marker to align the - because Bksp text is longer by 3
1897 tmp
= new TextItem();
1898 tmp
->set_text("Bksp - Return to character menu");
1899 tmp
->set_description_text("Lets you return back to Character choice menu");
1900 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 3;
1901 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
1902 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1903 max_coord
.y
= min_coord
.y
+ 1;
1904 tmp
->set_bounds(min_coord
, max_coord
);
1905 tmp
->set_fg_colour(BROWN
);
1906 tmp
->add_hotkey(CK_BKSP
);
1907 tmp
->set_id(M_ABORT
);
1908 tmp
->set_highlight_colour(LIGHTGRAY
);
1909 menu
->attach_item(tmp
);
1910 tmp
->set_visible(true);
1912 // Only add tab entry if we have a previous book choice
1913 if (defbook
!= SBT_NONE
)
1915 tmp
= new TextItem();
1919 text
+= _startup_book_name(defbook
);
1921 // Adjust the end marker to aling the - because
1922 // Tab text is longer by 2
1923 tmp
= new TextItem();
1924 tmp
->set_text(text
);
1925 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 2;
1926 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
1927 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
1928 max_coord
.y
= min_coord
.y
+ 1;
1929 tmp
->set_bounds(min_coord
, max_coord
);
1930 tmp
->set_fg_colour(BROWN
);
1931 tmp
->add_hotkey('\t');
1932 tmp
->set_id(M_DEFAULT_CHOICE
);
1933 tmp
->set_highlight_colour(LIGHTGRAY
);
1934 tmp
->set_description_text("Select your previous book choice");
1935 menu
->attach_item(tmp
);
1936 tmp
->set_visible(true);
1940 // Returns false if the user aborted.
1941 static bool _prompt_book(const newgame_def
* ng
, newgame_def
* ng_choice
,
1942 const newgame_def
& defaults
,
1943 book_type firstbook
, int numbooks
)
1946 menu
.set_select_type(PrecisionMenu::PRECISION_SINGLESELECT
);
1947 MenuFreeform
* freeform
= new MenuFreeform();
1948 freeform
->init(coord_def(1,1), coord_def(get_number_of_cols(),
1949 get_number_of_lines()), "freeform");
1950 menu
.attach_object(freeform
);
1951 menu
.set_active_object(freeform
);
1953 startup_book_type defbook
= _fixup_book(defaults
.book
, numbooks
);
1954 _construct_book_menu(*ng
, firstbook
, defbook
, numbooks
, freeform
);
1956 BoxMenuHighlighter
* highlighter
= new BoxMenuHighlighter(&menu
);
1957 highlighter
->init(coord_def(0,0), coord_def(0,0), "highlighter");
1958 menu
.attach_object(highlighter
);
1960 // Did we have a previous book?
1961 if (menu
.get_active_item() == NULL
)
1963 freeform
->activate_first_item();
1965 _print_character_info(ng
); // calls clrscr() so needs to be before attach()
1968 tiles
.get_crt()->attach_menu(&menu
);
1971 freeform
->set_visible(true);
1972 highlighter
->set_visible(true);
1975 cprintf("\nYou have a choice of books:");
1981 int keyn
= getch_ck();
1983 // First process menu entries
1984 if (!menu
.process_key(keyn
))
1986 // Process all the keys that are not attached to items
1990 cprintf("\nGoodbye!");
1997 // if we get this far, we did not get a significant selection
1998 // from the menu, nor did we get an escape character
1999 // continue the while loop from the beginning and poll a new key
2003 // We have a significant key input!
2004 // Construct selection vector
2005 std::vector
<MenuItem
*> selection
= menu
.get_selected_items();
2006 // There should only be one selection, otherwise something broke
2007 if (selection
.size() != 1)
2013 // Get the stored id from the selection
2014 int selection_ID
= selection
.at(0)->get_id();
2015 switch (selection_ID
)
2020 list_commands('%', false, _highlight_pattern(ng
));
2021 return _prompt_book(ng
, ng_choice
, defaults
, firstbook
, numbooks
);
2024 return _prompt_book(ng
, ng_choice
, defaults
, firstbook
, numbooks
);
2025 case M_DEFAULT_CHOICE
:
2026 if (defbook
!= SBT_NONE
)
2028 ng_choice
->book
= defbook
;
2031 // This case should not happen if defbook == SBT_NONE
2034 ng_choice
->book
= SBT_VIABLE
;
2037 ng_choice
->book
= SBT_RANDOM
;
2040 // We got an item selection
2041 ng_choice
->book
= static_cast<startup_book_type
> (selection_ID
);
2048 static void _resolve_book(newgame_def
* ng
, const newgame_def
* ng_choice
,
2051 switch (ng_choice
->book
)
2054 ng
->book
= SBT_NONE
;
2059 int good_choices
= 0;
2060 for (int i
= 0; i
< numbooks
; i
++)
2062 startup_book_type sb
= static_cast<startup_book_type
>(i
);
2063 if (book_restriction(sb
, *ng
) == CC_UNRESTRICTED
2064 && one_chance_in(++good_choices
))
2072 // intentional fall-through
2074 ng
->book
= static_cast<startup_book_type
>(random2(numbooks
));
2078 if (ng_choice
->book
>= 0 && ng_choice
->book
< numbooks
)
2079 ng
->book
= ng_choice
->book
;
2082 // Either an invalid combination was passed in through options,
2085 "Incompatible book specified in options file.");
2091 static bool _choose_book(newgame_def
* ng
, newgame_def
* ng_choice
,
2092 const newgame_def
& defaults
,
2093 book_type firstbook
, int numbooks
)
2095 if (ng_choice
->book
== SBT_NONE
2096 && !_prompt_book(ng
, ng_choice
, defaults
, firstbook
, numbooks
))
2100 _resolve_book(ng
, ng_choice
, numbooks
);
2104 static bool _choose_book(newgame_def
* ng
, newgame_def
* ng_choice
,
2105 const newgame_def
& defaults
)
2111 return (_choose_book(ng
, ng_choice
, defaults
, BOOK_CONJURATIONS_I
, 2));
2113 return (_choose_book(ng
, ng_choice
, defaults
, BOOK_MINOR_MAGIC_I
, 3));
2119 // Covers both chaos knight and priest choices.
2120 static std::string
_god_text(god_type god
)
2125 return "Zin (for traditional priests)";
2126 case GOD_YREDELEMNUL
:
2127 return "Yredelemnul (for priests of death)";
2129 return "Beogh (for priests of Orcs)";
2131 return "Xom of Chaos";
2133 return "Makhleb the Destroyer";
2135 return "Lugonu the Unformed";
2137 die("invalid priestly god: %d", god
);
2141 typedef std::pair
<god_type
, char_choice_restriction
> god_choice
;
2143 static god_type
_fixup_god(god_type god
, const std::vector
<god_choice
>& gods
)
2145 if (god
== GOD_NO_GOD
|| god
== GOD_RANDOM
|| god
== GOD_VIABLE
)
2147 for (unsigned int i
= 0; i
< gods
.size(); ++i
)
2148 if (god
== gods
[i
].first
)
2150 return (GOD_NO_GOD
);
2153 static void _construct_god_menu(const god_type
& defgod
,
2154 const std::vector
<god_choice
>& gods
,
2157 static const int ITEMS_START_Y
= 5;
2158 TextItem
* tmp
= NULL
;
2160 coord_def
min_coord(0,0);
2161 coord_def
max_coord(0,0);
2163 for (unsigned int i
= 0; i
< gods
.size(); ++i
)
2165 tmp
= new TextItem();
2168 if (gods
[i
].second
== CC_UNRESTRICTED
)
2170 tmp
->set_fg_colour(LIGHTGREY
);
2171 tmp
->set_highlight_colour(GREEN
);
2175 tmp
->set_fg_colour(DARKGREY
);
2176 tmp
->set_highlight_colour(YELLOW
);
2179 const char letter
= 'a' + i
;
2182 text
+= _god_text(gods
[i
].first
);
2183 //god text is longer than COLUMN_WIDTH
2184 //text.append(COLUMN_WIDTH - text.size() - 1 , ' ');
2185 tmp
->set_text(text
);
2187 tmp
->add_hotkey(letter
);
2188 tmp
->set_id(gods
[i
].first
);
2190 min_coord
.x
= X_MARGIN
;
2191 min_coord
.y
= ITEMS_START_Y
+ i
;
2192 max_coord
.x
= min_coord
.x
+ text
.size();
2193 max_coord
.y
= min_coord
.y
+ 1;
2194 tmp
->set_bounds(min_coord
, max_coord
);
2196 menu
->attach_item(tmp
);
2197 tmp
->set_visible(true);
2198 // Is this item our default god?
2199 if (gods
[i
].first
== defgod
)
2201 menu
->set_active_item(tmp
);
2205 // Add all the special button entries
2206 tmp
= new TextItem();
2207 tmp
->set_text("+ - Viable random choice");
2208 min_coord
.x
= X_MARGIN
;
2209 min_coord
.y
= SPECIAL_KEYS_START_Y
;
2210 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2211 max_coord
.y
= min_coord
.y
+ 1;
2212 tmp
->set_bounds(min_coord
, max_coord
);
2213 tmp
->set_fg_colour(BROWN
);
2214 tmp
->add_hotkey('+');
2215 tmp
->set_id(M_VIABLE
);
2216 tmp
->set_highlight_colour(LIGHTGRAY
);
2217 tmp
->set_description_text("Picks a random viable god");
2218 menu
->attach_item(tmp
);
2219 tmp
->set_visible(true);
2221 tmp
= new TextItem();
2222 tmp
->set_text("% - List aptitudes");
2223 min_coord
.x
= X_MARGIN
;
2224 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
2225 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2226 max_coord
.y
= min_coord
.y
+ 1;
2227 tmp
->set_bounds(min_coord
, max_coord
);
2228 tmp
->set_fg_colour(BROWN
);
2229 tmp
->add_hotkey('%');
2230 tmp
->set_id(M_APTITUDES
);
2231 tmp
->set_highlight_colour(LIGHTGRAY
);
2232 tmp
->set_description_text("Lists the numerical skill train aptitudes for all races");
2233 menu
->attach_item(tmp
);
2234 tmp
->set_visible(true);
2236 tmp
= new TextItem();
2237 tmp
->set_text("? - Help");
2238 min_coord
.x
= X_MARGIN
;
2239 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
2240 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2241 max_coord
.y
= min_coord
.y
+ 1;
2242 tmp
->set_bounds(min_coord
, max_coord
);
2243 tmp
->set_fg_colour(BROWN
);
2244 tmp
->add_hotkey('?');
2245 tmp
->set_id(M_HELP
);
2246 tmp
->set_highlight_colour(LIGHTGRAY
);
2247 tmp
->set_description_text("Opens the help screen");
2248 menu
->attach_item(tmp
);
2249 tmp
->set_visible(true);
2251 tmp
= new TextItem();
2252 tmp
->set_text("* - Random god");
2253 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
2254 min_coord
.y
= SPECIAL_KEYS_START_Y
;
2255 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2256 max_coord
.y
= min_coord
.y
+ 1;
2257 tmp
->set_bounds(min_coord
, max_coord
);
2258 tmp
->set_fg_colour(BROWN
);
2259 tmp
->add_hotkey('*');
2260 tmp
->set_id(M_RANDOM
);
2261 tmp
->set_highlight_colour(LIGHTGRAY
);
2262 tmp
->set_description_text("Picks a random god");
2263 menu
->attach_item(tmp
);
2264 tmp
->set_visible(true);
2266 // Adjust the end marker to align the - because Bksp text is longer by 3
2267 tmp
= new TextItem();
2268 tmp
->set_text("Bksp - Return to character menu");
2269 tmp
->set_description_text("Lets you return back to Character choice menu");
2270 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 3;
2271 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
2272 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2273 max_coord
.y
= min_coord
.y
+ 1;
2274 tmp
->set_bounds(min_coord
, max_coord
);
2275 tmp
->set_fg_colour(BROWN
);
2276 tmp
->add_hotkey(CK_BKSP
);
2277 tmp
->set_id(M_ABORT
);
2278 tmp
->set_highlight_colour(LIGHTGRAY
);
2279 menu
->attach_item(tmp
);
2280 tmp
->set_visible(true);
2282 // Only add tab entry if we have a previous god choice
2283 if (defgod
!= GOD_NO_GOD
)
2285 tmp
= new TextItem();
2289 text
+= defgod
== GOD_RANDOM
? "Random" :
2290 defgod
== GOD_VIABLE
? "Viable" :
2293 // Adjust the end marker to align the - because
2294 // Tab text is longer by 2
2295 tmp
= new TextItem();
2296 tmp
->set_text(text
);
2297 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 2;
2298 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
2299 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2300 max_coord
.y
= min_coord
.y
+ 1;
2301 tmp
->set_bounds(min_coord
, max_coord
);
2302 tmp
->set_fg_colour(BROWN
);
2303 tmp
->add_hotkey('\t');
2304 tmp
->set_id(M_DEFAULT_CHOICE
);
2305 tmp
->set_highlight_colour(LIGHTGRAY
);
2306 tmp
->set_description_text("Select your previous god choice");
2307 menu
->attach_item(tmp
);
2308 tmp
->set_visible(true);
2312 static bool _prompt_god(const newgame_def
* ng
, newgame_def
* ng_choice
,
2313 const newgame_def
& defaults
,
2314 const std::vector
<god_choice
>& gods
)
2317 menu
.set_select_type(PrecisionMenu::PRECISION_SINGLESELECT
);
2318 MenuFreeform
* freeform
= new MenuFreeform();
2319 freeform
->init(coord_def(1,1), coord_def(get_number_of_cols(),
2320 get_number_of_lines()), "freeform");
2321 menu
.attach_object(freeform
);
2322 menu
.set_active_object(freeform
);
2324 const god_type defgod
= _fixup_god(defaults
.religion
, gods
);
2325 _construct_god_menu(defgod
, gods
, freeform
);
2327 BoxMenuHighlighter
* highlighter
= new BoxMenuHighlighter(&menu
);
2328 highlighter
->init(coord_def(0,0), coord_def(0,0), "highlighter");
2329 menu
.attach_object(highlighter
);
2331 // Did we have a previous god?
2332 if (menu
.get_active_item() == NULL
)
2334 freeform
->activate_first_item();
2336 _print_character_info(ng
); // calls clrscr() so needs to be before attach()
2339 tiles
.get_crt()->attach_menu(&menu
);
2342 freeform
->set_visible(true);
2343 highlighter
->set_visible(true);
2346 cprintf("\nWhich god do you wish to serve?");
2352 int keyn
= getch_ck();
2354 // First process menu entries
2355 if (!menu
.process_key(keyn
))
2357 // Process all the keys that are not attached to items
2361 cprintf("\nGoodbye!");
2368 // if we get this far, we did not get a significant selection
2369 // from the menu, nor did we get an escape character
2370 // continue the while loop from the beginning and poll a new key
2374 // We have a significant key input!
2375 // Construct selection vector
2376 std::vector
<MenuItem
*> selection
= menu
.get_selected_items();
2377 // There should only be one selection, otherwise something broke
2378 if (selection
.size() != 1)
2384 // Get the stored id from the selection
2385 int selection_ID
= selection
.at(0)->get_id();
2386 switch (selection_ID
)
2391 list_commands('%', false, _highlight_pattern(ng
));
2392 return _prompt_god(ng
, ng_choice
, defaults
, gods
);
2395 return _prompt_god(ng
, ng_choice
, defaults
, gods
);
2396 case M_DEFAULT_CHOICE
:
2397 if (defgod
!= GOD_NO_GOD
)
2399 ng_choice
->religion
= defgod
;
2402 // This case should not happen when defgod == god_no_god
2405 ng_choice
->religion
= GOD_VIABLE
;
2408 ng_choice
->religion
= GOD_RANDOM
;
2411 // We got an item selection
2412 ng_choice
->religion
= static_cast<god_type
> (selection_ID
);
2419 static void _resolve_god(newgame_def
* ng
, const newgame_def
* ng_choice
,
2420 const std::vector
<god_choice
>& gods
)
2422 switch (ng_choice
->religion
)
2425 ng
->religion
= GOD_NO_GOD
;
2430 int good_choices
= 0;
2431 for (unsigned int i
= 0; i
< gods
.size(); i
++)
2433 if (gods
[i
].second
== CC_UNRESTRICTED
2434 && one_chance_in(++good_choices
))
2436 ng
->religion
= gods
[i
].first
;
2442 // intentional fall-through
2444 ng
->religion
= gods
[random2(gods
.size())].first
;
2448 // Check this is a legal choice, in case it came
2449 // through command line options.
2450 ng
->religion
= _fixup_god(ng_choice
->religion
, gods
);
2451 if (ng
->religion
== GOD_NO_GOD
)
2453 // Either an invalid combination was passed in through options,
2456 "Incompatible god specified in options file.");
2462 static bool _choose_god(newgame_def
* ng
, newgame_def
* ng_choice
,
2463 const newgame_def
& defaults
)
2465 if (ng
->job
!= JOB_PRIEST
&& ng
->job
!= JOB_CHAOS_KNIGHT
)
2468 std::vector
<god_choice
> gods
;
2469 for (unsigned int i
= 0; i
< NUM_GODS
; ++i
)
2472 god
.first
= static_cast<god_type
>(i
);
2473 god
.second
= religion_restriction(god
.first
, *ng
);
2474 if (god
.second
!= CC_BANNED
)
2475 gods
.push_back(god
);
2478 ASSERT(!gods
.empty());
2479 if (gods
.size() == 1)
2481 ng
->religion
= ng_choice
->religion
= gods
[0].first
;
2485 // XXX: assumes we can never choose between a god and no god.
2486 if (ng_choice
->religion
== GOD_NO_GOD
)
2487 if (!_prompt_god(ng
, ng_choice
, defaults
, gods
))
2490 _resolve_god(ng
, ng_choice
, gods
);
2494 int start_to_wand(int wandtype
, bool& is_rod
)
2500 case SWT_ENSLAVEMENT
:
2501 return (WAND_ENSLAVEMENT
);
2504 return (WAND_CONFUSION
);
2506 case SWT_MAGIC_DARTS
:
2507 return (WAND_MAGIC_DARTS
);
2510 return (WAND_FROST
);
2513 return (WAND_FLAME
);
2517 return (STAFF_STRIKING
);
2524 static void _construct_wand_menu(const startup_wand_type
& defwand
,
2527 static const int ITEMS_START_Y
= 5;
2528 TextItem
* tmp
= NULL
;
2530 coord_def
min_coord(0,0);
2531 coord_def
max_coord(0,0);
2534 for (int i
= 0; i
< NUM_STARTUP_WANDS
; i
++)
2536 tmp
= new TextItem();
2538 startup_wand_type sw
= static_cast<startup_wand_type
>(i
);
2540 tmp
->set_fg_colour(LIGHTGREY
);
2541 tmp
->set_highlight_colour(GREEN
);
2543 const char letter
= 'a' + i
;
2547 if (sw
== SWT_STRIKING
)
2550 make_rod(rod
, STAFF_STRIKING
, 8);
2551 text
+= rod
.name(DESC_QUALNAME
, false, true);
2556 wand_type w
= static_cast<wand_type
>(start_to_wand(sw
, dummy
));
2557 text
+= wand_type_name(w
);
2560 text
.append(COLUMN_WIDTH
- text
.size() - 1 , ' ');
2561 tmp
->set_text(text
);
2563 tmp
->add_hotkey(letter
);
2566 min_coord
.x
= X_MARGIN
;
2567 min_coord
.y
= ITEMS_START_Y
+ i
;
2568 max_coord
.x
= min_coord
.x
+ text
.size();
2569 max_coord
.y
= min_coord
.y
+ 1;
2570 tmp
->set_bounds(min_coord
, max_coord
);
2572 menu
->attach_item(tmp
);
2573 tmp
->set_visible(true);
2574 // Is this item our default god?
2577 menu
->set_active_item(tmp
);
2581 // Add all the special button entries
2582 // Wands do not have unviable choices
2583 //tmp = new TextItem();
2584 //tmp->set_text("+ - Viable random choice");
2585 //min_coord.x = X_MARGIN;
2586 //min_coord.y = SPECIAL_KEYS_START_Y;
2587 //max_coord.x = min_coord.x + tmp->get_text().size();
2588 //max_coord.y = min_coord.y + 1;
2589 //tmp->set_bounds(min_coord, max_coord);
2590 //tmp->set_fg_colour(BROWN);
2591 //tmp->add_hotkey('+');
2592 //tmp->set_id(SBT_VIABLE);
2593 //tmp->set_highlight_colour(LIGHTGRAY);
2594 //tmp->set_description_text("Picks a random viable god");
2595 //menu->attach_item(tmp);
2596 //tmp->set_visible(true);
2598 tmp
= new TextItem();
2599 tmp
->set_text("% - List aptitudes");
2600 min_coord
.x
= X_MARGIN
;
2601 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
2602 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2603 max_coord
.y
= min_coord
.y
+ 1;
2604 tmp
->set_bounds(min_coord
, max_coord
);
2605 tmp
->set_fg_colour(BROWN
);
2606 tmp
->add_hotkey('%');
2607 tmp
->set_id(M_APTITUDES
);
2608 tmp
->set_highlight_colour(LIGHTGRAY
);
2609 tmp
->set_description_text("Lists the numerical skill train aptitudes for all races");
2610 menu
->attach_item(tmp
);
2611 tmp
->set_visible(true);
2613 tmp
= new TextItem();
2614 tmp
->set_text("? - Help");
2615 min_coord
.x
= X_MARGIN
;
2616 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
2617 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2618 max_coord
.y
= min_coord
.y
+ 1;
2619 tmp
->set_bounds(min_coord
, max_coord
);
2620 tmp
->set_fg_colour(BROWN
);
2621 tmp
->add_hotkey('?');
2622 tmp
->set_id(M_HELP
);
2623 tmp
->set_highlight_colour(LIGHTGRAY
);
2624 tmp
->set_description_text("Opens the help screen");
2625 menu
->attach_item(tmp
);
2626 tmp
->set_visible(true);
2628 tmp
= new TextItem();
2629 tmp
->set_text("* - Random wand");
2630 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
2631 min_coord
.y
= SPECIAL_KEYS_START_Y
;
2632 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2633 max_coord
.y
= min_coord
.y
+ 1;
2634 tmp
->set_bounds(min_coord
, max_coord
);
2635 tmp
->set_fg_colour(BROWN
);
2636 tmp
->add_hotkey('*');
2637 tmp
->set_id(M_RANDOM
);
2638 tmp
->set_highlight_colour(LIGHTGRAY
);
2639 tmp
->set_description_text("Picks a random wand");
2640 menu
->attach_item(tmp
);
2641 tmp
->set_visible(true);
2643 // Adjust the end marker to align the - because Bksp text is longer by 3
2644 tmp
= new TextItem();
2645 tmp
->set_text("Bksp - Return to character menu");
2646 tmp
->set_description_text("Lets you return back to Character choice menu");
2647 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 3;
2648 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
2649 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2650 max_coord
.y
= min_coord
.y
+ 1;
2651 tmp
->set_bounds(min_coord
, max_coord
);
2652 tmp
->set_fg_colour(BROWN
);
2653 tmp
->add_hotkey(CK_BKSP
);
2654 tmp
->set_id(M_ABORT
);
2655 tmp
->set_highlight_colour(LIGHTGRAY
);
2656 menu
->attach_item(tmp
);
2657 tmp
->set_visible(true);
2659 // Only add tab entry if we have a previous wand choice
2660 if (defwand
!= SWT_NO_SELECTION
)
2662 tmp
= new TextItem();
2666 text
+= defwand
== SWT_ENSLAVEMENT
? "Enslavement" :
2667 defwand
== SWT_CONFUSION
? "Confusion" :
2668 defwand
== SWT_MAGIC_DARTS
? "Magic Darts" :
2669 defwand
== SWT_FROST
? "Frost" :
2670 defwand
== SWT_FLAME
? "Flame" :
2671 defwand
== SWT_STRIKING
? "Striking" :
2672 defwand
== SWT_RANDOM
? "Random" :
2675 // Adjust the end marker to aling the - because
2676 // Tab text is longer by 2
2677 tmp
= new TextItem();
2678 tmp
->set_text(text
);
2679 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 2;
2680 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
2681 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2682 max_coord
.y
= min_coord
.y
+ 1;
2683 tmp
->set_bounds(min_coord
, max_coord
);
2684 tmp
->set_fg_colour(BROWN
);
2685 tmp
->add_hotkey('\t');
2686 tmp
->set_id(M_DEFAULT_CHOICE
);
2687 tmp
->set_highlight_colour(LIGHTGRAY
);
2688 tmp
->set_description_text("Select your previous wand choice");
2689 menu
->attach_item(tmp
);
2690 tmp
->set_visible(true);
2694 static bool _prompt_wand(const newgame_def
* ng
, newgame_def
* ng_choice
,
2695 const newgame_def
& defaults
)
2698 menu
.set_select_type(PrecisionMenu::PRECISION_SINGLESELECT
);
2699 MenuFreeform
* freeform
= new MenuFreeform();
2700 freeform
->init(coord_def(1,1), coord_def(get_number_of_cols(),
2701 get_number_of_lines()), "freeform");
2702 menu
.attach_object(freeform
);
2703 menu
.set_active_object(freeform
);
2705 const startup_wand_type defwand
= defaults
.wand
;
2707 _construct_wand_menu(defwand
, freeform
);
2709 BoxMenuHighlighter
* highlighter
= new BoxMenuHighlighter(&menu
);
2710 highlighter
->init(coord_def(0,0), coord_def(0,0), "highlighter");
2711 menu
.attach_object(highlighter
);
2713 // Did we have a previous wand?
2714 if (menu
.get_active_item() == NULL
)
2716 freeform
->activate_first_item();
2718 _print_character_info(ng
); // calls clrscr() so needs to be before attach()
2721 tiles
.get_crt()->attach_menu(&menu
);
2724 freeform
->set_visible(true);
2725 highlighter
->set_visible(true);
2728 cprintf("\nYou have a choice of tools:");
2734 int keyn
= getch_ck();
2736 // First process menu entries
2737 if (!menu
.process_key(keyn
))
2739 // Process all the keys that are not attached to items
2743 cprintf("\nGoodbye!");
2750 // if we get this far, we did not get a significant selection
2751 // from the menu, nor did we get an escape character
2752 // continue the while loop from the beginning and poll a new key
2756 // We have a significant key input!
2757 // Construct selection vector
2758 std::vector
<MenuItem
*> selection
= menu
.get_selected_items();
2759 // There should only be one selection, otherwise something broke
2760 if (selection
.size() != 1)
2766 // Get the stored id from the selection
2767 int selection_ID
= selection
.at(0)->get_id();
2768 switch (selection_ID
)
2773 list_commands('%', false, _highlight_pattern(ng
));
2774 return _prompt_wand(ng
, ng_choice
, defaults
);
2777 return _prompt_wand(ng
, ng_choice
, defaults
);
2778 case M_DEFAULT_CHOICE
:
2779 if (defwand
!= SWT_NO_SELECTION
)
2781 ng_choice
->wand
= defwand
;
2784 // This case should not happen if defwand == swt_no_selection
2787 ng_choice
->wand
= SWT_RANDOM
;
2790 // We got an item selection
2791 ng_choice
->wand
= static_cast<startup_wand_type
> (selection_ID
);
2798 static void _resolve_wand(newgame_def
* ng
, const newgame_def
* ng_choice
)
2800 switch (ng_choice
->wand
)
2803 ng
->wand
= static_cast<startup_wand_type
>(random2(NUM_STARTUP_WANDS
));
2806 ng
->wand
= ng_choice
->wand
;
2811 static bool _choose_wand(newgame_def
* ng
, newgame_def
* ng_choice
,
2812 const newgame_def
& defaults
)
2814 if (ng
->job
!= JOB_ARTIFICER
)
2817 if (ng_choice
->wand
== SWT_NO_SELECTION
)
2818 if (!_prompt_wand(ng
, ng_choice
, defaults
))
2821 _resolve_wand(ng
, ng_choice
);
2825 static void _construct_gamemode_map_menu(const mapref_vector
& maps
,
2826 const newgame_def
& defaults
,
2829 static const int ITEMS_START_Y
= 5;
2830 static const int MENU_COLUMN_WIDTH
= get_number_of_cols();
2831 TextItem
* tmp
= NULL
;
2833 coord_def
min_coord(0,0);
2834 coord_def
max_coord(0,0);
2835 bool activate_next
= false;
2837 unsigned int padding_width
= 0;
2838 for (int i
= 0; i
< static_cast<int> (maps
.size()); i
++)
2840 if (padding_width
< maps
.at(i
)->desc_or_name().length())
2841 padding_width
= maps
.at(i
)->desc_or_name().length();
2843 padding_width
+= 4; // Count the letter and " - "
2845 for (int i
= 0; i
< static_cast<int> (maps
.size()); i
++)
2847 tmp
= new TextItem();
2850 tmp
->set_fg_colour(LIGHTGREY
);
2851 tmp
->set_highlight_colour(GREEN
);
2853 const char letter
= 'a' + i
;
2857 text
+= maps
[i
]->desc_or_name();
2858 if (static_cast<int>(text
.length()) > MENU_COLUMN_WIDTH
- 1)
2859 text
= text
.substr(0, MENU_COLUMN_WIDTH
- 1);
2862 if (padding_width
> text
.size())
2863 text
.append(padding_width
- text
.size(), ' ');
2865 tmp
->set_text(text
);
2866 tmp
->add_hotkey(letter
);
2867 tmp
->set_id(i
); // ID corresponds to location in vector
2869 min_coord
.x
= X_MARGIN
;
2870 min_coord
.y
= ITEMS_START_Y
+ i
;
2871 max_coord
.x
= min_coord
.x
+ text
.size();
2872 max_coord
.y
= min_coord
.y
+ 1;
2873 tmp
->set_bounds(min_coord
, max_coord
);
2875 menu
->attach_item(tmp
);
2876 tmp
->set_visible(true);
2880 menu
->set_active_item(tmp
);
2881 activate_next
= false;
2883 // Is this item our default map?
2884 else if (defaults
.map
== maps
[i
]->name
)
2886 if (crawl_state
.last_game_won
)
2887 activate_next
= true;
2889 menu
->set_active_item(tmp
);
2893 // Don't overwhelm new players with aptitudes or the full list of commands!
2894 if (!crawl_state
.game_is_tutorial())
2896 tmp
= new TextItem();
2897 tmp
->set_text("% - List aptitudes");
2898 min_coord
.x
= X_MARGIN
;
2899 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
2900 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2901 max_coord
.y
= min_coord
.y
+ 1;
2902 tmp
->set_bounds(min_coord
, max_coord
);
2903 tmp
->set_fg_colour(BROWN
);
2904 tmp
->add_hotkey('%');
2905 tmp
->set_id(M_APTITUDES
);
2906 tmp
->set_highlight_colour(LIGHTGRAY
);
2907 tmp
->set_description_text("Lists the numerical skill train aptitudes for all races");
2908 menu
->attach_item(tmp
);
2909 tmp
->set_visible(true);
2911 tmp
= new TextItem();
2912 tmp
->set_text("? - Help");
2913 min_coord
.x
= X_MARGIN
;
2914 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
2915 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2916 max_coord
.y
= min_coord
.y
+ 1;
2917 tmp
->set_bounds(min_coord
, max_coord
);
2918 tmp
->set_fg_colour(BROWN
);
2919 tmp
->add_hotkey('?');
2920 tmp
->set_id(M_HELP
);
2921 tmp
->set_highlight_colour(LIGHTGRAY
);
2922 tmp
->set_description_text("Opens the help screen");
2923 menu
->attach_item(tmp
);
2924 tmp
->set_visible(true);
2926 tmp
= new TextItem();
2927 tmp
->set_text("* - Random map");
2928 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
;
2929 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 1;
2930 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2931 max_coord
.y
= min_coord
.y
+ 1;
2932 tmp
->set_bounds(min_coord
, max_coord
);
2933 tmp
->set_fg_colour(BROWN
);
2934 tmp
->add_hotkey('*');
2935 tmp
->set_id(M_RANDOM
);
2936 tmp
->set_highlight_colour(LIGHTGRAY
);
2937 tmp
->set_description_text("Picks a random sprint map");
2938 menu
->attach_item(tmp
);
2939 tmp
->set_visible(true);
2942 // TODO: let players escape back to first screen menu
2943 // Adjust the end marker to align the - because Bksp text is longer by 3
2944 //tmp = new TextItem();
2945 //tmp->set_text("Bksp - Return to character menu");
2946 //tmp->set_description_text("Lets you return back to Character choice menu");
2947 //min_coord.x = X_MARGIN + COLUMN_WIDTH - 3;
2948 //min_coord.y = SPECIAL_KEYS_START_Y + 1;
2949 //max_coord.x = min_coord.x + tmp->get_text().size();
2950 //max_coord.y = min_coord.y + 1;
2951 //tmp->set_bounds(min_coord, max_coord);
2952 //tmp->set_fg_colour(BROWN);
2953 //tmp->add_hotkey(CK_BKSP);
2954 //tmp->set_id(M_ABORT);
2955 //tmp->set_highlight_colour(LIGHTGRAY);
2956 //menu->attach_item(tmp);
2957 //tmp->set_visible(true);
2959 // Only add tab entry if we have a previous map choice
2960 if (crawl_state
.game_is_sprint()
2961 && !defaults
.map
.empty() && _char_defined(defaults
))
2963 tmp
= new TextItem();
2966 text
+= defaults
.map
;
2968 // Adjust the end marker to align the - because
2969 // Tab text is longer by 2
2970 tmp
->set_text(text
);
2971 min_coord
.x
= X_MARGIN
+ COLUMN_WIDTH
- 2;
2972 min_coord
.y
= SPECIAL_KEYS_START_Y
+ 2;
2973 max_coord
.x
= min_coord
.x
+ tmp
->get_text().size();
2974 max_coord
.y
= min_coord
.y
+ 1;
2975 tmp
->set_bounds(min_coord
, max_coord
);
2976 tmp
->set_fg_colour(BROWN
);
2977 tmp
->add_hotkey('\t');
2978 tmp
->set_id(M_DEFAULT_CHOICE
);
2979 tmp
->set_highlight_colour(LIGHTGRAY
);
2980 tmp
->set_description_text("Select your previous sprint map and character");
2981 menu
->attach_item(tmp
);
2982 tmp
->set_visible(true);
2986 static bool _cmp_map_by_name(const map_def
* m1
, const map_def
* m2
)
2988 return (m1
->desc_or_name() < m2
->desc_or_name());
2991 static void _prompt_gamemode_map(newgame_def
* ng
, newgame_def
* ng_choice
,
2992 const newgame_def
& defaults
,
2996 menu
.set_select_type(PrecisionMenu::PRECISION_SINGLESELECT
);
2997 MenuFreeform
* freeform
= new MenuFreeform();
2998 freeform
->init(coord_def(1,1), coord_def(get_number_of_cols(),
2999 get_number_of_lines()), "freeform");
3000 menu
.attach_object(freeform
);
3001 menu
.set_active_object(freeform
);
3003 std::sort(maps
.begin(), maps
.end(), _cmp_map_by_name
);
3004 _construct_gamemode_map_menu(maps
, defaults
, freeform
);
3006 BoxMenuHighlighter
* highlighter
= new BoxMenuHighlighter(&menu
);
3007 highlighter
->init(coord_def(0,0), coord_def(0,0), "highlighter");
3008 menu
.attach_object(highlighter
);
3010 // Did we have a previous sprint map?
3011 if (menu
.get_active_item() == NULL
)
3012 freeform
->activate_first_item();
3014 _print_character_info(ng
); // calls clrscr() so needs to be before attach()
3017 tiles
.get_crt()->attach_menu(&menu
);
3020 freeform
->set_visible(true);
3021 highlighter
->set_visible(true);
3024 cprintf("\nYou have a choice of %s:\n\n",
3025 ng_choice
->type
== GAME_TYPE_TUTORIAL
? "lessons"
3032 int keyn
= getch_ck();
3034 // First process menu entries
3035 if (!menu
.process_key(keyn
))
3037 // Process all the keys that are not attached to items
3041 cprintf("\nGoodbye!");
3050 // if we get this far, we did not get a significant selection
3051 // from the menu, nor did we get an escape character
3052 // continue the while loop from the beginning and poll a new key
3056 // We have a significant key input!
3057 // Construct selection vector
3058 std::vector
<MenuItem
*> selection
= menu
.get_selected_items();
3059 // There should only be one selection, otherwise something broke
3060 if (selection
.size() != 1)
3066 // Get the stored id from the selection
3067 int selection_ID
= selection
.at(0)->get_id();
3068 switch (selection_ID
)
3074 list_commands('%', false, _highlight_pattern(ng
));
3075 return _prompt_gamemode_map(ng
, ng_choice
, defaults
, maps
);
3078 return _prompt_gamemode_map(ng
, ng_choice
, defaults
, maps
);
3079 case M_DEFAULT_CHOICE
:
3080 _set_default_choice(ng
, ng_choice
, defaults
);
3083 // FIXME setting this to "random" is broken
3084 ng_choice
->map
.clear();
3087 // We got an item selection
3088 ng_choice
->map
= maps
.at(selection_ID
)->name
;
3094 static void _resolve_gamemode_map(newgame_def
* ng
, const newgame_def
* ng_choice
,
3095 const mapref_vector
& maps
)
3097 if (ng_choice
->map
== "random" || ng_choice
->map
.empty())
3098 ng
->map
= maps
[random2(maps
.size())]->name
;
3100 ng
->map
= ng_choice
->map
;
3103 static void _choose_gamemode_map(newgame_def
* ng
, newgame_def
* ng_choice
,
3104 const newgame_def
& defaults
)
3106 // Sprint, otherwise Tutorial.
3107 const bool is_sprint
= (ng_choice
->type
== GAME_TYPE_SPRINT
);
3109 const mapref_vector maps
= (is_sprint
? get_sprint_maps()
3110 : get_tutorial_maps());
3113 end(1, true, make_stringf("No %s maps found.",
3114 is_sprint
? "sprint"
3115 : "tutorial").c_str());
3118 if (ng_choice
->map
.empty())
3121 && ng_choice
->type
== !crawl_state
.sprint_map
.empty())
3123 ng_choice
->map
= crawl_state
.sprint_map
;
3125 else if (maps
.size() > 1)
3126 _prompt_gamemode_map(ng
, ng_choice
, defaults
, maps
);
3128 ng_choice
->map
= maps
[0]->name
;
3131 _resolve_gamemode_map(ng
, ng_choice
, maps
);