PageRenderTime 93ms CodeModel.GetById 34ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/src/MenuActionBar.cpp

http://github.com/clintbellanger/flare
C++ | 431 lines | 291 code | 68 blank | 72 comment | 95 complexity | 35c7c80d08de3567d7686d1cd108908e MD5 | raw file
Possible License(s): GPL-3.0
  1/*
  2Copyright 2011 Clint Bellanger
  3
  4This file is part of FLARE.
  5
  6FLARE is free software: you can redistribute it and/or modify it under the terms
  7of the GNU General Public License as published by the Free Software Foundation,
  8either version 3 of the License, or (at your option) any later version.
  9
 10FLARE is distributed in the hope that it will be useful, but WITHOUT ANY
 11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 12PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 13
 14You should have received a copy of the GNU General Public License along with
 15FLARE.  If not, see http://www.gnu.org/licenses/
 16*/
 17
 18/**
 19 * class MenuActionBar
 20 *
 21 * Handles the config, display, and usage of the 0-9 hotkeys, mouse buttons, and menu calls
 22 */
 23 
 24#include "MenuActionBar.h"
 25#include "SharedResources.h"
 26#include "WidgetLabel.h"
 27
 28#include <string>
 29#include <sstream>
 30
 31using namespace std;
 32
 33
 34MenuActionBar::MenuActionBar(PowerManager *_powers, StatBlock *_hero, SDL_Surface *_icons) {
 35	powers = _powers;
 36	hero = _hero;
 37	icons = _icons;
 38	
 39	src.x = 0;
 40	src.y = 0;
 41	src.w = 32;
 42	src.h = 32;
 43	label_src.x = 0;
 44	label_src.y = 0;
 45	label_src.w = 640;
 46	label_src.h = 10;
 47	drag_prev_slot = -1;
 48	
 49	clear();
 50	
 51	// TEMP: set action bar positions
 52	// TODO: define in a config file so that the menu is customizable
 53	int offset_x = (VIEW_W - 640)/2;
 54	int offset_y = VIEW_H-32;
 55	
 56	for (int i=0; i<12; i++) {
 57		slots[i].w = slots[i].h = 32;
 58		slots[i].y = VIEW_H-32;
 59		slots[i].x = offset_x + i*32 + 32;
 60	}
 61	slots[10].x += 32;
 62	slots[11].x += 32;
 63	
 64	// menu button positions
 65	for (int i=0; i<4; i++) {
 66		menus[i].w = menus[i].h = 32;
 67		menus[i].y = VIEW_H-32;
 68		menus[i].x = offset_x + 480 + i*32;
 69	}
 70		
 71	// screen areas occupied by the three main sections	
 72	numberArea.h = mouseArea.h = menuArea.h = 32;
 73	numberArea.y = mouseArea.y = menuArea.y = offset_y;
 74	numberArea.x = offset_x+32;
 75	numberArea.w = 320;
 76	mouseArea.x = offset_x+384;
 77	mouseArea.w = 64;
 78	menuArea.x = offset_x+480;
 79	menuArea.w = 128;
 80	
 81	loadGraphics();
 82}
 83
 84void MenuActionBar::clear() {
 85	// clear action bar
 86	for (int i=0; i<12; i++) {
 87		hotkeys[i] = -1;
 88		slot_item_count[i] = -1;
 89		slot_enabled[i] = true;
 90	}
 91
 92    // clear menu notifications
 93    for (int i=0; i<4; i++) 
 94        requires_attention[i] = false;
 95	
 96	// default: LMB set to basic melee attack
 97	hotkeys[10] = 1;
 98}
 99
100void MenuActionBar::loadGraphics() {
101
102	emptyslot = IMG_Load(mods->locate("images/menus/slot_empty.png").c_str());
103	background = IMG_Load(mods->locate("images/menus/actionbar_trim.png").c_str());
104	labels = IMG_Load(mods->locate("images/menus/actionbar_labels.png").c_str());
105	disabled = IMG_Load(mods->locate("images/menus/disabled.png").c_str());
106	attention = IMG_Load(mods->locate("images/menus/attention_glow.png").c_str());
107	if(!emptyslot || !background || !labels || !disabled) {
108		fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError());
109		SDL_Quit();
110	}
111	
112	// optimize
113	SDL_Surface *cleanup = background;
114	background = SDL_DisplayFormatAlpha(background);
115	SDL_FreeSurface(cleanup);	
116	
117	cleanup = emptyslot;
118	emptyslot = SDL_DisplayFormatAlpha(emptyslot);
119	SDL_FreeSurface(cleanup);
120	
121	cleanup = labels;
122	labels = SDL_DisplayFormatAlpha(labels);
123	SDL_FreeSurface(cleanup);
124	
125	cleanup = disabled;
126	disabled = SDL_DisplayFormatAlpha(disabled);
127	SDL_FreeSurface(cleanup);
128
129	cleanup = attention;
130	attention = SDL_DisplayFormatAlpha(attention);
131	SDL_FreeSurface(cleanup);
132}
133
134/**
135 * generic render 32-pixel icon
136 */
137void MenuActionBar::renderIcon(int icon_id, int x, int y) {
138	SDL_Rect icon_src;
139	SDL_Rect icon_dest;
140	
141	icon_dest.x = x;
142	icon_dest.y = y;
143	icon_src.w = icon_src.h = icon_dest.w = icon_dest.h = 32;
144	icon_src.x = (icon_id % 16) * 32;
145	icon_src.y = (icon_id / 16) * 32;
146	SDL_BlitSurface(icons, &icon_src, screen, &icon_dest);
147}
148
149// Renders the "needs attention" icon over the appropriate log menu
150void MenuActionBar::renderAttention(int menu_id) {
151	SDL_Rect dest;
152
153    // x-value is 12 hotkeys and 4 empty slots over
154	dest.x = (VIEW_W - 640)/2 + (menu_id * 32) + 32*15;
155	dest.y = VIEW_H-32;
156    dest.w = dest.h = 32;
157	SDL_BlitSurface(attention, NULL, screen, &dest);		
158}
159
160void MenuActionBar::logic() {
161}
162
163
164
165void MenuActionBar::render() {
166
167	SDL_Rect dest;
168	SDL_Rect trimsrc;
169	
170	int offset_x = (VIEW_W - 640)/2;
171	
172	dest.x = offset_x;
173	dest.y = VIEW_H-35;
174	dest.w = 640;
175	dest.h = 35;
176	trimsrc.x = 0;
177	trimsrc.y = 0;
178	trimsrc.w = 640;
179	trimsrc.h = 35;
180	
181	SDL_BlitSurface(background, &trimsrc, screen, &dest);	
182	
183	// draw hotkeyed icons
184	src.x = src.y = 0;
185	src.w = src.h = dest.w = dest.h = 32;
186	dest.y = VIEW_H-32;	
187	for (int i=0; i<12; i++) {
188
189		if (i<=9)
190			dest.x = offset_x + (i * 32) + 32;
191		else
192			dest.x = offset_x + (i * 32) + 64;
193
194		if (hotkeys[i] != -1) {
195			slot_enabled[i] = (hero->hero_cooldown[hotkeys[i]] == 0) && (slot_item_count[i] != 0); //see if the slot should be greyed out
196			renderIcon(powers->powers[hotkeys[i]].icon, dest.x, dest.y);
197		}
198		else {
199			SDL_BlitSurface(emptyslot, &src, screen, &dest);
200		}
201	}
202	
203	renderCooldowns();
204	renderItemCounts();
205
206    // render log attention notifications
207    for (int i=0; i<4; i++)
208        if (requires_attention[i])
209            renderAttention(i);
210	
211	// draw hotkey labels
212	// TODO: keybindings
213	dest.x = offset_x;
214	dest.y = VIEW_H-10;
215	dest.w = 640;
216	dest.h = 10;
217	SDL_BlitSurface(labels, &label_src, screen, &dest);
218	
219}
220
221/**
222 * Display a notification for any power on cooldown
223 * Also displays disabled powers
224 */
225void MenuActionBar::renderCooldowns() {
226
227	SDL_Rect item_src;
228	SDL_Rect item_dest;
229	
230	for (int i=0; i<12; i++) {
231		if (!slot_enabled[i]) {
232		
233			item_src.x = 0;
234			item_src.y = 0;
235			item_src.h = 32;
236			item_src.w = 32;
237			
238			// Wipe from bottom to top
239			if (hero->hero_cooldown[hotkeys[i]]) {
240				item_src.h = 32 * (hero->hero_cooldown[hotkeys[i]] / (float)powers->powers[hotkeys[i]].cooldown);
241			}
242			
243			// SDL_BlitSurface will write to these Rects, so make a copy
244			item_dest.x = slots[i].x;
245			item_dest.y = slots[i].y;
246			item_dest.w = slots[i].w;
247			item_dest.h = slots[i].h;
248			
249			SDL_BlitSurface(disabled, &item_src, screen, &item_dest);
250		}
251	}
252}
253
254/**
255 * For powers that have consumables, display the number of consumables remaining
256 */
257void MenuActionBar::renderItemCounts() {
258
259	stringstream ss;
260
261	for (int i=0; i<12; i++) {
262		if (slot_item_count[i] > -1) {
263			ss.str("");
264			ss << slot_item_count[i];
265	
266			WidgetLabel label;
267			label.set(slots[i].x, slots[i].y, JUSTIFY_LEFT, VALIGN_TOP, ss.str(), FONT_WHITE);
268			label.render();
269		}
270	}
271}
272
273/**
274 * On mouseover, show tooltip for buttons
275 */
276TooltipData MenuActionBar::checkTooltip(Point mouse) {
277	TooltipData tip;
278	
279	//int offset_x = (VIEW_W - 640)/2;
280	if (isWithin(menus[0], mouse)) {
281		tip.lines[tip.num_lines++] = msg->get("Character Menu (C)");
282		return tip;
283	}
284	if (isWithin(menus[1], mouse)) {
285		tip.lines[tip.num_lines++] = msg->get("Inventory Menu (I)");
286		return tip;
287	}
288	if (isWithin(menus[2], mouse)) {
289		tip.lines[tip.num_lines++] = msg->get("Power Menu (P)");
290		return tip;
291	}
292	if (isWithin(menus[3], mouse)) {
293		tip.lines[tip.num_lines++] = msg->get("Log Menu (L)");
294		return tip;
295	}
296	for (int i=0; i<12; i++) {
297		if (hotkeys[i] != -1) {
298			if (isWithin(slots[i], mouse)) {
299				tip.lines[tip.num_lines++] = powers->powers[hotkeys[i]].name;
300			}
301		}
302	}
303
304	return tip;
305}
306
307/**
308 * After dragging a power or item onto the action bar, set as new hotkey
309 */
310void MenuActionBar::drop(Point mouse, int power_index, bool rearranging) {
311	for (int i=0; i<12; i++) {
312		if (isWithin(slots[i], mouse)) {
313			if (rearranging) {
314				hotkeys[drag_prev_slot] = hotkeys[i];
315			}
316			hotkeys[i] = power_index;
317			return;
318		}
319	}
320}
321
322/**
323 * CTRL-click a hotkey to clear it
324 */
325void MenuActionBar::remove(Point mouse) {
326	for (int i=0; i<12; i++) {
327		if (isWithin(slots[i], mouse)) {
328			hotkeys[i] = -1;
329			return;
330		}
331	}
332}
333
334/**
335 * If pressing an action key (keyboard or mouseclick) and the power is enabled,
336 * return that power's ID.
337 */
338int MenuActionBar::checkAction(Point mouse) {
339
340	// check click action
341	if ((inp->pressing[MAIN1] && !inp->lock[MAIN1]) || (inp->pressing[MAIN2] && !inp->lock[MAIN2])) {
342		for (int i=0; i<12; i++) {
343			if (isWithin(slots[i], mouse) && slot_enabled[i]) {
344
345				return hotkeys[i];
346			}
347		}
348	}
349	
350	// check hotkey action
351	if (inp->pressing[BAR_1] && slot_enabled[0]) return hotkeys[0];
352	if (inp->pressing[BAR_2] && slot_enabled[1]) return hotkeys[1];
353	if (inp->pressing[BAR_3] && slot_enabled[2]) return hotkeys[2];
354	if (inp->pressing[BAR_4] && slot_enabled[3]) return hotkeys[3];
355	if (inp->pressing[BAR_5] && slot_enabled[4]) return hotkeys[4];
356	if (inp->pressing[BAR_6] && slot_enabled[5]) return hotkeys[5];
357	if (inp->pressing[BAR_7] && slot_enabled[6]) return hotkeys[6];
358	if (inp->pressing[BAR_8] && slot_enabled[7]) return hotkeys[7];
359	if (inp->pressing[BAR_9] && slot_enabled[8]) return hotkeys[8];
360	if (inp->pressing[BAR_0] && slot_enabled[9]) return hotkeys[9];
361	if (inp->pressing[MAIN1] && slot_enabled[10] && !inp->lock[MAIN1]) {
362		return hotkeys[10];
363	}
364	if (inp->pressing[MAIN2] && slot_enabled[11] && !inp->lock[MAIN2]) {
365		return hotkeys[11];
366	}
367	return -1;
368}
369
370/**
371 * If clicking while a menu is open, assume the player wants to rearrange the action bar
372 */
373int MenuActionBar::checkDrag(Point mouse) {
374	int power_index;
375	
376	for (int i=0; i<12; i++) {
377		if (isWithin(slots[i], mouse)) {
378			drag_prev_slot = i;
379			power_index = hotkeys[i];
380			hotkeys[i] = -1;
381			return power_index;
382		}
383	}
384	
385	return -1;
386 }
387
388/**
389 * if clicking a menu, act as if the player pressed that menu's hotkey
390 */
391void MenuActionBar::checkMenu(Point mouse, bool &menu_c, bool &menu_i, bool &menu_p, bool &menu_l) {
392	if ((inp->pressing[MAIN1] && !inp->lock[MAIN1]) || (inp->pressing[MAIN2] && !inp->lock[MAIN2])) {
393		if (isWithin(menus[MENU_CHARACTER], mouse)) {
394			if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
395			else inp->lock[MAIN2] = true;
396			menu_c = true;
397		}
398		else if (isWithin(menus[MENU_INVENTORY], mouse)) {
399			if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
400			else inp->lock[MAIN2] = true;
401			menu_i = true;
402		}
403		else if (isWithin(menus[MENU_POWERS], mouse)) {
404			if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
405			else inp->lock[MAIN2] = true;
406			inp->lock[MAIN1] = true;
407			menu_p = true;
408		}
409		else if (isWithin(menus[MENU_LOG], mouse)) {
410			if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
411			else inp->lock[MAIN2] = true;
412			inp->lock[MAIN1] = true;
413			menu_l = true;		
414		}
415	}
416}
417
418/**
419 * Set all hotkeys at once e.g. when loading a game
420 */
421void MenuActionBar::set(int power_id[12]) {
422	for (int i=0; i<12; i++)
423		hotkeys[i] = power_id[i];
424}
425
426MenuActionBar::~MenuActionBar() {
427	SDL_FreeSurface(emptyslot);
428	SDL_FreeSurface(background);
429	SDL_FreeSurface(labels);
430	SDL_FreeSurface(disabled);
431}