1 /**
2 * \file player-properties.c
3 * \brief Class and race abilities
4 *
5 * Copyright (c) 1997-2020 Ben Harrison, James E. Wilson, Robert A. Koeneke,
6 * Leon Marrick, Bahman Rabii, Nick McConnell
7 *
8 * This work is free software; you can redistribute it and/or modify it
9 * under the terms of either:
10 *
11 * a) the GNU General Public License as published by the Free Software
12 * Foundation, version 2, or
13 *
14 * b) the "Angband licence":
15 * This software may be copied and distributed for educational, research,
16 * and not for profit purposes provided that this copyright and statement
17 * are included in all such copies. Other copyrights may also apply.
18 */
19
20 #include "angband.h"
21 #include "ui-input.h"
22 #include "ui-menu.h"
23
24 /**
25 * ------------------------------------------------------------------------
26 * Ability data structures and utilities
27 * ------------------------------------------------------------------------ */
28 enum {
29 PLAYER_FLAG_NONE,
30 PLAYER_FLAG_SPECIAL,
31 PLAYER_FLAG_RACE,
32 PLAYER_FLAG_CLASS
33 };
34
class_has_ability(const struct player_class * class,struct player_ability * ability)35 bool class_has_ability(const struct player_class *class,
36 struct player_ability *ability)
37 {
38 if (streq(ability->type, "player") &&
39 pf_has(class->pflags, ability->index)) {
40 return true;
41 } else if (streq(ability->type, "object") &&
42 of_has(class->flags, ability->index)) {
43 return true;
44 }
45 return false;
46 }
47
race_has_ability(const struct player_race * race,struct player_ability * ability)48 bool race_has_ability(const struct player_race *race,
49 struct player_ability *ability)
50 {
51 if (streq(ability->type, "player") &&
52 pf_has(race->pflags, ability->index)) {
53 return true;
54 } else if (streq(ability->type, "object") &&
55 of_has(race->flags, ability->index)) {
56 return true;
57 } else if (streq(ability->type, "element") &&
58 (race->el_info[ability->index].res_level == ability->value)) {
59 return true;
60 }
61
62 return false;
63 }
64
65 /**
66 * ------------------------------------------------------------------------
67 * Code for viewing race and class abilities
68 * ------------------------------------------------------------------------ */
69 int num_abilities;
70 struct player_ability ability_list[32];
71
72
view_ability_tag(struct menu * menu,int oid)73 static char view_ability_tag(struct menu *menu, int oid)
74 {
75 return I2A(oid);
76 }
77
78 /**
79 * Display an entry on the gain ability menu
80 */
view_ability_display(struct menu * menu,int oid,bool cursor,int row,int col,int width)81 void view_ability_display(struct menu *menu, int oid, bool cursor, int row,
82 int col, int width)
83 {
84 char buf[80];
85 byte color;
86 struct player_ability *choices = menu->menu_data;
87
88 switch (choices[oid].group) {
89 case PLAYER_FLAG_SPECIAL:
90 {
91 sprintf(buf, "Specialty Ability: %s", choices[oid].name);
92 color = COLOUR_GREEN;
93 break;
94 }
95 case PLAYER_FLAG_CLASS:
96 {
97 sprintf(buf, "Class: %s", choices[oid].name);
98 color = COLOUR_UMBER;
99 break;
100 }
101 case PLAYER_FLAG_RACE:
102 {
103 sprintf(buf, "Racial: %s", choices[oid].name);
104 color = COLOUR_ORANGE;
105 break;
106 }
107 default:
108 {
109 sprintf(buf, "Mysterious");
110 color = COLOUR_PURPLE;
111 }
112 }
113
114 /* Print it */
115 c_put_str(cursor ? COLOUR_WHITE : color, buf, row, col);
116
117 }
118
119
120 /**
121 * Show ability long description when browsing
122 */
view_ability_menu_browser(int oid,void * data,const region * loc)123 static void view_ability_menu_browser(int oid, void *data, const region *loc)
124 {
125 struct player_ability *choices = data;
126
127 /* Redirect output to the screen */
128 text_out_hook = text_out_to_screen;
129 text_out_wrap = 60;
130 text_out_indent = loc->col - 1;
131 text_out_pad = 1;
132
133 clear_from(loc->row + loc->page_rows);
134 Term_gotoxy(loc->col, loc->row + loc->page_rows);
135 text_out_c(COLOUR_L_BLUE, "\n%s\n", (char *) choices[oid].desc);
136
137 /* XXX */
138 text_out_pad = 0;
139 text_out_indent = 0;
140 text_out_wrap = 0;
141 }
142
143 /**
144 * Display list available specialties.
145 */
view_ability_menu(void)146 void view_ability_menu(void)
147 {
148 struct menu menu;
149 menu_iter menu_f = { view_ability_tag, 0, view_ability_display, 0, 0 };
150 region loc = { 0, 0, 70, -99 };
151 char buf[80];
152
153 /* Save the screen and clear it */
154 screen_save();
155
156 /* Prompt choices */
157 sprintf(buf,
158 "Race and class abilities (%c-%c, ESC=exit): ",
159 I2A(0), I2A(num_abilities - 1));
160
161 /* Set up the menu */
162 menu_init(&menu, MN_SKIN_SCROLL, &menu_f);
163 menu.header = buf;
164 menu_setpriv(&menu, num_abilities, ability_list);
165 loc.page_rows = num_abilities + 1;
166 menu.flags = MN_DBL_TAP;
167 menu.browse_hook = view_ability_menu_browser;
168 region_erase_bordered(&loc);
169 menu_layout(&menu, &loc);
170
171 menu_select(&menu, 0, false);
172
173 /* Load screen */
174 screen_load();
175
176 return;
177 }
178
179 /**
180 * Browse known abilities -BR-
181 */
view_abilities(void)182 static void view_abilities(void)
183 {
184 struct player_ability *ability;
185
186 /* Count the number of class powers we have */
187 for (ability = player_abilities; ability; ability = ability->next) {
188 if (class_has_ability(player->class, ability)) {
189 memcpy(&ability_list[num_abilities], ability,
190 sizeof(struct player_ability));
191 ability_list[num_abilities++].group = PLAYER_FLAG_CLASS;
192 }
193 }
194
195 /* Count the number of race powers we have */
196 for (ability = player_abilities; ability; ability = ability->next) {
197 if (race_has_ability(player->race, ability)) {
198 memcpy(&ability_list[num_abilities], ability,
199 sizeof(struct player_ability));
200 ability_list[num_abilities++].group = PLAYER_FLAG_RACE;
201 }
202 }
203
204 /* View choices until user exits */
205 view_ability_menu();
206
207 /* Exit */
208 num_abilities = 0;
209 return;
210 }
211
212
213 /**
214 * Interact with abilities -BR-
215 */
do_cmd_abilities(void)216 void do_cmd_abilities(void)
217 {
218 /* View existing abilities */
219 view_abilities();
220
221 return;
222 }
223