1 /*-------------------------------------------------------------------------------
2
3 BARONY
4 File: updatechestinventory.cpp
5 Desc: contains updateChestInventory()
6
7 Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 See LICENSE for details.
9
10 -------------------------------------------------------------------------------*/
11
12 #include "../main.hpp"
13 #include "../draw.hpp"
14 #include "../game.hpp"
15 #include "../stat.hpp"
16 #include "../items.hpp"
17 #include "../sound.hpp"
18 #include "../net.hpp"
19 #include "../player.hpp"
20 #include "interface.hpp"
21
22 Entity* openedChest[MAXPLAYERS] = { nullptr };
23
repopulateInvItems(list_t * chestInventory)24 void repopulateInvItems(list_t* chestInventory)
25 {
26 int c = 0;
27
28 //Step 1: Clear.
29 for ( c = 0; c < kNumChestItemsToDisplay; ++c )
30 {
31 invitemschest[c] = nullptr;
32 }
33
34 node_t* node = nullptr;
35 Item* item = nullptr;
36
37 c = 0;
38
39 //Step 2: Loop through inventory till reach part visible in chest GUI and add those items.
40 for ( node = chestInventory->first; node != nullptr; node = node->next )
41 {
42 if ( node->element )
43 {
44 item = (Item*) node->element;
45 if ( item )
46 {
47 ++c;
48 if ( c <= chestitemscroll )
49 {
50 continue;
51 }
52 invitemschest[c - chestitemscroll - 1] = item;
53 if ( c > (kNumChestItemsToDisplay - 1) + chestitemscroll )
54 {
55 break;
56 }
57 }
58 }
59 }
60 }
61
numItemsInChest()62 int numItemsInChest()
63 {
64 node_t* node = nullptr;
65
66 list_t* chestInventory = nullptr;
67 if ( clientnum != 0 )
68 {
69 if ( multiplayer != SERVER )
70 {
71 chestInventory = &chestInv;
72 }
73 }
74 else if (openedChest[clientnum]->children.first && openedChest[clientnum]->children.first->element)
75 {
76 chestInventory = (list_t*)openedChest[clientnum]->children.first->element;
77 }
78
79 int i = 0;
80
81 for (node = chestInventory->first; node != nullptr; node = node->next)
82 {
83 ++i;
84 }
85
86 return i;
87 }
88
warpMouseToSelectedChestSlot()89 void warpMouseToSelectedChestSlot()
90 {
91 int x = CHEST_INVENTORY_X + (inventoryoptionChest_bmp->w / 2);
92 int y = CHEST_INVENTORY_Y + 16 + (inventoryoptionChest_bmp->h * selectedChestSlot) + (inventoryoptionChest_bmp->h / 2);
93 SDL_WarpMouseInWindow(screen, x, y);
94 }
95
96 /*-------------------------------------------------------------------------------
97
98 updateChestInventory
99
100 Processes and draws everything related to chest inventory
101
102 -------------------------------------------------------------------------------*/
103
drawChestSlots()104 inline void drawChestSlots()
105 {
106 if ( !openedChest[clientnum] )
107 {
108 return;
109 }
110
111 SDL_Rect pos;
112 Item* item = nullptr;
113
114 int highlightingSlot = -1;
115
116 if (omousex >= CHEST_INVENTORY_X && omousex < CHEST_INVENTORY_X + (inventoryChest_bmp->w - 28))
117 {
118 pos.x = CHEST_INVENTORY_X + 12;
119 pos.w = 0;
120 pos.h = 0;
121
122 int currentY = CHEST_INVENTORY_Y + 16;
123 for ( int i = 0; i < kNumChestItemsToDisplay; ++i, currentY += inventoryoptionChest_bmp->h )
124 {
125 if ( omousey >= currentY && omousey < currentY + inventoryoptionChest_bmp->h )
126 {
127 pos.y = currentY;
128 item = openedChest[clientnum]->getItemFromChest(invitemschest[i], false, true);
129 if ( item != nullptr )
130 {
131 free(item); //Only YOU can prevent memleaks!
132 drawImage(inventoryoptionChest_bmp, nullptr, &pos); //Highlight the moused-over slot.
133 highlightingSlot = i;
134
135 bool grabbedItem = false;
136
137 if ( (mousestatus[SDL_BUTTON_LEFT] || *inputPressed(joyimpulses[INJOY_MENU_USE])) )
138 {
139 mousestatus[SDL_BUTTON_LEFT] = 0;
140 *inputPressed(joyimpulses[INJOY_MENU_USE]) = 0;
141 item = openedChest[clientnum]->getItemFromChest(invitemschest[i], false);
142 messagePlayer(clientnum, language[374], item->description());
143 itemPickup(clientnum, item);
144 playSound(35 + rand() % 3, 64);
145 grabbedItem = true;
146 }
147 else if ( mousestatus[SDL_BUTTON_RIGHT] )
148 {
149 mousestatus[SDL_BUTTON_RIGHT] = 0;
150 item = openedChest[clientnum]->getItemFromChest(invitemschest[i], true);
151 messagePlayer(clientnum, language[374], item->description());
152 itemPickup(clientnum, item); //Grab all of that item from the chest.
153 playSound(35 + rand() % 3, 64);
154 grabbedItem = true;
155 }
156
157 if ( grabbedItem )
158 {
159 list_t* chestInventory = nullptr;
160 if ( clientnum != 0 )
161 {
162 if ( multiplayer != SERVER )
163 {
164 chestInventory = &chestInv;
165 }
166 }
167 else if ( openedChest[clientnum]->children.first && openedChest[clientnum]->children.first->element )
168 {
169 chestInventory = (list_t*)openedChest[clientnum]->children.first->element;
170 }
171 repopulateInvItems(chestInventory); //Have to regenerate, otherwise the following if check will often end up evaluating to false. //Doesn't work. #blamedennis
172
173 item = openedChest[clientnum]->getItemFromChest(invitemschest[i], false, true);
174 if ( item )
175 {
176 free(item);
177 }
178 else
179 {
180 //Move cursor if this slot is now empty.
181 --highlightingSlot;
182 selectedChestSlot = highlightingSlot;
183 if ( selectedChestSlot >= 0 )
184 {
185 warpMouseToSelectedChestSlot();
186 }
187 else
188 {
189 warpMouseToSelectedInventorySlot();
190 }
191 }
192 }
193 }
194 }
195 }
196 }
197
198 if ( highlightingSlot >= 0 )
199 {
200 selectedChestSlot = highlightingSlot;
201 }
202 else
203 {
204 selectedChestSlot = -1;
205 }
206 }
207
updateChestInventory()208 void updateChestInventory()
209 {
210 if ( !openedChest[clientnum] )
211 {
212 for ( int c = 0; c < kNumChestItemsToDisplay; ++c )
213 {
214 invitemschest[c] = nullptr;
215 }
216 return;
217 }
218
219 SDL_Rect pos;
220 node_t* node, *nextnode;
221 int y, c;
222 int chest_buttonclick = 0;
223 Item* item;
224
225 //Chest inventory GUI.
226
227 //Center the chest GUI.
228 //pos.x = ((xres - winx) / 2) - (inventory_bmp->w / 2);
229 pos.x = CHEST_INVENTORY_X; //(winx + ((winw / 2) - (inventoryChest_bmp->w / 2)))
230 //pos.x = character_bmp->w;
231 //pos.y = ((yres - winy) / 2) - (inventory_bmp->h / 2);
232 pos.y = CHEST_INVENTORY_Y; //(winy + ((winh - winy) - (inventoryChest_bmp->h / 2)));
233 drawImage(inventoryChest_bmp, NULL, &pos);
234
235 // buttons
236 if ( mousestatus[SDL_BUTTON_LEFT] && !selectedItem )
237 {
238 if (openedChest[clientnum])
239 {
240 //Chest inventory scroll up button.
241 if (omousey >= CHEST_INVENTORY_Y + 16 && omousey < CHEST_INVENTORY_Y + 52)
242 {
243 if (omousex >= CHEST_INVENTORY_X + (inventoryChest_bmp->w - 28) && omousex < CHEST_INVENTORY_X + (inventoryChest_bmp->w - 12))
244 {
245 chest_buttonclick = 7;
246 chestitemscroll--;
247 mousestatus[SDL_BUTTON_LEFT] = 0;
248 }
249 }
250 //Chest inventory scroll down button.
251 else if (omousey >= CHEST_INVENTORY_Y + 52 && omousey < CHEST_INVENTORY_Y + 88)
252 {
253 if (omousex >= CHEST_INVENTORY_X + (inventoryChest_bmp->w - 28) && omousex < CHEST_INVENTORY_X + (inventoryChest_bmp->w - 12))
254 {
255 chest_buttonclick = 8;
256 chestitemscroll++;
257 mousestatus[SDL_BUTTON_LEFT] = 0;
258 }
259 }
260 else if (omousey >= CHEST_INVENTORY_Y && omousey < CHEST_INVENTORY_Y + 15)
261 {
262 //Chest inventory close button.
263 if (omousex >= CHEST_INVENTORY_X + 393 && omousex < CHEST_INVENTORY_X + 407)
264 {
265 chest_buttonclick = 9;
266 mousestatus[SDL_BUTTON_LEFT] = 0;
267 }
268 //Chest inventory grab all button.
269 if (omousex >= CHEST_INVENTORY_X + 376 && omousex < CHEST_INVENTORY_X + 391)
270 {
271 chest_buttonclick = 10;
272 mousestatus[SDL_BUTTON_LEFT] = 0;
273 }
274 if (omousex >= CHEST_INVENTORY_X && omousex < CHEST_INVENTORY_X + 377 && omousey >= CHEST_INVENTORY_Y && omousey < CHEST_INVENTORY_Y + 15)
275 {
276 gui_clickdrag = true;
277 dragging_chestGUI = true;
278 dragoffset_x = omousex - CHEST_INVENTORY_X;
279 dragoffset_y = omousey - CHEST_INVENTORY_Y;
280 mousestatus[SDL_BUTTON_LEFT] = 0;
281 }
282 }
283 }
284 }
285
286 if ( *inputPressed(joyimpulses[INJOY_MENU_CHEST_GRAB_ALL]) ) //Gamepad "Y" button grabs all items in chest.
287 {
288 *inputPressed(joyimpulses[INJOY_MENU_CHEST_GRAB_ALL]) = 0;
289 chest_buttonclick = 10;
290 }
291
292 // mousewheel
293 if ( omousex >= CHEST_INVENTORY_X + 12 && omousex < CHEST_INVENTORY_X + (inventoryChest_bmp->w - 28) )
294 {
295 if ( omousey >= CHEST_INVENTORY_Y + 16 && omousey < CHEST_INVENTORY_Y + (inventoryChest_bmp->h - 8) )
296 {
297 if ( mousestatus[SDL_BUTTON_WHEELDOWN] )
298 {
299 mousestatus[SDL_BUTTON_WHEELDOWN] = 0;
300 chestitemscroll++;
301 }
302 else if ( mousestatus[SDL_BUTTON_WHEELUP] )
303 {
304 mousestatus[SDL_BUTTON_WHEELUP] = 0;
305 chestitemscroll--;
306 }
307 }
308 }
309
310 if (dragging_chestGUI)
311 {
312 if (gui_clickdrag)
313 {
314 chestgui_offset_x = (omousex - dragoffset_x) - (CHEST_INVENTORY_X - chestgui_offset_x);
315 chestgui_offset_y = (omousey - dragoffset_y) - (CHEST_INVENTORY_Y - chestgui_offset_y);
316 if (CHEST_INVENTORY_X <= 0)
317 {
318 chestgui_offset_x = 0 - (CHEST_INVENTORY_X - chestgui_offset_x);
319 }
320 if (CHEST_INVENTORY_X > 0 + xres - inventoryChest_bmp->w)
321 {
322 chestgui_offset_x = (0 + xres - inventoryChest_bmp->w) - (CHEST_INVENTORY_X - chestgui_offset_x);
323 }
324 if (CHEST_INVENTORY_Y <= 0)
325 {
326 chestgui_offset_y = 0 - (CHEST_INVENTORY_Y - chestgui_offset_y);
327 }
328 if (CHEST_INVENTORY_Y > 0 + yres - inventoryChest_bmp->h)
329 {
330 chestgui_offset_y = (0 + yres - inventoryChest_bmp->h) - (CHEST_INVENTORY_Y - chestgui_offset_y);
331 }
332 }
333 else
334 {
335 dragging_chestGUI = false;
336 }
337 }
338
339 list_t* chest_inventory = NULL;
340 if (clientnum != 0)
341 {
342 if (multiplayer != SERVER)
343 {
344 chest_inventory = &chestInv;
345 }
346 }
347 else if (openedChest[clientnum]->children.first && openedChest[clientnum]->children.first->element)
348 {
349 chest_inventory = (list_t*)openedChest[clientnum]->children.first->element;
350 }
351
352 if (!chest_inventory)
353 {
354 messagePlayer(0, "Warning: openedChest[%d] has no inventory. This should not happen.", clientnum);
355 }
356 else
357 {
358 //Print the window label signifying this as the chest inventory GUI.
359 ttfPrintText(ttf8, (CHEST_INVENTORY_X + 2 + ((inventoryChest_bmp->w / 2) - ((TTF8_WIDTH * 15) / 2))), CHEST_INVENTORY_Y + 4, language[373]);
360
361 //Chest inventory up button.
362 if (chest_buttonclick == 7)
363 {
364 pos.x = CHEST_INVENTORY_X + (inventoryChest_bmp->w - 28);
365 pos.y = CHEST_INVENTORY_Y + 16;
366 pos.w = 0;
367 pos.h = 0;
368 drawImage(invup_bmp, NULL, &pos);
369 }
370 //Chest inventory down button.
371 if (chest_buttonclick == 8)
372 {
373 pos.x = CHEST_INVENTORY_X + (inventoryChest_bmp->w - 28);
374 pos.y = CHEST_INVENTORY_Y + 52;
375 pos.w = 0;
376 pos.h = 0;
377 drawImage(invdown_bmp, NULL, &pos);
378 }
379 //Chest inventory close button.
380 if (chest_buttonclick == 9)
381 {
382 pos.x = CHEST_INVENTORY_X + 393;
383 pos.y = CHEST_INVENTORY_Y;
384 pos.w = 0;
385 pos.h = 0;
386 drawImage(invclose_bmp, NULL, &pos);
387 if (openedChest[clientnum])
388 {
389 openedChest[clientnum]->closeChest();
390 return; //Crashes otherwise, because the rest of this function runs without a chest...
391 }
392 }
393 //Chest inventory grab all items button.
394 if (chest_buttonclick == 10)
395 {
396 pos.x = CHEST_INVENTORY_X + 376;
397 pos.y = CHEST_INVENTORY_Y;
398 pos.w = 0;
399 pos.h = 0;
400 drawImage(invgraball_bmp, NULL, &pos);
401 for (node = chest_inventory->first; node != NULL; node = nextnode)
402 {
403 nextnode = node->next;
404 if (node->element && openedChest[clientnum])
405 {
406 item = openedChest[clientnum]->getItemFromChest(static_cast<Item* >(node->element), true);
407 if ( item != NULL )
408 {
409 messagePlayer(clientnum, language[374], item->description());
410 itemPickup(clientnum, item);
411 playSound(35 + rand() % 3, 64);
412 }
413 }
414 }
415 }
416
417 drawChestSlots();
418
419 //Okay, now prepare to render all the items.
420 y = CHEST_INVENTORY_Y + 22;
421 c = 0;
422 if (chest_inventory)
423 {
424 c = numItemsInChest();
425 chestitemscroll = std::max(0, std::min(chestitemscroll, c - 4));
426
427 repopulateInvItems(chest_inventory);
428
429 c = 0;
430
431 //Actually render the items.
432 for (node = chest_inventory->first; node != NULL; node = node->next)
433 {
434 if (node->element)
435 {
436 item = (Item*) node->element;
437 if (item)
438 {
439 c++;
440 if (c <= chestitemscroll)
441 {
442 continue;
443 }
444 char tempstr[64] = { 0 };
445 strncpy(tempstr, item->description(), 46);
446 if ( strlen(tempstr) == 46 )
447 {
448 strcat(tempstr, " ...");
449 }
450 ttfPrintText(ttf8, CHEST_INVENTORY_X + 36, y, tempstr);
451 pos.x = CHEST_INVENTORY_X + 16;
452 pos.y = CHEST_INVENTORY_Y + 17 + 18 * (c - chestitemscroll - 1);
453 pos.w = 16;
454 pos.h = 16;
455 drawImageScaled(itemSprite(item), NULL, &pos);
456 y += 18;
457 if (c > (kNumChestItemsToDisplay - 1) + chestitemscroll)
458 {
459 break;
460 }
461 }
462 }
463 }
464 }
465 }
466 }
467
selectChestSlot(int slot)468 void selectChestSlot(int slot)
469 {
470 //TODO?: Grab amount (difference between slot and selectedChestSlot)?
471
472 if ( slot < selectedChestSlot )
473 {
474 //Moving up.
475
476 /*
477 * Possible cases:
478 * * 1) Move cursor up the GUI through different selectedChestSlot.
479 * * 2) Page up through chestitemscroll--
480 * * 3) Scrolling up past top of chest, no chestitemscroll (move back to inventory)
481 */
482
483 if ( selectedChestSlot <= 0 )
484 {
485 //Covers cases 2 & 3.
486
487 /*
488 * Possible cases:
489 * * A) Hit very top of chest inventory, can't go any further. Return to inventory.
490 * * B) Page up, scrolling through chestitemscroll.
491 */
492
493 if ( chestitemscroll <= 0 )
494 {
495 //Case 3/A: Return to inventory.
496 selectedChestSlot = -1;
497 }
498 else
499 {
500 //Case 2/B: Page up through chest inventory.
501 --chestitemscroll;
502 }
503 }
504 else
505 {
506 //Covers case 1.
507
508 //Move cursor up the GUI through different selectedChestSlot (--selectedChestSlot).
509 --selectedChestSlot;
510 warpMouseToSelectedChestSlot();
511 }
512 }
513 else if ( slot > selectedChestSlot )
514 {
515 //Moving down.
516
517 /*
518 * Possible cases:
519 * * 1) Moving cursor down through GUI through different selectedChestSlot.
520 * * 2) Scrolling down past bottom of chest through chestitemscroll++
521 * * 3) Scrolling down past bottom of chest, max chest scroll (revoke move -- can't go beyond limit of chest).
522 */
523
524 Item* item = nullptr;
525
526 if ( selectedChestSlot >= (kNumChestItemsToDisplay - 1) )
527 {
528 //Covers cases 2 & 3.
529
530 /*
531 * Possible cases:
532 * * A) Hit very bottom of chest inventory, can't even scroll any further! Revoke movement.
533 * * B) Page down, scrolling through chestitemscroll.
534 */
535
536 ++chestitemscroll; //chestitemscroll is sanitized in updateChestInventory().
537 }
538 else
539 {
540 //Covers case 1.
541 //Move cursor down through the GUi through different selectedChestSlot (++selectedChestSlot).
542 //This is a little bit trickier since must revoke movement if there is no item in the next slot!
543
544 /*
545 * Two possible cases:
546 * * A) Items below this. Advance selectedChestSlot to them.
547 * * B) On last item already. Do nothing (revoke movement).
548 */
549
550 item = openedChest[clientnum]->getItemFromChest(invitemschest[selectedChestSlot + 1], false, true);
551
552
553 if ( item )
554 {
555 free(item); //Cleanup duty.
556
557 ++selectedChestSlot;
558 warpMouseToSelectedChestSlot();
559 }
560 else
561 {
562 }
563 }
564 }
565 }
566