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