1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: shopgui.cpp
5 	Desc: contains shop (GUI) related functions
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 "../shops.hpp"
18 #include "../player.hpp"
19 #include "interface.hpp"
20 #include "../colors.hpp"
21 
22 
hideItemFromShopView(Item & item)23 bool hideItemFromShopView(Item& item)
24 {
25 	if ( item.type == ARTIFACT_ORB_GREEN || item.type == ARTIFACT_ORB_RED || item.type == ARTIFACT_ORB_BLUE )
26 	{
27 		return true;
28 	}
29 	return false;
30 }
31 
rebuildShopInventory()32 void rebuildShopInventory()
33 {
34 	bool mysteriousShopkeeper = (shopkeepertype == 10);
35 	bool mysteriousShopkeeperGreenOrb = false;
36 	bool mysteriousShopkeeperBlueOrb = false;
37 	bool mysteriousShopkeeperRedOrb = false;
38 	if ( mysteriousShopkeeper )
39 	{
40 		for ( node_t* node = shopInv->first; node != NULL; node = node->next )
41 		{
42 			Item* item = (Item*)node->element;
43 			if ( item )
44 			{
45 				if ( item->type == ARTIFACT_ORB_BLUE )
46 				{
47 					mysteriousShopkeeperBlueOrb = true;
48 				}
49 				else if ( item->type == ARTIFACT_ORB_RED )
50 				{
51 					mysteriousShopkeeperRedOrb = true;
52 				}
53 				else if ( item->type == ARTIFACT_ORB_GREEN )
54 				{
55 					mysteriousShopkeeperGreenOrb = true;
56 				}
57 			}
58 		}
59 	}
60 
61 	//Count number of items.
62 	int c = 0;
63 	node_t* node = nullptr;
64 	for ( node = shopInv->first; node != NULL; node = node->next )
65 	{
66 		Item* item = (Item*) node->element;
67 		if ( item )
68 		{
69 			if ( mysteriousShopkeeper )
70 			{
71 				if ( !mysteriousShopkeeperBlueOrb
72 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_BLUE].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_BLUE].end() )
73 				{
74 					continue;
75 				}
76 				if ( !mysteriousShopkeeperGreenOrb
77 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_GREEN].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_GREEN].end() )
78 				{
79 					continue;
80 				}
81 				if ( !mysteriousShopkeeperRedOrb
82 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_RED].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_RED].end() )
83 				{
84 					continue;
85 				}
86 			}
87 			if ( hideItemFromShopView(*item) )
88 			{
89 				continue;
90 			}
91 			if ( shopinventorycategory == 0 && itemCategory(item) != WEAPON && itemCategory(item) != THROWN )
92 			{
93 				continue;
94 			}
95 			else if ( shopinventorycategory == 1 && itemCategory(item) != ARMOR )
96 			{
97 				continue;
98 			}
99 			else if ( shopinventorycategory == 2 && itemCategory(item) != AMULET && itemCategory(item) != RING )
100 			{
101 				continue;
102 			}
103 			else if ( shopinventorycategory == 3 && itemCategory(item) != SPELLBOOK && itemCategory(item) != MAGICSTAFF && itemCategory(item) != SCROLL )
104 			{
105 				continue;
106 			}
107 			else if ( shopinventorycategory == 4 && itemCategory(item) != GEM )
108 			{
109 				continue;
110 			}
111 			else if ( shopinventorycategory == 5 && itemCategory(item) != FOOD && itemCategory(item) != POTION )
112 			{
113 				continue;
114 			}
115 			else if ( shopinventorycategory == 6 && itemCategory(item) != TOOL && itemCategory(item) != BOOK )
116 			{
117 				continue;
118 			}
119 		}
120 		c++;
121 	}
122 	//Sanitize item scroll.
123 	shopitemscroll = std::max(0, std::min(shopitemscroll, c - 4));
124 	//Clear out currently displayed items.
125 	for ( c = 0; c < 4; c++ )
126 	{
127 		shopinvitems[c] = NULL;
128 	}
129 
130 	//Display the items.
131 	c = 0;
132 	for ( node = shopInv->first; node != NULL; node = node->next )
133 	{
134 		Item* item = (Item*) node->element;
135 		if (item)
136 		{
137 			if ( mysteriousShopkeeper )
138 			{
139 				if ( !mysteriousShopkeeperBlueOrb
140 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_BLUE].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_BLUE].end() )
141 				{
142 					continue;
143 				}
144 				if ( !mysteriousShopkeeperGreenOrb
145 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_GREEN].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_GREEN].end() )
146 				{
147 					continue;
148 				}
149 				if ( !mysteriousShopkeeperRedOrb
150 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_RED].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_RED].end() )
151 				{
152 					continue;
153 				}
154 			}
155 			if ( hideItemFromShopView(*item) )
156 			{
157 				continue;
158 			}
159 			if ( shopinventorycategory == 0 && itemCategory(item) != WEAPON && itemCategory(item) != THROWN )
160 			{
161 				continue;
162 			}
163 			else if ( shopinventorycategory == 1 && itemCategory(item) != ARMOR )
164 			{
165 				continue;
166 			}
167 			else if ( shopinventorycategory == 2 && itemCategory(item) != AMULET && itemCategory(item) != RING )
168 			{
169 				continue;
170 			}
171 			else if ( shopinventorycategory == 3 && itemCategory(item) != SPELLBOOK && itemCategory(item) != MAGICSTAFF && itemCategory(item) != SCROLL )
172 			{
173 				continue;
174 			}
175 			else if ( shopinventorycategory == 4 && itemCategory(item) != GEM )
176 			{
177 				continue;
178 			}
179 			else if ( shopinventorycategory == 5 && itemCategory(item) != FOOD && itemCategory(item) != POTION )
180 			{
181 				continue;
182 			}
183 			else if ( shopinventorycategory == 6 && itemCategory(item) != TOOL && itemCategory(item) != BOOK )
184 			{
185 				continue;
186 			}
187 			c++;
188 			if ( c <= shopitemscroll )
189 			{
190 				continue;
191 			}
192 			shopinvitems[c - shopitemscroll - 1] = item;
193 			if ( c > 3 + shopitemscroll )
194 			{
195 				break;
196 			}
197 		}
198 	}
199 }
200 
201 struct Area
202 {
203 public:
204 	int x1, x2, y1, y2;
205 
AreaArea206 	Area(int inX1 = 0, int inX2 = 0, int inY1 = 0, int inY2 = 0)
207 	{
208 		x1 = inX1;
209 		x2 = inX2;
210 		y1 = inY1;
211 		y2 = inY2;
212 	}
213 };
214 
checkBuyItem()215 inline void checkBuyItem()
216 {
217 	if ( (stats[clientnum]->HP <= 0) || (players[clientnum] == nullptr) || (players[clientnum]->entity == nullptr) )
218 	{
219 		return;
220 	}
221 
222 	//Window bounds.
223 	Area shopWindow(xres / 2 - SHOPWINDOW_SIZEX / 2, xres / 2 + SHOPWINDOW_SIZEX / 2, yres / 2 - SHOPWINDOW_SIZEY / 2, yres / 2 + SHOPWINDOW_SIZEY / 2);
224 
225 	//Location of inventory slots.
226 	Area slotAreaBounds;
227 	slotAreaBounds.x1 = shopWindow.x1 + (shopWindow.x2 - shopWindow.x1) / 2 - inventory_bmp->w / 2 + 12;
228 	slotAreaBounds.x2 = slotAreaBounds.x1 + inventoryoption_bmp->w; //Original code: inventory_bmp->w - 28
229 	slotAreaBounds.y1 = shopWindow.y1 + 16 + 160 + 16;
230 	slotAreaBounds.y2 = slotAreaBounds.y1 + (inventoryoption_bmp->h * NUM_SHOP_GUI_SLOTS);
231 
232 	SDL_Rect slotPos;
233 	slotPos.x = slotAreaBounds.x1;
234 	slotPos.w = inventoryoption_bmp->w;
235 	slotPos.y = slotAreaBounds.y1;
236 	slotPos.h = inventoryoption_bmp->h;
237 
238 	if ( (omousex < slotPos.x) || (omousex >= slotPos.x + slotPos.w) )
239 	{
240 		selectedShopSlot = -1;
241 		return;
242 	}
243 
244 	bool selectingSlot = false;
245 
246 	for (int i = 0; i < NUM_SHOP_GUI_SLOTS; ++i, slotPos.y += slotPos.h)
247 	{
248 		if ( omousey >= slotPos.y && omousey < slotPos.y + slotPos.h )
249 		{
250 			//If moused over, highlight slot & check for mouse click or gamepad buy button.
251 			selectedShopSlot = i;
252 			selectingSlot = true;
253 			drawImage(inventoryoption_bmp, nullptr, &slotPos);
254 			if ( mousestatus[SDL_BUTTON_LEFT] || *inputPressed(joyimpulses[INJOY_MENU_USE]) )
255 			{
256 				mousestatus[SDL_BUTTON_LEFT] = 0;
257 				*inputPressed(joyimpulses[INJOY_MENU_USE]) = 0;
258 				buyItemFromShop(shopinvitems[i]);
259 				//Check if no more items after this slot & deal accordingly.
260 				rebuildShopInventory();
261 				if ( shopinvitems[i] == nullptr )
262 				{
263 					if ( shopinvitems[0] == nullptr )
264 					{
265 						//Go back to inventory.
266 						selectedShopSlot = -1;
267 						warpMouseToSelectedInventorySlot();
268 					}
269 					else
270 					{
271 						//Move up one slot.
272 						--selectedShopSlot;
273 						warpMouseToSelectedShopSlot();
274 					}
275 				}
276 			}
277 		}
278 	}
279 
280 	if ( !selectingSlot )
281 	{
282 		selectedShopSlot = -1;
283 	}
284 }
285 
warpMouseToSelectedShopSlot()286 void warpMouseToSelectedShopSlot()
287 {
288 	Area shopWindow(xres / 2 - SHOPWINDOW_SIZEX / 2, xres / 2 + SHOPWINDOW_SIZEX / 2, yres / 2 - SHOPWINDOW_SIZEY / 2, yres / 2 + SHOPWINDOW_SIZEY / 2);
289 
290 	Area slotAreaBounds;
291 	slotAreaBounds.x1 = shopWindow.x1 + (shopWindow.x2 - shopWindow.x1) / 2 - inventory_bmp->w / 2 + 12;
292 	slotAreaBounds.x2 = slotAreaBounds.x1 + inventoryoption_bmp->w; //Original code: inventory_bmp->w - 28
293 	slotAreaBounds.y1 = shopWindow.y1 + 16 + 160 + 16;
294 	slotAreaBounds.y2 = slotAreaBounds.y1 + (inventoryoption_bmp->h * NUM_SHOP_GUI_SLOTS);
295 
296 	SDL_Rect slotPos;
297 	slotPos.x = slotAreaBounds.x1;
298 	slotPos.w = inventoryoption_bmp->w;
299 	slotPos.h = inventoryoption_bmp->h;
300 	slotPos.y = slotAreaBounds.y1 + (inventoryoption_bmp->h * selectedShopSlot);
301 
302 	SDL_WarpMouseInWindow(screen, slotPos.x + (slotPos.w / 2), slotPos.y + (slotPos.h / 2));
303 }
304 
305 /*-------------------------------------------------------------------------------
306 
307 	updateShopWindow
308 
309 	Draws and processes everything related to the shop window
310 
311 -------------------------------------------------------------------------------*/
312 
updateShopWindow()313 void updateShopWindow()
314 {
315 	SDL_Rect pos;
316 	node_t* node;
317 	int c;
318 
319 	if ( multiplayer != CLIENT )
320 	{
321 		Entity* entity = uidToEntity(shopkeeper);
322 		if (entity)
323 		{
324 			Stat* stats = entity->getStats();
325 			shopkeepername = stats->name;
326 		}
327 	}
328 
329 	// draw window
330 	int x1 = xres / 2 - SHOPWINDOW_SIZEX / 2, x2 = xres / 2 + SHOPWINDOW_SIZEX / 2;
331 	int y1 = yres / 2 - SHOPWINDOW_SIZEY / 2, y2 = yres / 2 + SHOPWINDOW_SIZEY / 2;
332 	drawWindowFancy( x1, y1, x2, y2 );
333 
334 	// clicking
335 	int x = x1 + (x2 - x1) / 2 - inventory_bmp->w / 2;
336 	int y = y1 + 16 + 160;
337 	pos.x = x;
338 	pos.y = y;
339 	drawImage(inventory_bmp, NULL, &pos);
340 	if ( mousestatus[SDL_BUTTON_LEFT] )
341 	{
342 		if ( omousey >= y && omousey < y + 16 )
343 		{
344 			if ( omousex >= x + 12 && omousex < x + inventory_bmp->w - 12 )
345 			{
346 				mousestatus[SDL_BUTTON_LEFT] = 0;
347 				shopinventorycategory = (omousex - x - 12) / button_bmp->w;
348 			}
349 		}
350 		else if ( omousey >= y + 16 && omousey < y + 52 )
351 		{
352 			if ( omousex >= x + inventory_bmp->w - 28 && omousex < x + inventory_bmp->w - 12 )
353 			{
354 				mousestatus[SDL_BUTTON_LEFT] = 0;
355 				buttonclick = 10;
356 				shopitemscroll--;
357 			}
358 		}
359 		else if ( omousey >= y + 52 && omousey < y + 88 )
360 		{
361 			if ( omousex >= x + inventory_bmp->w - 28 && omousex < x + inventory_bmp->w - 12 )
362 			{
363 				mousestatus[SDL_BUTTON_LEFT] = 0;
364 				buttonclick = 11;
365 				shopitemscroll++;
366 			}
367 		}
368 	}
369 
370 	// mousewheel
371 	if ( omousex >= x + 12 && omousex < x + inventory_bmp->w - 28 )
372 	{
373 		if ( omousey >= 16 && omousey < y + inventory_bmp->h - 8 )
374 		{
375 			if ( mousestatus[SDL_BUTTON_WHEELDOWN] )
376 			{
377 				mousestatus[SDL_BUTTON_WHEELDOWN] = 0;
378 				shopitemscroll++;
379 			}
380 			else if ( mousestatus[SDL_BUTTON_WHEELUP] )
381 			{
382 				mousestatus[SDL_BUTTON_WHEELUP] = 0;
383 				shopitemscroll--;
384 			}
385 		}
386 	}
387 
388 	// inventory up button
389 	if ( buttonclick == 10 )
390 	{
391 		pos.x = x + inventory_bmp->w - 28;
392 		pos.y = y + 16;
393 		pos.w = 0;
394 		pos.h = 0;
395 		drawImage(invup_bmp, NULL, &pos);
396 	}
397 	// inventory down button
398 	if ( buttonclick == 11 )
399 	{
400 		pos.x = x + inventory_bmp->w - 28;
401 		pos.y = y + 52;
402 		pos.w = 0;
403 		pos.h = 0;
404 		drawImage(invdown_bmp, NULL, &pos);
405 	}
406 	pos.x = x + 12 + button_bmp->w * shopinventorycategory;
407 	pos.y = y;
408 	pos.w = 0;
409 	pos.h = 0;
410 	if ( shopinventorycategory <= 6 )
411 	{
412 		drawImage(button_bmp, NULL, &pos);
413 	}
414 	else
415 	{
416 		drawImage(smallbutton_bmp, NULL, &pos);
417 	}
418 
419 	// inventory category labels
420 	ttfPrintText(ttf8, x + 14, y + 4, language[349]);
421 	ttfPrintText(ttf8, x + 14 + 60, y + 4, language[350]);
422 	ttfPrintText(ttf8, x + 14 + 120, y + 4, language[351]);
423 	ttfPrintText(ttf8, x + 14 + 180, y + 4, language[352]);
424 	ttfPrintText(ttf8, x + 14 + 240, y + 4, language[353]);
425 	ttfPrintText(ttf8, x + 14 + 300, y + 4, language[354]);
426 	ttfPrintText(ttf8, x + 14 + 360, y + 4, language[355]);
427 	ttfPrintText(ttf8, x + 12 + 424, y + 4, language[356]);
428 
429 	// buying
430 	checkBuyItem();
431 
432 
433 	rebuildShopInventory();
434 
435 	int y3 = y + 22;
436 	bool mysteriousShopkeeper = (shopkeepertype == 10);
437 	bool mysteriousShopkeeperGreenOrb = false;
438 	bool mysteriousShopkeeperBlueOrb = false;
439 	bool mysteriousShopkeeperRedOrb = false;
440 	if ( mysteriousShopkeeper )
441 	{
442 		for ( node = shopInv->first; node != NULL; node = node->next )
443 		{
444 			Item* item = (Item*)node->element;
445 			if ( item )
446 			{
447 				if ( item->type == ARTIFACT_ORB_BLUE )
448 				{
449 					mysteriousShopkeeperBlueOrb = true;
450 				}
451 				else if ( item->type == ARTIFACT_ORB_RED )
452 				{
453 					mysteriousShopkeeperRedOrb = true;
454 				}
455 				else if ( item->type == ARTIFACT_ORB_GREEN )
456 				{
457 					mysteriousShopkeeperGreenOrb = true;
458 				}
459 			}
460 		}
461 	}
462 
463 	c = 0;
464 	for ( node = shopInv->first; node != NULL; node = node->next )
465 	{
466 		Item* item = (Item*) node->element;
467 		if (item)
468 		{
469 			if ( mysteriousShopkeeper )
470 			{
471 				if ( !mysteriousShopkeeperBlueOrb
472 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_BLUE].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_BLUE].end() )
473 				{
474 					continue;
475 				}
476 				if ( !mysteriousShopkeeperGreenOrb
477 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_GREEN].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_GREEN].end() )
478 				{
479 					continue;
480 				}
481 				if ( !mysteriousShopkeeperRedOrb
482 					&& shopkeeperMysteriousItems[ARTIFACT_ORB_RED].find(item->type) != shopkeeperMysteriousItems[ARTIFACT_ORB_RED].end() )
483 				{
484 					continue;
485 				}
486 			}
487 			if ( hideItemFromShopView(*item) )
488 			{
489 				continue;
490 			}
491 			if ( shopinventorycategory == 0 && itemCategory(item) != WEAPON && itemCategory(item) != THROWN )
492 			{
493 				continue;
494 			}
495 			else if ( shopinventorycategory == 1 && itemCategory(item) != ARMOR )
496 			{
497 				continue;
498 			}
499 			else if ( shopinventorycategory == 2 && itemCategory(item) != AMULET && itemCategory(item) != RING )
500 			{
501 				continue;
502 			}
503 			else if ( shopinventorycategory == 3 && itemCategory(item) != SPELLBOOK && itemCategory(item) != MAGICSTAFF && itemCategory(item) != SCROLL )
504 			{
505 				continue;
506 			}
507 			else if ( shopinventorycategory == 4 && itemCategory(item) != GEM )
508 			{
509 				continue;
510 			}
511 			else if ( shopinventorycategory == 5 && itemCategory(item) != FOOD && itemCategory(item) != POTION )
512 			{
513 				continue;
514 			}
515 			else if ( shopinventorycategory == 6 && itemCategory(item) != TOOL && itemCategory(item) != BOOK )
516 			{
517 				continue;
518 			}
519 			c++;
520 			if ( c <= shopitemscroll )
521 			{
522 				continue;
523 			}
524 			char tempstr[64] = { 0 };
525 			strncpy(tempstr, item->description(), 42);
526 			if ( strlen(tempstr) == 42 )
527 			{
528 				strcat(tempstr, " ...");
529 			}
530 			Uint32 color = uint32ColorWhite(*mainsurface);
531 			if ( item->beatitude > 0 && stats[clientnum]->PROFICIENCIES[PRO_APPRAISAL] >= SKILL_LEVEL_EXPERT )
532 			{
533 				color = uint32ColorGreen(*mainsurface);
534 			}
535 			ttfPrintTextColor(ttf8, x + 12 + 36, y3, color, true, tempstr);
536 			ttfPrintTextFormatted(ttf8, x + 12 + 348, y3, "%7dG", item->buyValue(clientnum));
537 
538 			if ( mysteriousShopkeeper )
539 			{
540 				pos.x = x + 12 + (348);
541 				pos.y = y + 17 + 18 * (c - shopitemscroll - 1);
542 				pos.w = 16;
543 				pos.h = 16;
544 
545 				for ( auto orbCategories : shopkeeperMysteriousItems )
546 				{
547 					if ( orbCategories.second.find(item->type) != orbCategories.second.end() )
548 					{
549 						node_t* tmpNode = items[orbCategories.first].surfaces.first;
550 						if ( tmpNode )
551 						{
552 							drawImageScaled(*(SDL_Surface**)(tmpNode->element), NULL, &pos);
553 						}
554 						break;
555 					}
556 				}
557 			}
558 
559 			pos.x = x + 12 + 16;
560 			pos.y = y + 17 + 18 * (c - shopitemscroll - 1);
561 			pos.w = 16;
562 			pos.h = 16;
563 			drawImageScaled(itemSprite(item), NULL, &pos);
564 			y3 += 18;
565 			if ( c > 3 + shopitemscroll )
566 			{
567 				break;
568 			}
569 		}
570 	}
571 
572 	// draw money count
573 	ttfPrintTextFormatted( ttf16, x1 + 16, y2 - 32, language[357], stats[clientnum]->GOLD );
574 
575 	// chitchat
576 	if ( (ticks - shoptimer) % 600 == 0 && !mysteriousShopkeeper )
577 	{
578 		shopspeech = language[216 + rand() % NUMCHITCHAT];
579 		shoptimer--;
580 	}
581 
582 	// draw speech
583 	if ( !strcmp(shopspeech, language[194]) || !strcmp(shopspeech, language[195]) || !strcmp(shopspeech, language[196]) )
584 	{
585 		if ( mysteriousShopkeeper )
586 		{
587 			shopspeech = language[3893 + rand() % 3];
588 		}
589 		else
590 		{
591 			ttfPrintTextFormatted( ttf16, x1 + 16 + 160 + 16, y1 + 64, language[358], shopkeepername, language[184 + shopkeepertype] );
592 		}
593 	}
594 
595 	if (sellitem)
596 	{
597 		ttfPrintTextFormatted( ttf16, x1 + 16 + 160 + 16, y1 + 32, shopspeech, sellitem->sellValue(clientnum) );
598 	}
599 	else
600 	{
601 		ttfPrintTextFormatted( ttf16, x1 + 16 + 160 + 16, y1 + 32, shopspeech, 0 );
602 	}
603 
604 
605 	// draw black box for shopkeeper
606 	pos.x = x1 + 16;
607 	pos.y = y1 + 16;
608 	pos.w = 160;
609 	pos.h = 160;
610 	drawRect(&pos, 0, 255);
611 
612 	// draw shopkeeper
613 	if ( uidToEntity(shopkeeper) )
614 	{
615 		Entity* entity = uidToEntity(shopkeeper);
616 		if ( !entity->flags[INVISIBLE] )
617 		{
618 			pos.x = x1 + 16;
619 			pos.y = y1 + 16;
620 			pos.w = 160;
621 			pos.h = 160;
622 			if ( mysteriousShopkeeper )
623 			{
624 				drawImage(shopkeeper2_bmp, NULL, &pos);
625 			}
626 			else
627 			{
628 				drawImage(shopkeeper_bmp, NULL, &pos);
629 			}
630 		}
631 		else
632 		{
633 			pos.x = x1 + 16;
634 			pos.y = y1 + 16;
635 			pos.w = 160;
636 			pos.h = 160;
637 			drawRect(&pos, 0, 255);
638 		}
639 	}
640 }
641 
642 /*void warpMouseToselectedShopSlot() {
643 	//Shop window boundaries.
644 	int x1 = xres/2 - SHOPWINDOW_SIZEX/2, x2 = xres/2 + SHOPWINDOW_SIZEX/2;
645 	int y1 = yres/2 - SHOPWINDOW_SIZEY/2, y2 = yres/2 + SHOPWINDOW_SIZEY/2;
646 
647 	//Calculate x that will be halfway in slot.
648 	int x = x1 + (x2 - x1)/2 - inventory_bmp->w/2;
649 	int y = y1 + 16 + 160 + (inventoryoption_bmp->h * selectedShopSlot) + (inventoryoption_bmp->h / 2);
650 	SDL_WarpMouseInWindow(screen, x, y);
651 }*/
652 
getItemInfoFromShop(int slot)653 inline Item* getItemInfoFromShop(int slot)
654 {
655 	if ( slot >= 4 )
656 	{
657 		return nullptr; //Out of bounds,
658 	}
659 
660 	return shopinvitems[slot];
661 }
662 
selectShopSlot(int slot)663 void selectShopSlot(int slot)
664 {
665 	if ( slot < selectedShopSlot )
666 	{
667 		//Moving up.
668 
669 		/*
670 		 * Possible cases:
671 		 * * 1) Move cursor up the GUI through different selectedShopSlot.
672 		 * * 2) Page up through shopitemscroll--
673 		 * * 3) Scrolling up past top of shop, no shopitemscroll (move back to inventory)
674 		 */
675 
676 		if ( selectedShopSlot <= 0 )
677 		{
678 			//Covers cases 2 & 3.
679 
680 			/*
681 			 * Possible cases:
682 			 * * A) Hit very top of shop inventory, can't go any further. Return to inventory.
683 			 * * B) Page up, scrolling through shopitemscroll.
684 			 */
685 
686 			if ( shopitemscroll <= 0 )
687 			{
688 				//Case 3/A: Return to inventory.
689 				selectedShopSlot = -1;
690 			}
691 			else
692 			{
693 				//Case 2/B: Page up through shop inventory.
694 				--shopitemscroll;
695 			}
696 		}
697 		else
698 		{
699 			//Covers case 1.
700 
701 			//Move cursor up the GUI through different selectedShopSlot (--selectedShopSlot).
702 			--selectedShopSlot;
703 			warpMouseToSelectedShopSlot();
704 		}
705 	}
706 	else if ( slot > selectedShopSlot )
707 	{
708 		//Moving down.
709 
710 		/*
711 		 * Possible cases:
712 		 * * 1) Moving cursor down through GUI through different selectedShopSlot.
713 		 * * 2) Scrolling down past bottom of shop through shopitemscroll++
714 		 * * 3) Scrolling down past bottom of shop, max shop scroll (revoke move -- can't go beyond limit of shop).
715 		 */
716 
717 		if ( selectedShopSlot >= NUM_SHOP_GUI_SLOTS - 1 )
718 		{
719 			//Covers cases 2 & 3.
720 			++shopitemscroll; //Shopitemscroll is automatically sanitized in updateShopWindow().
721 		}
722 		else
723 		{
724 			//Covers case 1.
725 			//Move cursor down through the GUi through different selectedShopSlot (++selectedShopSlot).
726 			//This is a little bit trickier since must revoke movement if there is no item in the next slot!
727 
728 			/*
729 			 * Two possible cases:
730 			 * * A) Items below this. Advance selectedShopSlot to them.
731 			 * * B) On last item already. Do nothing (revoke movement).
732 			 */
733 
734 			Item* item = getItemInfoFromShop(selectedShopSlot + 1);
735 
736 			if ( item )
737 			{
738 				++selectedShopSlot;
739 				warpMouseToSelectedShopSlot();
740 			}
741 			else
742 			{
743 				//No more items. Stop.
744 			}
745 		}
746 	}
747 }
748 
cycleShopCategories(int direction)749 void cycleShopCategories(int direction)
750 {
751 	if ( direction < 0 )
752 	{
753 		//Cycle left.
754 		--shopinventorycategory;
755 	}
756 	else if ( direction > 0 )
757 	{
758 		//Cycle right.
759 		++shopinventorycategory;
760 	}
761 
762 	if ( shopinventorycategory < 0 )
763 	{
764 		shopinventorycategory = NUM_SHOP_CATEGORIES - 1;
765 	}
766 	else if ( shopinventorycategory >= NUM_SHOP_CATEGORIES )
767 	{
768 		shopinventorycategory = 0;
769 	}
770 }