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