/src/MenuActionBar.cpp
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}