1 /**
2  * @file stores.cpp
3  *
4  * Implementation of functionality for stores and towner dialogs.
5  */
6 #include "all.h"
7 #include "options.h"
8 #include <algorithm>
9 
10 DEVILUTION_BEGIN_NAMESPACE
11 
12 namespace {
13 
14 /** The current towner being interacted with */
15 _talker_id talker;
16 
17 /** Is the curren dialog full size */
18 bool stextsize;
19 
20 /** Number of text lines in the current dialog */
21 int stextsmax;
22 /** Remember currently selected text line from stext while displaying a dialog */
23 int stextlhold;
24 /** Currently selected text line from stext */
25 int stextsel;
26 /** Text lines */
27 STextStruct stext[STORE_LINES];
28 
29 /** Does the current panel have a scrollbar */
30 bool stextscrl;
31 /** Remember last scoll position */
32 int stextvhold;
33 /** Scoll position */
34 int stextsval;
35 /** Next scoll position */
36 int stextdown;
37 /** Previous scoll position */
38 int stextup;
39 /** Count down for the push state of the scroll up button */
40 char stextscrlubtn;
41 /** Count down for the push state of the scroll down button */
42 char stextscrldbtn;
43 
44 /** Remember current store while displaying a dialog */
45 talk_id stextshold;
46 
47 /** Start of possible gossip dialogs for current store */
48 _speech_id gossipstart;
49 /** End of possible gossip dialogs for current store */
50 _speech_id gossipend;
51 
52 /** Maps from towner IDs to NPC names. */
53 const char *const talkname[] = {
54 	"Griswold",
55 	"Pepin",
56 	"",
57 	"Ogden",
58 	"Cain",
59 	"Farnham",
60 	"Adria",
61 	"Gillian",
62 	"Wirt"
63 };
64 
DrawSTextBack(CelOutputBuffer out)65 void DrawSTextBack(CelOutputBuffer out)
66 {
67 	CelDrawTo(out, PANEL_X + 344, 327 + UI_OFFSET_Y, pSTextBoxCels, 1, 271);
68 	DrawHalfTransparentRectTo(out, PANEL_X + 347, UI_OFFSET_Y + 28, 265, 297);
69 }
70 
DrawSSlider(CelOutputBuffer out,int y1,int y2)71 void DrawSSlider(CelOutputBuffer out, int y1, int y2)
72 {
73 	int yd1, yd2, yd3;
74 
75 	yd1 = y1 * 12 + 44 + UI_OFFSET_Y;
76 	yd2 = y2 * 12 + 44 + UI_OFFSET_Y;
77 	if (stextscrlubtn != -1)
78 		CelDrawTo(out, PANEL_X + 601, yd1, pSTextSlidCels, 12, 12);
79 	else
80 		CelDrawTo(out, PANEL_X + 601, yd1, pSTextSlidCels, 10, 12);
81 	if (stextscrldbtn != -1)
82 		CelDrawTo(out, PANEL_X + 601, yd2, pSTextSlidCels, 11, 12);
83 	else
84 		CelDrawTo(out, PANEL_X + 601, yd2, pSTextSlidCels, 9, 12);
85 	yd1 += 12;
86 	for (yd3 = yd1; yd3 < yd2; yd3 += 12) {
87 		CelDrawTo(out, PANEL_X + 601, yd3, pSTextSlidCels, 14, 12);
88 	}
89 	if (stextsel == 22)
90 		yd3 = stextlhold;
91 	else
92 		yd3 = stextsel;
93 	if (storenumh > 1)
94 		yd3 = 1000 * (stextsval + ((yd3 - stextup) >> 2)) / (storenumh - 1) * (y2 * 12 - y1 * 12 - 24) / 1000;
95 	else
96 		yd3 = 0;
97 	CelDrawTo(out, PANEL_X + 601, (y1 + 1) * 12 + 44 + UI_OFFSET_Y + yd3, pSTextSlidCels, 13, 12);
98 }
99 
AddSLine(int y)100 void AddSLine(int y)
101 {
102 	stext[y]._sx = 0;
103 	stext[y]._syoff = 0;
104 	stext[y]._sstr[0] = 0;
105 	stext[y]._sline = 1;
106 }
107 
AddSTextVal(int y,int val)108 void AddSTextVal(int y, int val)
109 {
110 	stext[y]._sval = val;
111 }
112 
OffsetSTextY(int y,int yo)113 void OffsetSTextY(int y, int yo)
114 {
115 	stext[y]._syoff = yo;
116 }
117 
AddSText(int x,int y,bool j,const char * str,text_color clr,BOOL sel)118 void AddSText(int x, int y, bool j, const char *str, text_color clr, BOOL sel)
119 {
120 	stext[y]._sx = x;
121 	stext[y]._syoff = 0;
122 	strcpy(stext[y]._sstr, str);
123 	stext[y]._sjust = j;
124 	stext[y]._sclr = clr;
125 	stext[y]._sline = 0;
126 	stext[y]._ssel = sel;
127 }
128 
PrintStoreItem(ItemStruct * x,int l,text_color iclr)129 void PrintStoreItem(ItemStruct *x, int l, text_color iclr)
130 {
131 	char sstr[128];
132 	char str, dex;
133 	BYTE mag;
134 
135 	sstr[0] = '\0';
136 	if (x->_iIdentified) {
137 		if (x->_iMagical != ITEM_QUALITY_UNIQUE) {
138 			if (x->_iPrePower != -1) {
139 				PrintItemPower(x->_iPrePower, x);
140 				strcat(sstr, tempstr);
141 			}
142 		}
143 		if (x->_iSufPower != -1) {
144 			PrintItemPower(x->_iSufPower, x);
145 			if (sstr[0])
146 				strcat(sstr, ",  ");
147 			strcat(sstr, tempstr);
148 		}
149 	}
150 	if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) {
151 		sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges);
152 		if (sstr[0])
153 			strcat(sstr, ",  ");
154 		strcat(sstr, tempstr);
155 	}
156 	if (sstr[0]) {
157 		AddSText(40, l, FALSE, sstr, iclr, FALSE);
158 		l++;
159 	}
160 	sstr[0] = '\0';
161 	if (x->_iClass == ICLASS_WEAPON)
162 		sprintf(sstr, "Damage: %i-%i  ", x->_iMinDam, x->_iMaxDam);
163 	if (x->_iClass == ICLASS_ARMOR)
164 		sprintf(sstr, "Armor: %i  ", x->_iAC);
165 	if (x->_iMaxDur != DUR_INDESTRUCTIBLE && x->_iMaxDur) {
166 		sprintf(tempstr, "Dur: %i/%i,  ", x->_iDurability, x->_iMaxDur);
167 		strcat(sstr, tempstr);
168 	} else {
169 		strcat(sstr, "Indestructible,  ");
170 	}
171 	if (x->_itype == ITYPE_MISC)
172 		sstr[0] = '\0';
173 	str = x->_iMinStr;
174 	mag = x->_iMinMag;
175 	dex = x->_iMinDex;
176 	if (str == 0 && mag == 0 && dex == 0) {
177 		strcat(sstr, "No required attributes");
178 	} else {
179 		strcpy(tempstr, "Required:");
180 		if (str)
181 			sprintf(tempstr + strlen(tempstr), " %i Str", str);
182 		if (mag)
183 			sprintf(tempstr + strlen(tempstr), " %i Mag", mag);
184 		if (dex)
185 			sprintf(tempstr + strlen(tempstr), " %i Dex", dex);
186 		strcat(sstr, tempstr);
187 	}
188 	AddSText(40, l++, FALSE, sstr, iclr, FALSE);
189 	if (x->_iMagical == ITEM_QUALITY_UNIQUE) {
190 		if (x->_iIdentified)
191 			AddSText(40, l, FALSE, "Unique Item", iclr, FALSE);
192 	}
193 }
194 
StoreAutoPlace()195 void StoreAutoPlace()
196 {
197 	BOOL done;
198 	int i, w, h, idx;
199 
200 	SetICursor(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM);
201 	w = icursW28;
202 	h = icursH28;
203 	done = FALSE;
204 	if (AutoEquipEnabled(plr[myplr], plr[myplr].HoldItem) && AutoEquip(myplr, plr[myplr].HoldItem)) {
205 		done = TRUE;
206 	}
207 
208 	if (w == 1 && h == 1 && !done) {
209 		idx = plr[myplr].HoldItem.IDidx;
210 		if (plr[myplr].HoldItem._iStatFlag && AllItemsList[idx].iUsable) {
211 			for (i = 0; i < MAXBELTITEMS && !done; i++) {
212 				if (plr[myplr].SpdList[i].isEmpty()) {
213 					plr[myplr].SpdList[i] = plr[myplr].HoldItem;
214 					done = TRUE;
215 				}
216 			}
217 		}
218 		for (i = 30; i <= 39 && !done; i++) {
219 			done = AutoPlace(myplr, i, w, h, TRUE);
220 		}
221 		for (i = 20; i <= 29 && !done; i++) {
222 			done = AutoPlace(myplr, i, w, h, TRUE);
223 		}
224 		for (i = 10; i <= 19 && !done; i++) {
225 			done = AutoPlace(myplr, i, w, h, TRUE);
226 		}
227 		for (i = 0; i <= 9 && !done; i++) {
228 			done = AutoPlace(myplr, i, w, h, TRUE);
229 		}
230 	}
231 	if (w == 1 && h == 2 && !done) {
232 		for (i = 29; i >= 20 && !done; i--) {
233 			done = AutoPlace(myplr, i, w, h, TRUE);
234 		}
235 		for (i = 9; i >= 0 && !done; i--) {
236 			done = AutoPlace(myplr, i, w, h, TRUE);
237 		}
238 		for (i = 19; i >= 10 && !done; i--) {
239 			done = AutoPlace(myplr, i, w, h, TRUE);
240 		}
241 	}
242 	if (w == 1 && h == 3 && !done) {
243 		for (i = 0; i < 20 && !done; i++) {
244 			done = AutoPlace(myplr, i, w, h, TRUE);
245 		}
246 	}
247 	if (w == 2 && h == 2 && !done) {
248 		for (i = 0; i < 10 && !done; i++) {
249 			done = AutoPlace(myplr, AP2x2Tbl[i], w, h, TRUE);
250 		}
251 		for (i = 21; i < 29 && !done; i += 2) {
252 			done = AutoPlace(myplr, i, w, h, TRUE);
253 		}
254 		for (i = 1; i < 9 && !done; i += 2) {
255 			done = AutoPlace(myplr, i, w, h, TRUE);
256 		}
257 		for (i = 10; i < 19 && !done; i++) {
258 			done = AutoPlace(myplr, i, w, h, TRUE);
259 		}
260 	}
261 	if (w == 2 && h == 3 && !done) {
262 		for (i = 0; i < 9 && !done; i++) {
263 			done = AutoPlace(myplr, i, w, h, TRUE);
264 		}
265 		for (i = 10; i < 19 && !done; i++) {
266 			done = AutoPlace(myplr, i, w, h, TRUE);
267 		}
268 	}
269 }
270 
S_StartSmith()271 void S_StartSmith()
272 {
273 	stextsize = false;
274 	stextscrl = false;
275 	AddSText(0, 1, TRUE, "Welcome to the", COL_GOLD, FALSE);
276 	AddSText(0, 3, TRUE, "Blacksmith's shop", COL_GOLD, FALSE);
277 	AddSText(0, 7, TRUE, "Would you like to:", COL_GOLD, FALSE);
278 	AddSText(0, 10, TRUE, "Talk to Griswold", COL_BLUE, TRUE);
279 	AddSText(0, 12, TRUE, "Buy basic items", COL_WHITE, TRUE);
280 	AddSText(0, 14, TRUE, "Buy premium items", COL_WHITE, TRUE);
281 	AddSText(0, 16, TRUE, "Sell items", COL_WHITE, TRUE);
282 	AddSText(0, 18, TRUE, "Repair items", COL_WHITE, TRUE);
283 	AddSText(0, 20, TRUE, "Leave the shop", COL_WHITE, TRUE);
284 	AddSLine(5);
285 	storenumh = 20;
286 }
287 
S_ScrollSBuy(int idx)288 void S_ScrollSBuy(int idx)
289 {
290 	int l, ls;
291 
292 	ls = idx;
293 	ClearSText(5, 21);
294 	stextup = 5;
295 
296 	for (l = 5; l < 20; l += 4) {
297 		if (!smithitem[ls].isEmpty()) {
298 			text_color iclr = COL_WHITE;
299 			if (smithitem[ls]._iMagical) {
300 				iclr = COL_BLUE;
301 			}
302 
303 			if (!smithitem[ls]._iStatFlag) {
304 				iclr = COL_RED;
305 			}
306 
307 			if (smithitem[ls]._iMagical) {
308 				AddSText(20, l, FALSE, smithitem[ls]._iIName, iclr, TRUE);
309 			} else {
310 				AddSText(20, l, FALSE, smithitem[ls]._iName, iclr, TRUE);
311 			}
312 
313 			AddSTextVal(l, smithitem[ls]._iIvalue);
314 			PrintStoreItem(&smithitem[ls], l + 1, iclr);
315 			stextdown = l;
316 			ls++;
317 		}
318 	}
319 
320 	if (stextsel != -1 && !stext[stextsel]._ssel && stextsel != 22)
321 		stextsel = stextdown;
322 }
323 
S_StartSBuy()324 void S_StartSBuy()
325 {
326 	int i;
327 
328 	stextsize = true;
329 	stextscrl = true;
330 	stextsval = 0;
331 	sprintf(tempstr, "I have these items for sale:             Your gold: %i", plr[myplr]._pGold);
332 	AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
333 	AddSLine(3);
334 	AddSLine(21);
335 	S_ScrollSBuy(stextsval);
336 	AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE);
337 	OffsetSTextY(22, 6);
338 	storenumh = 0;
339 	for (i = 0; !smithitem[i].isEmpty(); i++) {
340 		storenumh++;
341 	}
342 
343 	stextsmax = storenumh - 4;
344 	if (stextsmax < 0)
345 		stextsmax = 0;
346 }
347 
S_ScrollSPBuy(int idx)348 void S_ScrollSPBuy(int idx)
349 {
350 	int l, boughtitems;
351 
352 	ClearSText(5, 21);
353 	boughtitems = idx;
354 
355 	stextup = 5;
356 	for (idx = 0; boughtitems; idx++) {
357 		if (!premiumitem[idx].isEmpty())
358 			boughtitems--;
359 	}
360 
361 	for (l = 5; l < 20 && idx < SMITH_PREMIUM_ITEMS; l += 4) {
362 		if (!premiumitem[idx].isEmpty()) {
363 			text_color iclr = COL_WHITE;
364 			if (premiumitem[idx]._iMagical)
365 				iclr = COL_BLUE;
366 			if (!premiumitem[idx]._iStatFlag)
367 				iclr = COL_RED;
368 			AddSText(20, l, FALSE, premiumitem[idx]._iIName, iclr, TRUE);
369 			AddSTextVal(l, premiumitem[idx]._iIvalue);
370 			PrintStoreItem(&premiumitem[idx], l + 1, iclr);
371 			stextdown = l;
372 		} else {
373 			l -= 4;
374 		}
375 		idx++;
376 	}
377 	if (stextsel != -1 && !stext[stextsel]._ssel && stextsel != 22)
378 		stextsel = stextdown;
379 }
380 
S_StartSPBuy()381 BOOL S_StartSPBuy()
382 {
383 	int i;
384 
385 	storenumh = 0;
386 	for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) {
387 		if (!premiumitem[i].isEmpty())
388 			storenumh++;
389 	}
390 	if (!storenumh) {
391 		StartStore(STORE_SMITH);
392 		stextsel = 14;
393 		return FALSE;
394 	}
395 
396 	stextsize = true;
397 	stextscrl = true;
398 	stextsval = 0;
399 
400 	sprintf(tempstr, "I have these premium items for sale:     Your gold: %i", plr[myplr]._pGold);
401 	AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
402 	AddSLine(3);
403 	AddSLine(21);
404 	AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE);
405 	OffsetSTextY(22, 6);
406 
407 	stextsmax = storenumh - 4;
408 	if (stextsmax < 0)
409 		stextsmax = 0;
410 
411 	S_ScrollSPBuy(stextsval);
412 
413 	return TRUE;
414 }
415 
SmithSellOk(int i)416 BOOL SmithSellOk(int i)
417 {
418 	ItemStruct *pI;
419 
420 	if (i >= 0) {
421 		pI = &plr[myplr].InvList[i];
422 	} else {
423 		pI = &plr[myplr].SpdList[-(i + 1)];
424 	}
425 
426 	if (pI->isEmpty())
427 		return FALSE;
428 
429 	if (pI->_iMiscId > IMISC_OILFIRST && pI->_iMiscId < IMISC_OILLAST)
430 		return TRUE;
431 
432 	if (pI->_itype == ITYPE_MISC)
433 		return FALSE;
434 	if (pI->_itype == ITYPE_GOLD)
435 		return FALSE;
436 	if (pI->_itype == ITYPE_STAFF && (!gbIsHellfire || pI->_iSpell != SPL_NULL))
437 		return FALSE;
438 	if (pI->_iClass == ICLASS_QUEST)
439 		return FALSE;
440 	if (pI->IDidx == IDI_LAZSTAFF)
441 		return FALSE;
442 
443 	return TRUE;
444 }
445 
S_ScrollSSell(int idx)446 void S_ScrollSSell(int idx)
447 {
448 	int l;
449 
450 	ClearSText(5, 21);
451 	stextup = 5;
452 
453 	for (l = 5; l < 20; l += 4) {
454 		if (idx >= storenumh)
455 			break;
456 		if (!storehold[idx].isEmpty()) {
457 			text_color iclr = COL_WHITE;
458 			if (storehold[idx]._iMagical) {
459 				iclr = COL_BLUE;
460 			}
461 
462 			if (!storehold[idx]._iStatFlag) {
463 				iclr = COL_RED;
464 			}
465 
466 			if (storehold[idx]._iMagical && storehold[idx]._iIdentified) {
467 				AddSText(20, l, FALSE, storehold[idx]._iIName, iclr, TRUE);
468 				AddSTextVal(l, storehold[idx]._iIvalue);
469 			} else {
470 				AddSText(20, l, FALSE, storehold[idx]._iName, iclr, TRUE);
471 				AddSTextVal(l, storehold[idx]._ivalue);
472 			}
473 
474 			PrintStoreItem(&storehold[idx], l + 1, iclr);
475 			stextdown = l;
476 		}
477 		idx++;
478 	}
479 
480 	stextsmax = storenumh - 4;
481 	if (stextsmax < 0)
482 		stextsmax = 0;
483 }
484 
S_StartSSell()485 void S_StartSSell()
486 {
487 	int i;
488 	BOOL sellok;
489 
490 	stextsize = true;
491 	sellok = FALSE;
492 	storenumh = 0;
493 
494 	for (i = 0; i < 48; i++)
495 		storehold[i]._itype = ITYPE_NONE;
496 
497 	for (i = 0; i < plr[myplr]._pNumInv; i++) {
498 		if (storenumh >= 48)
499 			break;
500 		if (SmithSellOk(i)) {
501 			sellok = TRUE;
502 			storehold[storenumh] = plr[myplr].InvList[i];
503 
504 			if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && storehold[storenumh]._iIdentified)
505 				storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue;
506 
507 			if ((storehold[storenumh]._ivalue >>= 2) == 0)
508 				storehold[storenumh]._ivalue = 1;
509 
510 			storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue;
511 			storehidx[storenumh++] = i;
512 		}
513 	}
514 
515 	for (i = 0; i < MAXBELTITEMS; i++) {
516 		if (storenumh >= 48)
517 			break;
518 		if (SmithSellOk(-(i + 1))) {
519 			storehold[storenumh] = plr[myplr].SpdList[i];
520 			sellok = TRUE;
521 
522 			if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && storehold[storenumh]._iIdentified)
523 				storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue;
524 
525 			if (!(storehold[storenumh]._ivalue >>= 2))
526 				storehold[storenumh]._ivalue = 1;
527 
528 			storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue;
529 			storehidx[storenumh++] = -(i + 1);
530 		}
531 	}
532 
533 	if (!sellok) {
534 		stextscrl = false;
535 		sprintf(tempstr, "You have nothing I want.             Your gold: %i", plr[myplr]._pGold);
536 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
537 		AddSLine(3);
538 		AddSLine(21);
539 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
540 		OffsetSTextY(22, 6);
541 	} else {
542 		stextscrl = true;
543 		stextsval = 0;
544 		stextsmax = plr[myplr]._pNumInv;
545 		sprintf(tempstr, "Which item is for sale?             Your gold: %i", plr[myplr]._pGold);
546 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
547 		AddSLine(3);
548 		AddSLine(21);
549 		S_ScrollSSell(stextsval);
550 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
551 		OffsetSTextY(22, 6);
552 	}
553 }
554 
SmithRepairOk(int i)555 BOOL SmithRepairOk(int i)
556 {
557 	if (plr[myplr].InvList[i].isEmpty())
558 		return FALSE;
559 	if (plr[myplr].InvList[i]._itype == ITYPE_MISC)
560 		return FALSE;
561 	if (plr[myplr].InvList[i]._itype == ITYPE_GOLD)
562 		return FALSE;
563 	if (plr[myplr].InvList[i]._iDurability == plr[myplr].InvList[i]._iMaxDur)
564 		return FALSE;
565 
566 	return TRUE;
567 }
568 
S_StartSRepair()569 void S_StartSRepair()
570 {
571 	BOOL repairok;
572 	int i;
573 
574 	stextsize = true;
575 	repairok = FALSE;
576 	storenumh = 0;
577 	for (i = 0; i < 48; i++)
578 		storehold[i]._itype = ITYPE_NONE;
579 	if (!plr[myplr].InvBody[INVLOC_HEAD].isEmpty() && plr[myplr].InvBody[INVLOC_HEAD]._iDurability != plr[myplr].InvBody[INVLOC_HEAD]._iMaxDur) {
580 		repairok = TRUE;
581 		AddStoreHoldRepair(plr[myplr].InvBody, -1);
582 	}
583 	if (!plr[myplr].InvBody[INVLOC_CHEST].isEmpty() && plr[myplr].InvBody[INVLOC_CHEST]._iDurability != plr[myplr].InvBody[INVLOC_CHEST]._iMaxDur) {
584 		repairok = TRUE;
585 		AddStoreHoldRepair(&plr[myplr].InvBody[INVLOC_CHEST], -2);
586 	}
587 	if (!plr[myplr].InvBody[INVLOC_HAND_LEFT].isEmpty() && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iDurability != plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxDur) {
588 		repairok = TRUE;
589 		AddStoreHoldRepair(&plr[myplr].InvBody[INVLOC_HAND_LEFT], -3);
590 	}
591 	if (!plr[myplr].InvBody[INVLOC_HAND_RIGHT].isEmpty() && plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iDurability != plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iMaxDur) {
592 		repairok = TRUE;
593 		AddStoreHoldRepair(&plr[myplr].InvBody[INVLOC_HAND_RIGHT], -4);
594 	}
595 	for (i = 0; i < plr[myplr]._pNumInv; i++) {
596 		if (storenumh >= 48)
597 			break;
598 		if (SmithRepairOk(i)) {
599 			repairok = TRUE;
600 			AddStoreHoldRepair(&plr[myplr].InvList[i], i);
601 		}
602 	}
603 	if (!repairok) {
604 		stextscrl = false;
605 		sprintf(tempstr, "You have nothing to repair.             Your gold: %i", plr[myplr]._pGold);
606 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
607 		AddSLine(3);
608 		AddSLine(21);
609 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
610 		OffsetSTextY(22, 6);
611 		return;
612 	}
613 
614 	stextscrl = true;
615 	stextsval = 0;
616 	stextsmax = plr[myplr]._pNumInv;
617 	sprintf(tempstr, "Repair which item?             Your gold: %i", plr[myplr]._pGold);
618 	AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
619 	AddSLine(3);
620 	AddSLine(21);
621 	S_ScrollSSell(stextsval);
622 	AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
623 	OffsetSTextY(22, 6);
624 }
625 
FillManaPlayer()626 void FillManaPlayer()
627 {
628 	if (!sgOptions.Gameplay.bAdriaRefillsMana)
629 		return;
630 	if (plr[myplr]._pMana != plr[myplr]._pMaxMana) {
631 		PlaySFX(IS_CAST8);
632 	}
633 	plr[myplr]._pMana = plr[myplr]._pMaxMana;
634 	plr[myplr]._pManaBase = plr[myplr]._pMaxManaBase;
635 	drawmanaflag = TRUE;
636 }
637 
S_StartWitch()638 void S_StartWitch()
639 {
640 	FillManaPlayer();
641 	stextsize = false;
642 	stextscrl = false;
643 	AddSText(0, 2, TRUE, "Witch's shack", COL_GOLD, FALSE);
644 	AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE);
645 	AddSText(0, 12, TRUE, "Talk to Adria", COL_BLUE, TRUE);
646 	AddSText(0, 14, TRUE, "Buy items", COL_WHITE, TRUE);
647 	AddSText(0, 16, TRUE, "Sell items", COL_WHITE, TRUE);
648 	AddSText(0, 18, TRUE, "Recharge staves", COL_WHITE, TRUE);
649 	AddSText(0, 20, TRUE, "Leave the shack", COL_WHITE, TRUE);
650 	AddSLine(5);
651 	storenumh = 20;
652 }
653 
S_ScrollWBuy(int idx)654 void S_ScrollWBuy(int idx)
655 {
656 	int l, ls;
657 
658 	ls = idx;
659 	ClearSText(5, 21);
660 	stextup = 5;
661 
662 	for (l = 5; l < 20; l += 4) {
663 		if (!witchitem[ls].isEmpty()) {
664 			text_color iclr = COL_WHITE;
665 			if (witchitem[ls]._iMagical) {
666 				iclr = COL_BLUE;
667 			}
668 
669 			if (!witchitem[ls]._iStatFlag) {
670 				iclr = COL_RED;
671 			}
672 
673 			if (witchitem[ls]._iMagical) {
674 				AddSText(20, l, FALSE, witchitem[ls]._iIName, iclr, TRUE);
675 			} else {
676 				AddSText(20, l, FALSE, witchitem[ls]._iName, iclr, TRUE);
677 			}
678 
679 			AddSTextVal(l, witchitem[ls]._iIvalue);
680 			PrintStoreItem(&witchitem[ls], l + 1, iclr);
681 			stextdown = l;
682 			ls++;
683 		}
684 	}
685 
686 	if (stextsel != -1 && !stext[stextsel]._ssel && stextsel != 22)
687 		stextsel = stextdown;
688 }
689 
S_StartWBuy()690 void S_StartWBuy()
691 {
692 	int i;
693 
694 	stextsize = true;
695 	stextscrl = true;
696 	stextsval = 0;
697 	stextsmax = 20;
698 	sprintf(tempstr, "I have these items for sale:             Your gold: %i", plr[myplr]._pGold);
699 	AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
700 	AddSLine(3);
701 	AddSLine(21);
702 	S_ScrollWBuy(stextsval);
703 	AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE);
704 	OffsetSTextY(22, 6);
705 
706 	storenumh = 0;
707 	for (i = 0; !witchitem[i].isEmpty(); i++) {
708 		storenumh++;
709 	}
710 	stextsmax = storenumh - 4;
711 	if (stextsmax < 0)
712 		stextsmax = 0;
713 }
714 
WitchSellOk(int i)715 BOOL WitchSellOk(int i)
716 {
717 	BOOL rv;
718 	ItemStruct *pI;
719 
720 	rv = FALSE;
721 
722 	if (i >= 0)
723 		pI = &plr[myplr].InvList[i];
724 	else
725 		pI = &plr[myplr].SpdList[-(i + 1)];
726 
727 	if (pI->_itype == ITYPE_MISC)
728 		rv = TRUE;
729 	if (pI->_iMiscId > 29 && pI->_iMiscId < 41)
730 		rv = FALSE;
731 	if (pI->_iClass == ICLASS_QUEST)
732 		rv = FALSE;
733 	if (pI->_itype == ITYPE_STAFF && (!gbIsHellfire || pI->_iSpell != SPL_NULL))
734 		rv = TRUE;
735 	if (pI->IDidx >= IDI_FIRSTQUEST && pI->IDidx <= IDI_LASTQUEST)
736 		rv = FALSE;
737 	if (pI->IDidx == IDI_LAZSTAFF)
738 		rv = FALSE;
739 	return rv;
740 }
741 
S_StartWSell()742 void S_StartWSell()
743 {
744 	int i;
745 	BOOL sellok;
746 
747 	stextsize = true;
748 	sellok = FALSE;
749 	storenumh = 0;
750 
751 	for (i = 0; i < 48; i++)
752 		storehold[i]._itype = ITYPE_NONE;
753 
754 	for (i = 0; i < plr[myplr]._pNumInv; i++) {
755 		if (storenumh >= 48)
756 			break;
757 		if (WitchSellOk(i)) {
758 			sellok = TRUE;
759 			storehold[storenumh] = plr[myplr].InvList[i];
760 
761 			if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && storehold[storenumh]._iIdentified)
762 				storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue;
763 
764 			if ((storehold[storenumh]._ivalue >>= 2) == 0)
765 				storehold[storenumh]._ivalue = 1;
766 
767 			storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue;
768 			storehidx[storenumh++] = i;
769 		}
770 	}
771 
772 	for (i = 0; i < MAXBELTITEMS; i++) {
773 		if (storenumh >= 48)
774 			break;
775 		if (!plr[myplr].SpdList[i].isEmpty() && WitchSellOk(-(i + 1))) {
776 			sellok = TRUE;
777 			storehold[storenumh] = plr[myplr].SpdList[i];
778 
779 			if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && storehold[storenumh]._iIdentified)
780 				storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue;
781 
782 			if ((storehold[storenumh]._ivalue >>= 2) == 0)
783 				storehold[storenumh]._ivalue = 1;
784 
785 			storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue;
786 			storehidx[storenumh++] = -(i + 1);
787 		}
788 	}
789 
790 	if (!sellok) {
791 		stextscrl = false;
792 		sprintf(tempstr, "You have nothing I want.             Your gold: %i", plr[myplr]._pGold);
793 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
794 		AddSLine(3);
795 		AddSLine(21);
796 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
797 		OffsetSTextY(22, 6);
798 	} else {
799 		stextscrl = true;
800 		stextsval = 0;
801 		stextsmax = plr[myplr]._pNumInv;
802 		sprintf(tempstr, "Which item is for sale?             Your gold: %i", plr[myplr]._pGold);
803 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
804 		AddSLine(3);
805 		AddSLine(21);
806 		S_ScrollSSell(stextsval);
807 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
808 		OffsetSTextY(22, 6);
809 	}
810 }
811 
WitchRechargeOk(int i)812 BOOL WitchRechargeOk(int i)
813 {
814 	BOOL rv;
815 
816 	rv = FALSE;
817 	if (plr[myplr].InvList[i]._itype == ITYPE_STAFF
818 	    && plr[myplr].InvList[i]._iCharges != plr[myplr].InvList[i]._iMaxCharges) {
819 		rv = TRUE;
820 	}
821 	if ((plr[myplr].InvList[i]._iMiscId == IMISC_UNIQUE || plr[myplr].InvList[i]._iMiscId == IMISC_STAFF)
822 	    && plr[myplr].InvList[i]._iCharges < plr[myplr].InvList[i]._iMaxCharges) {
823 		rv = TRUE;
824 	}
825 	return rv;
826 }
827 
AddStoreHoldRecharge(ItemStruct itm,int i)828 void AddStoreHoldRecharge(ItemStruct itm, int i)
829 {
830 	storehold[storenumh] = itm;
831 	storehold[storenumh]._ivalue += spelldata[itm._iSpell].sStaffCost;
832 	storehold[storenumh]._ivalue = storehold[storenumh]._ivalue * (storehold[storenumh]._iMaxCharges - storehold[storenumh]._iCharges) / (storehold[storenumh]._iMaxCharges * 2);
833 	storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue;
834 	storehidx[storenumh] = i;
835 	storenumh++;
836 }
837 
S_StartWRecharge()838 void S_StartWRecharge()
839 {
840 	int i;
841 	BOOL rechargeok;
842 
843 	stextsize = true;
844 	rechargeok = FALSE;
845 	storenumh = 0;
846 
847 	for (i = 0; i < 48; i++) {
848 		storehold[i]._itype = ITYPE_NONE;
849 	}
850 
851 	if ((plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF || plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_UNIQUE)
852 	    && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges != plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxCharges) {
853 		rechargeok = TRUE;
854 		AddStoreHoldRecharge(plr[myplr].InvBody[INVLOC_HAND_LEFT], -1);
855 	}
856 
857 	for (i = 0; i < plr[myplr]._pNumInv; i++) {
858 		if (storenumh >= 48)
859 			break;
860 		if (WitchRechargeOk(i)) {
861 			rechargeok = TRUE;
862 			AddStoreHoldRecharge(plr[myplr].InvList[i], i);
863 		}
864 	}
865 
866 	if (!rechargeok) {
867 		stextscrl = false;
868 		sprintf(tempstr, "You have nothing to recharge.             Your gold: %i", plr[myplr]._pGold);
869 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
870 		AddSLine(3);
871 		AddSLine(21);
872 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
873 		OffsetSTextY(22, 6);
874 	} else {
875 		stextscrl = true;
876 		stextsval = 0;
877 		stextsmax = plr[myplr]._pNumInv;
878 		sprintf(tempstr, "Recharge which item?             Your gold: %i", plr[myplr]._pGold);
879 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
880 		AddSLine(3);
881 		AddSLine(21);
882 		S_ScrollSSell(stextsval);
883 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
884 		OffsetSTextY(22, 6);
885 	}
886 }
887 
S_StartNoMoney()888 void S_StartNoMoney()
889 {
890 	StartStore(stextshold);
891 	stextscrl = false;
892 	stextsize = true;
893 	ClearSText(5, 23);
894 	AddSText(0, 14, TRUE, "You do not have enough gold", COL_WHITE, TRUE);
895 }
896 
S_StartNoRoom()897 void S_StartNoRoom()
898 {
899 	StartStore(stextshold);
900 	stextscrl = false;
901 	ClearSText(5, 23);
902 	AddSText(0, 14, TRUE, "You do not have enough room in inventory", COL_WHITE, TRUE);
903 }
904 
S_StartConfirm()905 void S_StartConfirm()
906 {
907 	BOOL idprint;
908 
909 	StartStore(stextshold);
910 	stextscrl = false;
911 	ClearSText(5, 23);
912 	text_color iclr = COL_WHITE;
913 
914 	if (plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL)
915 		iclr = COL_BLUE;
916 	if (!plr[myplr].HoldItem._iStatFlag)
917 		iclr = COL_RED;
918 
919 	idprint = plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL;
920 
921 	if (stextshold == STORE_SIDENTIFY)
922 		idprint = FALSE;
923 	if (plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL && !plr[myplr].HoldItem._iIdentified) {
924 		if (stextshold == STORE_SSELL)
925 			idprint = FALSE;
926 		if (stextshold == STORE_WSELL)
927 			idprint = FALSE;
928 		if (stextshold == STORE_SREPAIR)
929 			idprint = FALSE;
930 		if (stextshold == STORE_WRECHARGE)
931 			idprint = FALSE;
932 	}
933 	if (idprint)
934 		AddSText(20, 8, FALSE, plr[myplr].HoldItem._iIName, iclr, FALSE);
935 	else
936 		AddSText(20, 8, FALSE, plr[myplr].HoldItem._iName, iclr, FALSE);
937 
938 	AddSTextVal(8, plr[myplr].HoldItem._iIvalue);
939 	PrintStoreItem(&plr[myplr].HoldItem, 9, iclr);
940 
941 	switch (stextshold) {
942 	case STORE_BBOY:
943 		strcpy(tempstr, "Do we have a deal?");
944 		break;
945 	case STORE_SIDENTIFY:
946 		strcpy(tempstr, "Are you sure you want to identify this item?");
947 		break;
948 	case STORE_HBUY:
949 	case STORE_SPBUY:
950 	case STORE_WBUY:
951 	case STORE_SBUY:
952 		strcpy(tempstr, "Are you sure you want to buy this item?");
953 		break;
954 	case STORE_WRECHARGE:
955 		strcpy(tempstr, "Are you sure you want to recharge this item?");
956 		break;
957 	case STORE_SSELL:
958 	case STORE_WSELL:
959 		strcpy(tempstr, "Are you sure you want to sell this item?");
960 		break;
961 	case STORE_SREPAIR:
962 		strcpy(tempstr, "Are you sure you want to repair this item?");
963 		break;
964 	default:
965 		app_fatal("Unknown store dialog %d", stextshold);
966 	}
967 	AddSText(0, 15, TRUE, tempstr, COL_WHITE, FALSE);
968 	AddSText(0, 18, TRUE, "Yes", COL_WHITE, TRUE);
969 	AddSText(0, 20, TRUE, "No", COL_WHITE, TRUE);
970 }
971 
S_StartBoy()972 void S_StartBoy()
973 {
974 	stextsize = false;
975 	stextscrl = false;
976 	AddSText(0, 2, TRUE, "Wirt the Peg-legged boy", COL_GOLD, FALSE);
977 	AddSLine(5);
978 	if (!boyitem.isEmpty()) {
979 		AddSText(0, 8, TRUE, "Talk to Wirt", COL_BLUE, TRUE);
980 		AddSText(0, 12, TRUE, "I have something for sale,", COL_GOLD, FALSE);
981 		AddSText(0, 14, TRUE, "but it will cost 50 gold", COL_GOLD, FALSE);
982 		AddSText(0, 16, TRUE, "just to take a look. ", COL_GOLD, FALSE);
983 		AddSText(0, 18, TRUE, "What have you got?", COL_WHITE, TRUE);
984 		AddSText(0, 20, TRUE, "Say goodbye", COL_WHITE, TRUE);
985 	} else {
986 		AddSText(0, 12, TRUE, "Talk to Wirt", COL_BLUE, TRUE);
987 		AddSText(0, 18, TRUE, "Say goodbye", COL_WHITE, TRUE);
988 	}
989 }
990 
S_StartBBoy()991 void S_StartBBoy()
992 {
993 	stextsize = true;
994 	stextscrl = false;
995 	sprintf(tempstr, "I have this item for sale:             Your gold: %i", plr[myplr]._pGold);
996 	AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
997 	AddSLine(3);
998 	AddSLine(21);
999 	text_color iclr = COL_WHITE;
1000 
1001 	if (boyitem._iMagical != ITEM_QUALITY_NORMAL)
1002 		iclr = COL_BLUE;
1003 	if (!boyitem._iStatFlag)
1004 		iclr = COL_RED;
1005 	if (boyitem._iMagical != ITEM_QUALITY_NORMAL)
1006 		AddSText(20, 10, FALSE, boyitem._iIName, iclr, TRUE);
1007 	else
1008 		AddSText(20, 10, FALSE, boyitem._iName, iclr, TRUE);
1009 
1010 	if (gbIsHellfire)
1011 		AddSTextVal(10, boyitem._iIvalue - (boyitem._iIvalue >> 2));
1012 	else
1013 		AddSTextVal(10, boyitem._iIvalue + (boyitem._iIvalue >> 1));
1014 	PrintStoreItem(&boyitem, 11, iclr);
1015 	AddSText(0, 22, TRUE, "Leave", COL_WHITE, TRUE);
1016 	OffsetSTextY(22, 6);
1017 }
1018 
HealPlayer()1019 void HealPlayer()
1020 {
1021 	if (plr[myplr]._pHitPoints != plr[myplr]._pMaxHP) {
1022 		PlaySFX(IS_CAST8);
1023 	}
1024 	plr[myplr]._pHitPoints = plr[myplr]._pMaxHP;
1025 	plr[myplr]._pHPBase = plr[myplr]._pMaxHPBase;
1026 	drawhpflag = TRUE;
1027 }
1028 
S_StartHealer()1029 void S_StartHealer()
1030 {
1031 	HealPlayer();
1032 	stextsize = false;
1033 	stextscrl = false;
1034 	AddSText(0, 1, TRUE, "Welcome to the", COL_GOLD, FALSE);
1035 	AddSText(0, 3, TRUE, "Healer's home", COL_GOLD, FALSE);
1036 	AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE);
1037 	AddSText(0, 12, TRUE, "Talk to Pepin", COL_BLUE, TRUE);
1038 	AddSText(0, 14, TRUE, "Buy items", COL_WHITE, TRUE);
1039 	AddSText(0, 16, TRUE, "Leave Healer's home", COL_WHITE, TRUE);
1040 	AddSLine(5);
1041 	storenumh = 20;
1042 }
1043 
S_ScrollHBuy(int idx)1044 void S_ScrollHBuy(int idx)
1045 {
1046 	int l;
1047 
1048 	ClearSText(5, 21);
1049 	stextup = 5;
1050 	for (l = 5; l < 20; l += 4) {
1051 		if (!healitem[idx].isEmpty()) {
1052 			text_color iclr = COL_WHITE;
1053 			if (!healitem[idx]._iStatFlag) {
1054 				iclr = COL_RED;
1055 			}
1056 
1057 			AddSText(20, l, FALSE, healitem[idx]._iName, iclr, TRUE);
1058 			AddSTextVal(l, healitem[idx]._iIvalue);
1059 			PrintStoreItem(&healitem[idx], l + 1, iclr);
1060 			stextdown = l;
1061 			idx++;
1062 		}
1063 	}
1064 
1065 	if (stextsel != -1 && !stext[stextsel]._ssel && stextsel != 22)
1066 		stextsel = stextdown;
1067 }
1068 
S_StartHBuy()1069 void S_StartHBuy()
1070 {
1071 	int i;
1072 
1073 	stextsize = true;
1074 	stextscrl = true;
1075 	stextsval = 0;
1076 	sprintf(tempstr, "I have these items for sale:             Your gold: %i", plr[myplr]._pGold);
1077 	AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
1078 	AddSLine(3);
1079 	AddSLine(21);
1080 	S_ScrollHBuy(stextsval);
1081 	AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE);
1082 	OffsetSTextY(22, 6);
1083 
1084 	storenumh = 0;
1085 	for (i = 0; !healitem[i].isEmpty(); i++) {
1086 		storenumh++;
1087 	}
1088 	stextsmax = storenumh - 4;
1089 	if (stextsmax < 0)
1090 		stextsmax = 0;
1091 }
1092 
S_StartStory()1093 void S_StartStory()
1094 {
1095 	stextsize = false;
1096 	stextscrl = false;
1097 	AddSText(0, 2, TRUE, "The Town Elder", COL_GOLD, FALSE);
1098 	AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE);
1099 	AddSText(0, 12, TRUE, "Talk to Cain", COL_BLUE, TRUE);
1100 	AddSText(0, 14, TRUE, "Identify an item", COL_WHITE, TRUE);
1101 	AddSText(0, 18, TRUE, "Say goodbye", COL_WHITE, TRUE);
1102 	AddSLine(5);
1103 }
1104 
IdItemOk(ItemStruct * i)1105 BOOL IdItemOk(ItemStruct *i)
1106 {
1107 	if (i->isEmpty()) {
1108 		return FALSE;
1109 	}
1110 	if (i->_iMagical == ITEM_QUALITY_NORMAL) {
1111 		return FALSE;
1112 	}
1113 	return !i->_iIdentified;
1114 }
1115 
AddStoreHoldId(ItemStruct itm,int i)1116 void AddStoreHoldId(ItemStruct itm, int i)
1117 {
1118 	storehold[storenumh] = itm;
1119 	storehold[storenumh]._ivalue = 100;
1120 	storehold[storenumh]._iIvalue = 100;
1121 	storehidx[storenumh] = i;
1122 	storenumh++;
1123 }
1124 
S_StartSIdentify()1125 void S_StartSIdentify()
1126 {
1127 	BOOL idok;
1128 	int i;
1129 
1130 	idok = FALSE;
1131 	stextsize = true;
1132 	storenumh = 0;
1133 
1134 	for (i = 0; i < 48; i++)
1135 		storehold[i]._itype = ITYPE_NONE;
1136 
1137 	if (IdItemOk(&plr[myplr].InvBody[INVLOC_HEAD])) {
1138 		idok = TRUE;
1139 		AddStoreHoldId(plr[myplr].InvBody[INVLOC_HEAD], -1);
1140 	}
1141 	if (IdItemOk(&plr[myplr].InvBody[INVLOC_CHEST])) {
1142 		idok = TRUE;
1143 		AddStoreHoldId(plr[myplr].InvBody[INVLOC_CHEST], -2);
1144 	}
1145 	if (IdItemOk(&plr[myplr].InvBody[INVLOC_HAND_LEFT])) {
1146 		idok = TRUE;
1147 		AddStoreHoldId(plr[myplr].InvBody[INVLOC_HAND_LEFT], -3);
1148 	}
1149 	if (IdItemOk(&plr[myplr].InvBody[INVLOC_HAND_RIGHT])) {
1150 		idok = TRUE;
1151 		AddStoreHoldId(plr[myplr].InvBody[INVLOC_HAND_RIGHT], -4);
1152 	}
1153 	if (IdItemOk(&plr[myplr].InvBody[INVLOC_RING_LEFT])) {
1154 		idok = TRUE;
1155 		AddStoreHoldId(plr[myplr].InvBody[INVLOC_RING_LEFT], -5);
1156 	}
1157 	if (IdItemOk(&plr[myplr].InvBody[INVLOC_RING_RIGHT])) {
1158 		idok = TRUE;
1159 		AddStoreHoldId(plr[myplr].InvBody[INVLOC_RING_RIGHT], -6);
1160 	}
1161 	if (IdItemOk(&plr[myplr].InvBody[INVLOC_AMULET])) {
1162 		idok = TRUE;
1163 		AddStoreHoldId(plr[myplr].InvBody[INVLOC_AMULET], -7);
1164 	}
1165 
1166 	for (i = 0; i < plr[myplr]._pNumInv; i++) {
1167 		if (storenumh >= 48)
1168 			break;
1169 		if (IdItemOk(&plr[myplr].InvList[i])) {
1170 			idok = TRUE;
1171 			AddStoreHoldId(plr[myplr].InvList[i], i);
1172 		}
1173 	}
1174 
1175 	if (!idok) {
1176 		stextscrl = false;
1177 		sprintf(tempstr, "You have nothing to identify.             Your gold: %i", plr[myplr]._pGold);
1178 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
1179 		AddSLine(3);
1180 		AddSLine(21);
1181 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
1182 		OffsetSTextY(22, 6);
1183 	} else {
1184 		stextscrl = true;
1185 		stextsval = 0;
1186 		stextsmax = plr[myplr]._pNumInv;
1187 		sprintf(tempstr, "Identify which item?             Your gold: %i", plr[myplr]._pGold);
1188 		AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE);
1189 		AddSLine(3);
1190 		AddSLine(21);
1191 		S_ScrollSSell(stextsval);
1192 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
1193 		OffsetSTextY(22, 6);
1194 	}
1195 }
1196 
S_StartIdShow()1197 void S_StartIdShow()
1198 {
1199 	StartStore(stextshold);
1200 	stextscrl = false;
1201 	ClearSText(5, 23);
1202 	text_color iclr = COL_WHITE;
1203 
1204 	if (plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL)
1205 		iclr = COL_BLUE;
1206 	if (!plr[myplr].HoldItem._iStatFlag)
1207 		iclr = COL_RED;
1208 
1209 	AddSText(0, 7, TRUE, "This item is:", COL_WHITE, FALSE);
1210 	AddSText(20, 11, FALSE, plr[myplr].HoldItem._iIName, iclr, FALSE);
1211 	PrintStoreItem(&plr[myplr].HoldItem, 12, iclr);
1212 	AddSText(0, 18, TRUE, "Done", COL_WHITE, TRUE);
1213 }
1214 
S_StartTalk()1215 void S_StartTalk()
1216 {
1217 	int i, sn, sn2, la;
1218 
1219 	stextsize = false;
1220 	stextscrl = false;
1221 	sprintf(tempstr, "Talk to %s", talkname[talker]);
1222 	AddSText(0, 2, TRUE, tempstr, COL_GOLD, FALSE);
1223 	AddSLine(5);
1224 	if (gbIsSpawn) {
1225 		sprintf(tempstr, "Talking to %s", talkname[talker]);
1226 		AddSText(0, 10, TRUE, tempstr, COL_WHITE, FALSE);
1227 		AddSText(0, 12, TRUE, "is not available", COL_WHITE, FALSE);
1228 		AddSText(0, 14, TRUE, "in the shareware", COL_WHITE, FALSE);
1229 		AddSText(0, 16, TRUE, "version", COL_WHITE, FALSE);
1230 		AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
1231 		return;
1232 	}
1233 
1234 	sn = 0;
1235 	for (i = 0; i < MAXQUESTS; i++) {
1236 		if (quests[i]._qactive == QUEST_ACTIVE && Qtalklist[talker][i] != TEXT_NONE && quests[i]._qlog)
1237 			sn++;
1238 	}
1239 
1240 	if (sn > 6) {
1241 		sn = 14 - (sn >> 1);
1242 		la = 1;
1243 	} else {
1244 		sn = 15 - sn;
1245 		la = 2;
1246 	}
1247 
1248 	sn2 = sn - 2;
1249 
1250 	for (i = 0; i < MAXQUESTS; i++) {
1251 		if (quests[i]._qactive == QUEST_ACTIVE && Qtalklist[talker][i] != TEXT_NONE && quests[i]._qlog) {
1252 			AddSText(0, sn, TRUE, questlist[i]._qlstr, COL_WHITE, TRUE);
1253 			sn += la;
1254 		}
1255 	}
1256 	AddSText(0, sn2, TRUE, "Gossip", COL_BLUE, TRUE);
1257 	AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE);
1258 }
1259 
S_StartTavern()1260 void S_StartTavern()
1261 {
1262 	stextsize = false;
1263 	stextscrl = false;
1264 	AddSText(0, 1, TRUE, "Welcome to the", COL_GOLD, FALSE);
1265 	AddSText(0, 3, TRUE, "Rising Sun", COL_GOLD, FALSE);
1266 	AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE);
1267 	AddSText(0, 12, TRUE, "Talk to Ogden", COL_BLUE, TRUE);
1268 	AddSText(0, 18, TRUE, "Leave the tavern", COL_WHITE, TRUE);
1269 	AddSLine(5);
1270 	storenumh = 20;
1271 }
1272 
S_StartBarMaid()1273 void S_StartBarMaid()
1274 {
1275 	stextsize = false;
1276 	stextscrl = false;
1277 	AddSText(0, 2, TRUE, "Gillian", COL_GOLD, FALSE);
1278 	AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE);
1279 	AddSText(0, 12, TRUE, "Talk to Gillian", COL_BLUE, TRUE);
1280 	AddSText(0, 18, TRUE, "Say goodbye", COL_WHITE, TRUE);
1281 	AddSLine(5);
1282 	storenumh = 20;
1283 }
1284 
S_StartDrunk()1285 void S_StartDrunk()
1286 {
1287 	stextsize = false;
1288 	stextscrl = false;
1289 	AddSText(0, 2, TRUE, "Farnham the Drunk", COL_GOLD, FALSE);
1290 	AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE);
1291 	AddSText(0, 12, TRUE, "Talk to Farnham", COL_BLUE, TRUE);
1292 	AddSText(0, 18, TRUE, "Say Goodbye", COL_WHITE, TRUE);
1293 	AddSLine(5);
1294 	storenumh = 20;
1295 }
1296 
S_SmithEnter()1297 void S_SmithEnter()
1298 {
1299 	switch (stextsel) {
1300 	case 10:
1301 		talker = TOWN_SMITH;
1302 		stextlhold = 10;
1303 		stextshold = STORE_SMITH;
1304 		gossipstart = TEXT_GRISWOLD2;
1305 		gossipend = TEXT_GRISWOLD13;
1306 		StartStore(STORE_GOSSIP);
1307 		break;
1308 	case 12:
1309 		StartStore(STORE_SBUY);
1310 		break;
1311 	case 14:
1312 		StartStore(STORE_SPBUY);
1313 		break;
1314 	case 16:
1315 		StartStore(STORE_SSELL);
1316 		break;
1317 	case 18:
1318 		StartStore(STORE_SREPAIR);
1319 		break;
1320 	case 20:
1321 		stextflag = STORE_NONE;
1322 		break;
1323 	}
1324 }
1325 
1326 /**
1327  * @brief Purchases an item from the smith.
1328  */
SmithBuyItem()1329 void SmithBuyItem()
1330 {
1331 	int idx;
1332 
1333 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1334 	if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_NORMAL)
1335 		plr[myplr].HoldItem._iIdentified = FALSE;
1336 	StoreAutoPlace();
1337 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1338 	if (idx == SMITH_ITEMS - 1) {
1339 		smithitem[SMITH_ITEMS - 1]._itype = ITYPE_NONE;
1340 	} else {
1341 		for (; !smithitem[idx + 1].isEmpty(); idx++) {
1342 			smithitem[idx] = smithitem[idx + 1];
1343 		}
1344 		smithitem[idx]._itype = ITYPE_NONE;
1345 	}
1346 	CalcPlrInv(myplr, TRUE);
1347 }
1348 
S_SBuyEnter()1349 void S_SBuyEnter()
1350 {
1351 	int idx, i;
1352 	BOOL done;
1353 
1354 	if (stextsel == 22) {
1355 		StartStore(STORE_SMITH);
1356 		stextsel = 12;
1357 	} else {
1358 		stextlhold = stextsel;
1359 		stextvhold = stextsval;
1360 		stextshold = STORE_SBUY;
1361 		idx = stextsval + ((stextsel - stextup) >> 2);
1362 		if (plr[myplr]._pGold < smithitem[idx]._iIvalue) {
1363 			StartStore(STORE_NOMONEY);
1364 		} else {
1365 			plr[myplr].HoldItem = smithitem[idx];
1366 			SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM);
1367 			done = FALSE;
1368 			if (AutoEquipEnabled(plr[myplr], plr[myplr].HoldItem) && AutoEquip(myplr, plr[myplr].HoldItem, false)) {
1369 				done = TRUE;
1370 			}
1371 
1372 			for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) {
1373 				done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE);
1374 			}
1375 			if (done)
1376 				StartStore(STORE_CONFIRM);
1377 			else
1378 				StartStore(STORE_NOROOM);
1379 			SetCursor_(CURSOR_HAND);
1380 		}
1381 	}
1382 }
1383 
1384 /**
1385  * @brief Purchases a premium item from the smith.
1386  */
SmithBuyPItem()1387 void SmithBuyPItem()
1388 {
1389 	int i, xx, idx;
1390 
1391 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1392 	if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_NORMAL)
1393 		plr[myplr].HoldItem._iIdentified = FALSE;
1394 	StoreAutoPlace();
1395 
1396 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1397 	xx = 0;
1398 	for (i = 0; idx >= 0; i++) {
1399 		if (!premiumitem[i].isEmpty()) {
1400 			idx--;
1401 			xx = i;
1402 		}
1403 	}
1404 
1405 	premiumitem[xx]._itype = ITYPE_NONE;
1406 	numpremium--;
1407 	SpawnPremium(myplr);
1408 }
1409 
S_SPBuyEnter()1410 void S_SPBuyEnter()
1411 {
1412 	int i, idx, xx;
1413 	BOOL done;
1414 
1415 	if (stextsel == 22) {
1416 		StartStore(STORE_SMITH);
1417 		stextsel = 14;
1418 	} else {
1419 		stextshold = STORE_SPBUY;
1420 		stextlhold = stextsel;
1421 		stextvhold = stextsval;
1422 		xx = stextsval + ((stextsel - stextup) >> 2);
1423 		idx = 0;
1424 		for (i = 0; xx >= 0; i++) {
1425 			if (!premiumitem[i].isEmpty()) {
1426 				xx--;
1427 				idx = i;
1428 			}
1429 		}
1430 		if (plr[myplr]._pGold < premiumitem[idx]._iIvalue) {
1431 			StartStore(STORE_NOMONEY);
1432 		} else {
1433 			plr[myplr].HoldItem = premiumitem[idx];
1434 			SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM);
1435 			done = FALSE;
1436 			if (AutoEquipEnabled(plr[myplr], plr[myplr].HoldItem) && AutoEquip(myplr, plr[myplr].HoldItem, false)) {
1437 				done = TRUE;
1438 			}
1439 
1440 			for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) {
1441 				done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE);
1442 			}
1443 			if (done)
1444 				StartStore(STORE_CONFIRM);
1445 			else
1446 				StartStore(STORE_NOROOM);
1447 			SetCursor_(CURSOR_HAND);
1448 		}
1449 	}
1450 }
1451 
StoreGoldFit(int idx)1452 BOOL StoreGoldFit(int idx)
1453 {
1454 	int i, sz, cost, numsqrs;
1455 
1456 	cost = storehold[idx]._iIvalue;
1457 	sz = cost / MaxGold;
1458 	if (cost % MaxGold != 0)
1459 		sz++;
1460 
1461 	SetCursor_(storehold[idx]._iCurs + CURSOR_FIRSTITEM);
1462 	numsqrs = cursW / 28 * (cursH / 28);
1463 	SetCursor_(CURSOR_HAND);
1464 
1465 	if (numsqrs >= sz)
1466 		return TRUE;
1467 
1468 	for (i = 0; i < NUM_INV_GRID_ELEM; i++) {
1469 		if (plr[myplr].InvGrid[i] == 0)
1470 			numsqrs++;
1471 	}
1472 
1473 	for (i = 0; i < plr[myplr]._pNumInv; i++) {
1474 		if (plr[myplr].InvList[i]._itype == ITYPE_GOLD && plr[myplr].InvList[i]._ivalue != MaxGold) {
1475 			if (cost + plr[myplr].InvList[i]._ivalue <= MaxGold)
1476 				cost = 0;
1477 			else
1478 				cost -= MaxGold - plr[myplr].InvList[i]._ivalue;
1479 		}
1480 	}
1481 
1482 	sz = cost / MaxGold;
1483 	if (cost % MaxGold)
1484 		sz++;
1485 
1486 	return numsqrs >= sz;
1487 }
1488 
1489 /**
1490  * @brief Add gold pile to the players invetory
1491  * @param v The value of the gold pile
1492  */
PlaceStoreGold(int v)1493 void PlaceStoreGold(int v)
1494 {
1495 	BOOL done;
1496 	int ii, xx, yy, i;
1497 
1498 	done = FALSE;
1499 
1500 	for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) {
1501 		yy = 10 * (i / 10);
1502 		xx = i % 10;
1503 		if (plr[myplr].InvGrid[xx + yy] == 0) {
1504 			ii = plr[myplr]._pNumInv;
1505 			GetGoldSeed(myplr, &golditem);
1506 			plr[myplr].InvList[ii] = golditem;
1507 			plr[myplr]._pNumInv++;
1508 			plr[myplr].InvGrid[xx + yy] = plr[myplr]._pNumInv;
1509 			plr[myplr].InvList[ii]._ivalue = v;
1510 			SetGoldCurs(myplr, ii);
1511 			done = TRUE;
1512 		}
1513 	}
1514 }
1515 
1516 /**
1517  * @brief Sells an item from the player's inventory or belt.
1518  */
StoreSellItem()1519 void StoreSellItem()
1520 {
1521 	int i, idx, cost;
1522 
1523 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1524 	if (storehidx[idx] >= 0)
1525 		RemoveInvItem(myplr, storehidx[idx]);
1526 	else
1527 		RemoveSpdBarItem(myplr, -(storehidx[idx] + 1));
1528 	cost = storehold[idx]._iIvalue;
1529 	storenumh--;
1530 	if (idx != storenumh) {
1531 		while (idx < storenumh) {
1532 			storehold[idx] = storehold[idx + 1];
1533 			storehidx[idx] = storehidx[idx + 1];
1534 			idx++;
1535 		}
1536 	}
1537 	plr[myplr]._pGold += cost;
1538 	for (i = 0; i < plr[myplr]._pNumInv && cost > 0; i++) {
1539 		if (plr[myplr].InvList[i]._itype == ITYPE_GOLD && plr[myplr].InvList[i]._ivalue != MaxGold) {
1540 			if (cost + plr[myplr].InvList[i]._ivalue <= MaxGold) {
1541 				plr[myplr].InvList[i]._ivalue += cost;
1542 				SetGoldCurs(myplr, i);
1543 				cost = 0;
1544 			} else {
1545 				cost -= MaxGold - plr[myplr].InvList[i]._ivalue;
1546 				plr[myplr].InvList[i]._ivalue = MaxGold;
1547 				SetGoldCurs(myplr, i);
1548 			}
1549 		}
1550 	}
1551 	if (cost > 0) {
1552 		while (cost > MaxGold) {
1553 			PlaceStoreGold(MaxGold);
1554 			cost -= MaxGold;
1555 		}
1556 		PlaceStoreGold(cost);
1557 	}
1558 }
1559 
S_SSellEnter()1560 void S_SSellEnter()
1561 {
1562 	int idx;
1563 
1564 	if (stextsel == 22) {
1565 		StartStore(STORE_SMITH);
1566 		stextsel = 16;
1567 	} else {
1568 		stextlhold = stextsel;
1569 		idx = stextsval + ((stextsel - stextup) >> 2);
1570 		stextshold = STORE_SSELL;
1571 		stextvhold = stextsval;
1572 		plr[myplr].HoldItem = storehold[idx];
1573 
1574 		if (StoreGoldFit(idx))
1575 			StartStore(STORE_CONFIRM);
1576 		else
1577 			StartStore(STORE_NOROOM);
1578 	}
1579 }
1580 
1581 /**
1582  * @brief Repairs an item in the player's inventory or body in the smith.
1583  */
SmithRepairItem()1584 void SmithRepairItem()
1585 {
1586 	int i, idx;
1587 
1588 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1589 
1590 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1591 	storehold[idx]._iDurability = storehold[idx]._iMaxDur;
1592 
1593 	i = storehidx[idx];
1594 	if (i < 0) {
1595 		if (i == -1)
1596 			plr[myplr].InvBody[INVLOC_HEAD]._iDurability = plr[myplr].InvBody[INVLOC_HEAD]._iMaxDur;
1597 		if (i == -2)
1598 			plr[myplr].InvBody[INVLOC_CHEST]._iDurability = plr[myplr].InvBody[INVLOC_CHEST]._iMaxDur;
1599 		if (i == -3)
1600 			plr[myplr].InvBody[INVLOC_HAND_LEFT]._iDurability = plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxDur;
1601 		if (i == -4)
1602 			plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iDurability = plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iMaxDur;
1603 	} else {
1604 		plr[myplr].InvList[i]._iDurability = plr[myplr].InvList[i]._iMaxDur;
1605 	}
1606 }
1607 
S_SRepairEnter()1608 void S_SRepairEnter()
1609 {
1610 	int idx;
1611 
1612 	if (stextsel == 22) {
1613 		StartStore(STORE_SMITH);
1614 		stextsel = 18;
1615 	} else {
1616 		stextshold = STORE_SREPAIR;
1617 		stextlhold = stextsel;
1618 		stextvhold = stextsval;
1619 		idx = stextsval + ((stextsel - stextup) >> 2);
1620 		plr[myplr].HoldItem = storehold[idx];
1621 		if (plr[myplr]._pGold < storehold[idx]._iIvalue)
1622 			StartStore(STORE_NOMONEY);
1623 		else
1624 			StartStore(STORE_CONFIRM);
1625 	}
1626 }
1627 
S_WitchEnter()1628 void S_WitchEnter()
1629 {
1630 	switch (stextsel) {
1631 	case 12:
1632 		stextlhold = 12;
1633 		talker = TOWN_WITCH;
1634 		stextshold = STORE_WITCH;
1635 		gossipstart = TEXT_ADRIA2;
1636 		gossipend = TEXT_ADRIA13;
1637 		StartStore(STORE_GOSSIP);
1638 		return;
1639 	case 14:
1640 		StartStore(STORE_WBUY);
1641 		return;
1642 	case 16:
1643 		StartStore(STORE_WSELL);
1644 		return;
1645 	case 18:
1646 		StartStore(STORE_WRECHARGE);
1647 		return;
1648 	case 20:
1649 		stextflag = STORE_NONE;
1650 		break;
1651 	}
1652 }
1653 
1654 /**
1655  * @brief Purchases an item from the witch.
1656  */
WitchBuyItem()1657 void WitchBuyItem()
1658 {
1659 	int idx;
1660 
1661 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1662 
1663 	if (idx < 3)
1664 		plr[myplr].HoldItem._iSeed = AdvanceRndSeed();
1665 
1666 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1667 	StoreAutoPlace();
1668 
1669 	if (idx >= 3) {
1670 		if (idx == WITCH_ITEMS - 1) {
1671 			witchitem[WITCH_ITEMS - 1]._itype = ITYPE_NONE;
1672 		} else {
1673 			for (; !witchitem[idx + 1].isEmpty(); idx++) {
1674 				witchitem[idx] = witchitem[idx + 1];
1675 			}
1676 			witchitem[idx]._itype = ITYPE_NONE;
1677 		}
1678 	}
1679 
1680 	CalcPlrInv(myplr, TRUE);
1681 }
1682 
S_WBuyEnter()1683 void S_WBuyEnter()
1684 {
1685 	int i, idx;
1686 	BOOL done;
1687 
1688 	if (stextsel == 22) {
1689 		StartStore(STORE_WITCH);
1690 		stextsel = 14;
1691 	} else {
1692 		stextlhold = stextsel;
1693 		stextvhold = stextsval;
1694 		stextshold = STORE_WBUY;
1695 		idx = stextsval + ((stextsel - stextup) >> 2);
1696 
1697 		if (plr[myplr]._pGold < witchitem[idx]._iIvalue) {
1698 			StartStore(STORE_NOMONEY);
1699 		} else {
1700 			plr[myplr].HoldItem = witchitem[idx];
1701 			SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM);
1702 			done = FALSE;
1703 			if (AutoEquipEnabled(plr[myplr], plr[myplr].HoldItem) && AutoEquip(myplr, plr[myplr].HoldItem, false)) {
1704 				done = TRUE;
1705 			}
1706 
1707 			for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) {
1708 				done = SpecialAutoPlace(myplr, i, plr[myplr].HoldItem);
1709 			}
1710 
1711 			if (done)
1712 				StartStore(STORE_CONFIRM);
1713 			else
1714 				StartStore(STORE_NOROOM);
1715 
1716 			SetCursor_(CURSOR_HAND);
1717 		}
1718 	}
1719 }
1720 
S_WSellEnter()1721 void S_WSellEnter()
1722 {
1723 	int idx;
1724 
1725 	if (stextsel == 22) {
1726 		StartStore(STORE_WITCH);
1727 		stextsel = 16;
1728 	} else {
1729 		stextlhold = stextsel;
1730 		idx = stextsval + ((stextsel - stextup) >> 2);
1731 		stextshold = STORE_WSELL;
1732 		stextvhold = stextsval;
1733 		plr[myplr].HoldItem = storehold[idx];
1734 		if (StoreGoldFit(idx))
1735 			StartStore(STORE_CONFIRM);
1736 		else
1737 			StartStore(STORE_NOROOM);
1738 	}
1739 }
1740 
1741 /**
1742  * @brief Recharges an item in the player's inventory or body in the witch.
1743  */
WitchRechargeItem()1744 void WitchRechargeItem()
1745 {
1746 	int i, idx;
1747 
1748 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1749 
1750 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1751 	storehold[idx]._iCharges = storehold[idx]._iMaxCharges;
1752 
1753 	i = storehidx[idx];
1754 	if (i < 0)
1755 		plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges = plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxCharges;
1756 	else
1757 		plr[myplr].InvList[i]._iCharges = plr[myplr].InvList[i]._iMaxCharges;
1758 
1759 	CalcPlrInv(myplr, TRUE);
1760 }
1761 
S_WRechargeEnter()1762 void S_WRechargeEnter()
1763 {
1764 	int idx;
1765 
1766 	if (stextsel == 22) {
1767 		StartStore(STORE_WITCH);
1768 		stextsel = 18;
1769 	} else {
1770 		stextshold = STORE_WRECHARGE;
1771 		stextlhold = stextsel;
1772 		stextvhold = stextsval;
1773 		idx = stextsval + ((stextsel - stextup) >> 2);
1774 		plr[myplr].HoldItem = storehold[idx];
1775 		if (plr[myplr]._pGold < storehold[idx]._iIvalue)
1776 			StartStore(STORE_NOMONEY);
1777 		else
1778 			StartStore(STORE_CONFIRM);
1779 	}
1780 }
1781 
S_BoyEnter()1782 void S_BoyEnter()
1783 {
1784 	if (!boyitem.isEmpty() && stextsel == 18) {
1785 		if (plr[myplr]._pGold < 50) {
1786 			stextshold = STORE_BOY;
1787 			stextlhold = 18;
1788 			stextvhold = stextsval;
1789 			StartStore(STORE_NOMONEY);
1790 		} else {
1791 			TakePlrsMoney(50);
1792 			StartStore(STORE_BBOY);
1793 		}
1794 	} else if ((stextsel == 8 && !boyitem.isEmpty()) || (stextsel == 12 && boyitem.isEmpty())) {
1795 		talker = TOWN_PEGBOY;
1796 		stextshold = STORE_BOY;
1797 		stextlhold = stextsel;
1798 		gossipstart = TEXT_WIRT2;
1799 		gossipend = TEXT_WIRT12;
1800 		StartStore(STORE_GOSSIP);
1801 	} else {
1802 		stextflag = STORE_NONE;
1803 	}
1804 }
1805 
BoyBuyItem()1806 void BoyBuyItem()
1807 {
1808 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1809 	StoreAutoPlace();
1810 	boyitem._itype = ITYPE_NONE;
1811 	stextshold = STORE_BOY;
1812 	CalcPlrInv(myplr, TRUE);
1813 	stextlhold = 12;
1814 }
1815 
1816 /**
1817  * @brief Purchases an item from the healer.
1818  */
HealerBuyItem()1819 void HealerBuyItem()
1820 {
1821 	int idx;
1822 
1823 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1824 	if (!gbIsMultiplayer) {
1825 		if (idx < 2)
1826 			plr[myplr].HoldItem._iSeed = AdvanceRndSeed();
1827 	} else {
1828 		if (idx < 3)
1829 			plr[myplr].HoldItem._iSeed = AdvanceRndSeed();
1830 	}
1831 
1832 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1833 	if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_NORMAL)
1834 		plr[myplr].HoldItem._iIdentified = FALSE;
1835 	StoreAutoPlace();
1836 
1837 	if (!gbIsMultiplayer) {
1838 		if (idx < 2)
1839 			return;
1840 	} else {
1841 		if (idx < 3)
1842 			return;
1843 	}
1844 	idx = stextvhold + ((stextlhold - stextup) >> 2);
1845 	if (idx == 19) {
1846 		healitem[19]._itype = ITYPE_NONE;
1847 	} else {
1848 		for (; !healitem[idx + 1].isEmpty(); idx++) {
1849 			healitem[idx] = healitem[idx + 1];
1850 		}
1851 		healitem[idx]._itype = ITYPE_NONE;
1852 	}
1853 	CalcPlrInv(myplr, TRUE);
1854 }
1855 
S_BBuyEnter()1856 void S_BBuyEnter()
1857 {
1858 	if (stextsel != 10) {
1859 		stextflag = STORE_NONE;
1860 		return;
1861 	}
1862 
1863 	stextshold = STORE_BBOY;
1864 	stextvhold = stextsval;
1865 	stextlhold = 10;
1866 	int price = boyitem._iIvalue;
1867 	if (gbIsHellfire)
1868 		price -= boyitem._iIvalue >> 2;
1869 	else
1870 		price += boyitem._iIvalue >> 1;
1871 
1872 	if (plr[myplr]._pGold < price) {
1873 		StartStore(STORE_NOMONEY);
1874 		return;
1875 	}
1876 
1877 	plr[myplr].HoldItem = boyitem;
1878 	plr[myplr].HoldItem._iIvalue = price;
1879 	SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM);
1880 
1881 	bool done = false;
1882 	if (AutoEquipEnabled(plr[myplr], plr[myplr].HoldItem) && AutoEquip(myplr, plr[myplr].HoldItem, false)) {
1883 		done = true;
1884 	}
1885 
1886 	for (int i = 0; i < NUM_INV_GRID_ELEM && !done; i++) {
1887 		done = AutoPlace(myplr, i, cursW / 28, cursH / 28, false);
1888 	}
1889 
1890 	StartStore(done ? STORE_CONFIRM : STORE_NOROOM);
1891 
1892 	SetCursor_(CURSOR_HAND);
1893 }
1894 
StoryIdItem()1895 void StoryIdItem()
1896 {
1897 	int idx;
1898 
1899 	idx = storehidx[((stextlhold - stextup) >> 2) + stextvhold];
1900 	if (idx < 0) {
1901 		if (idx == -1)
1902 			plr[myplr].InvBody[INVLOC_HEAD]._iIdentified = TRUE;
1903 		if (idx == -2)
1904 			plr[myplr].InvBody[INVLOC_CHEST]._iIdentified = TRUE;
1905 		if (idx == -3)
1906 			plr[myplr].InvBody[INVLOC_HAND_LEFT]._iIdentified = TRUE;
1907 		if (idx == -4)
1908 			plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iIdentified = TRUE;
1909 		if (idx == -5)
1910 			plr[myplr].InvBody[INVLOC_RING_LEFT]._iIdentified = TRUE;
1911 		if (idx == -6)
1912 			plr[myplr].InvBody[INVLOC_RING_RIGHT]._iIdentified = TRUE;
1913 		if (idx == -7)
1914 			plr[myplr].InvBody[INVLOC_AMULET]._iIdentified = TRUE;
1915 	} else {
1916 		plr[myplr].InvList[idx]._iIdentified = TRUE;
1917 	}
1918 	plr[myplr].HoldItem._iIdentified = TRUE;
1919 	TakePlrsMoney(plr[myplr].HoldItem._iIvalue);
1920 	CalcPlrInv(myplr, TRUE);
1921 }
1922 
S_ConfirmEnter()1923 void S_ConfirmEnter()
1924 {
1925 	if (stextsel == 18) {
1926 		switch (stextshold) {
1927 		case STORE_SBUY:
1928 			SmithBuyItem();
1929 			break;
1930 		case STORE_SSELL:
1931 		case STORE_WSELL:
1932 			StoreSellItem();
1933 			break;
1934 		case STORE_SREPAIR:
1935 			SmithRepairItem();
1936 			break;
1937 		case STORE_WBUY:
1938 			WitchBuyItem();
1939 			break;
1940 		case STORE_WRECHARGE:
1941 			WitchRechargeItem();
1942 			break;
1943 		case STORE_BBOY:
1944 			BoyBuyItem();
1945 			break;
1946 		case STORE_HBUY:
1947 			HealerBuyItem();
1948 			break;
1949 		case STORE_SIDENTIFY:
1950 			StoryIdItem();
1951 			StartStore(STORE_IDSHOW);
1952 			return;
1953 		case STORE_SPBUY:
1954 			SmithBuyPItem();
1955 			break;
1956 		default:
1957 			break;
1958 		}
1959 	}
1960 
1961 	StartStore(stextshold);
1962 
1963 	if (stextsel == 22)
1964 		return;
1965 
1966 	stextsel = stextlhold;
1967 	stextsval = std::min(stextvhold, stextsmax);
1968 
1969 	while (stextsel != -1 && !stext[stextsel]._ssel) {
1970 		stextsel--;
1971 	}
1972 }
1973 
S_HealerEnter()1974 void S_HealerEnter()
1975 {
1976 	switch (stextsel) {
1977 	case 12:
1978 		stextlhold = 12;
1979 		talker = TOWN_HEALER;
1980 		stextshold = STORE_HEALER;
1981 		gossipstart = TEXT_PEPIN2;
1982 		gossipend = TEXT_PEPIN11;
1983 		StartStore(STORE_GOSSIP);
1984 		break;
1985 	case 14:
1986 		StartStore(STORE_HBUY);
1987 		break;
1988 	case 16:
1989 		stextflag = STORE_NONE;
1990 		break;
1991 	}
1992 }
1993 
S_HBuyEnter()1994 void S_HBuyEnter()
1995 {
1996 	int i, idx;
1997 	BOOL done;
1998 
1999 	if (stextsel == 22) {
2000 		StartStore(STORE_HEALER);
2001 		stextsel = 16;
2002 	} else {
2003 		stextlhold = stextsel;
2004 		stextvhold = stextsval;
2005 		stextshold = STORE_HBUY;
2006 		idx = stextsval + ((stextsel - stextup) >> 2);
2007 
2008 		if (plr[myplr]._pGold < healitem[idx]._iIvalue) {
2009 			StartStore(STORE_NOMONEY);
2010 		} else {
2011 			plr[myplr].HoldItem = healitem[idx];
2012 			SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM);
2013 			done = FALSE;
2014 			if (AutoEquipEnabled(plr[myplr], plr[myplr].HoldItem) && AutoEquip(myplr, plr[myplr].HoldItem, false)) {
2015 				done = TRUE;
2016 			}
2017 
2018 			for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) {
2019 				done = SpecialAutoPlace(myplr, i, plr[myplr].HoldItem);
2020 			}
2021 
2022 			if (done)
2023 				StartStore(STORE_CONFIRM);
2024 			else
2025 				StartStore(STORE_NOROOM);
2026 
2027 			SetCursor_(CURSOR_HAND);
2028 		}
2029 	}
2030 }
2031 
S_StoryEnter()2032 void S_StoryEnter()
2033 {
2034 	switch (stextsel) {
2035 	case 12:
2036 		stextlhold = 12;
2037 		talker = TOWN_STORY;
2038 		stextshold = STORE_STORY;
2039 		gossipstart = TEXT_STORY2;
2040 		gossipend = TEXT_STORY11;
2041 		StartStore(STORE_GOSSIP);
2042 		break;
2043 	case 14:
2044 		StartStore(STORE_SIDENTIFY);
2045 		break;
2046 	case 18:
2047 		stextflag = STORE_NONE;
2048 		break;
2049 	}
2050 }
2051 
S_SIDEnter()2052 void S_SIDEnter()
2053 {
2054 	int idx;
2055 
2056 	if (stextsel == 22) {
2057 		StartStore(STORE_STORY);
2058 		stextsel = 14;
2059 	} else {
2060 		stextshold = STORE_SIDENTIFY;
2061 		stextlhold = stextsel;
2062 		stextvhold = stextsval;
2063 		idx = stextsval + ((stextsel - stextup) >> 2);
2064 		plr[myplr].HoldItem = storehold[idx];
2065 		if (plr[myplr]._pGold < storehold[idx]._iIvalue)
2066 			StartStore(STORE_NOMONEY);
2067 		else
2068 			StartStore(STORE_CONFIRM);
2069 	}
2070 }
2071 
S_TalkEnter()2072 void S_TalkEnter()
2073 {
2074 	int i, tq, sn, la;
2075 
2076 	if (stextsel == 22) {
2077 		StartStore(stextshold);
2078 		stextsel = stextlhold;
2079 		return;
2080 	}
2081 
2082 	sn = 0;
2083 	for (i = 0; i < MAXQUESTS; i++) {
2084 		if (quests[i]._qactive == QUEST_ACTIVE && Qtalklist[talker][i] != TEXT_NONE && quests[i]._qlog)
2085 			sn++;
2086 	}
2087 	if (sn > 6) {
2088 		sn = 14 - (sn >> 1);
2089 		la = 1;
2090 	} else {
2091 		sn = 15 - sn;
2092 		la = 2;
2093 	}
2094 
2095 	if (stextsel == sn - 2) {
2096 		SetRndSeed(towner[talker]._tSeed);
2097 		tq = gossipstart + random_(0, gossipend - gossipstart + 1);
2098 		InitQTextMsg(tq);
2099 		return;
2100 	}
2101 
2102 	for (i = 0; i < MAXQUESTS; i++) {
2103 		if (quests[i]._qactive == QUEST_ACTIVE && Qtalklist[talker][i] != TEXT_NONE && quests[i]._qlog) {
2104 			if (sn == stextsel) {
2105 				InitQTextMsg(Qtalklist[talker][i]);
2106 			}
2107 			sn += la;
2108 		}
2109 	}
2110 }
2111 
S_TavernEnter()2112 void S_TavernEnter()
2113 {
2114 	switch (stextsel) {
2115 	case 12:
2116 		stextlhold = 12;
2117 		talker = TOWN_TAVERN;
2118 		stextshold = STORE_TAVERN;
2119 		gossipstart = TEXT_OGDEN2;
2120 		gossipend = TEXT_OGDEN10;
2121 		StartStore(STORE_GOSSIP);
2122 		break;
2123 	case 18:
2124 		stextflag = STORE_NONE;
2125 		break;
2126 	}
2127 }
2128 
S_BarmaidEnter()2129 void S_BarmaidEnter()
2130 {
2131 	switch (stextsel) {
2132 	case 12:
2133 		stextlhold = 12;
2134 		talker = TOWN_BMAID;
2135 		stextshold = STORE_BARMAID;
2136 		gossipstart = TEXT_GILLIAN2;
2137 		gossipend = TEXT_GILLIAN10;
2138 		StartStore(STORE_GOSSIP);
2139 		break;
2140 	case 18:
2141 		stextflag = STORE_NONE;
2142 		break;
2143 	}
2144 }
2145 
S_DrunkEnter()2146 void S_DrunkEnter()
2147 {
2148 	switch (stextsel) {
2149 	case 12:
2150 		stextlhold = 12;
2151 		talker = TOWN_DRUNK;
2152 		stextshold = STORE_DRUNK;
2153 		gossipstart = TEXT_FARNHAM2;
2154 		gossipend = TEXT_FARNHAM13;
2155 		StartStore(STORE_GOSSIP);
2156 		break;
2157 	case 18:
2158 		stextflag = STORE_NONE;
2159 		break;
2160 	}
2161 }
2162 
2163 }
2164 
2165 ItemStruct golditem;
2166 
2167 Uint8 *pSTextBoxCels;
2168 Uint8 *pSPentSpn2Cels;
2169 Uint8 *pSTextSlidCels;
2170 
2171 talk_id stextflag;
2172 
2173 int storenumh;
2174 char storehidx[48];
2175 ItemStruct storehold[48];
2176 
2177 ItemStruct smithitem[SMITH_ITEMS];
2178 int numpremium;
2179 int premiumlevel;
2180 ItemStruct premiumitem[SMITH_PREMIUM_ITEMS];
2181 
2182 ItemStruct healitem[20];
2183 
2184 ItemStruct witchitem[WITCH_ITEMS];
2185 
2186 int boylevel;
2187 ItemStruct boyitem;
2188 
AddStoreHoldRepair(ItemStruct * itm,int i)2189 void AddStoreHoldRepair(ItemStruct *itm, int i)
2190 {
2191 	ItemStruct *item;
2192 	int v;
2193 
2194 	item = &storehold[storenumh];
2195 	storehold[storenumh] = *itm;
2196 
2197 	int due = item->_iMaxDur - item->_iDurability;
2198 	if (item->_iMagical != ITEM_QUALITY_NORMAL && item->_iIdentified) {
2199 		v = 30 * item->_iIvalue * due / (item->_iMaxDur * 100 * 2);
2200 		if (v == 0)
2201 			return;
2202 	} else {
2203 		v = item->_ivalue * due / (item->_iMaxDur * 2);
2204 		v = std::max(v, 1);
2205 	}
2206 	item->_iIvalue = v;
2207 	item->_ivalue = v;
2208 	storehidx[storenumh] = i;
2209 	storenumh++;
2210 }
2211 
InitStores()2212 void InitStores()
2213 {
2214 	pSTextBoxCels = LoadFileInMem("Data\\TextBox2.CEL", NULL);
2215 	pSPentSpn2Cels = LoadFileInMem("Data\\PentSpn2.CEL", NULL);
2216 	pSTextSlidCels = LoadFileInMem("Data\\TextSlid.CEL", NULL);
2217 	ClearSText(0, STORE_LINES);
2218 	stextflag = STORE_NONE;
2219 	stextsize = false;
2220 	stextscrl = false;
2221 	numpremium = 0;
2222 	premiumlevel = 1;
2223 
2224 	for (int i = 0; i < SMITH_PREMIUM_ITEMS; i++)
2225 		premiumitem[i]._itype = ITYPE_NONE;
2226 
2227 	boyitem._itype = ITYPE_NONE;
2228 	boylevel = 0;
2229 }
2230 
PentSpn2Spin()2231 int PentSpn2Spin()
2232 {
2233 	return (SDL_GetTicks() / 50) % 8 + 1;
2234 }
2235 
SetupTownStores()2236 void SetupTownStores()
2237 {
2238 	int i, l;
2239 
2240 	SetRndSeed(glSeedTbl[currlevel] * SDL_GetTicks());
2241 	if (!gbIsMultiplayer) {
2242 		l = 0;
2243 		for (i = 0; i < NUMLEVELS; i++) {
2244 			if (plr[myplr]._pLvlVisited[i])
2245 				l = i;
2246 		}
2247 	} else {
2248 		l = plr[myplr]._pLevel >> 1;
2249 	}
2250 	l += 2;
2251 	if (l < 6)
2252 		l = 6;
2253 	if (l > 16)
2254 		l = 16;
2255 	SpawnStoreGold();
2256 	SpawnSmith(l);
2257 	SpawnWitch(l);
2258 	SpawnHealer(l);
2259 	SpawnBoy(plr[myplr]._pLevel);
2260 	SpawnPremium(myplr);
2261 }
2262 
FreeStoreMem()2263 void FreeStoreMem()
2264 {
2265 	MemFreeDbg(pSTextBoxCels);
2266 	MemFreeDbg(pSPentSpn2Cels);
2267 	MemFreeDbg(pSTextSlidCels);
2268 }
2269 
PrintSString(CelOutputBuffer out,int x,int y,bool cjustflag,const char * str,text_color col,int val)2270 void PrintSString(CelOutputBuffer out, int x, int y, bool cjustflag, const char *str, text_color col, int val)
2271 {
2272 	int len, width, sx, sy, i, k, s;
2273 	int xx, yy;
2274 	BYTE c;
2275 	char valstr[32];
2276 
2277 	s = y * 12 + stext[y]._syoff;
2278 	if (stextsize)
2279 		xx = PANEL_X + 32;
2280 	else
2281 		xx = PANEL_X + 352;
2282 	sx = xx + x;
2283 	sy = s + 44 + UI_OFFSET_Y;
2284 	len = strlen(str);
2285 	if (stextsize)
2286 		yy = 577;
2287 	else
2288 		yy = 257;
2289 	k = 0;
2290 	if (cjustflag) {
2291 		width = 0;
2292 		for (i = 0; i < len; i++)
2293 			width += fontkern[fontframe[gbFontTransTbl[(BYTE)str[i]]]] + 1;
2294 		if (width < yy)
2295 			k = (yy - width) >> 1;
2296 		sx += k;
2297 	}
2298 	if (stextsel == y) {
2299 		CelDrawTo(out, cjustflag ? xx + x + k - 20 : xx + x - 20, s + 45 + UI_OFFSET_Y, pSPentSpn2Cels, PentSpn2Spin(), 12);
2300 	}
2301 	for (i = 0; i < len; i++) {
2302 		c = fontframe[gbFontTransTbl[(BYTE)str[i]]];
2303 		k += fontkern[c] + 1;
2304 		if (c != 0 && k <= yy) {
2305 			PrintChar(out, sx, sy, c, col);
2306 		}
2307 		sx += fontkern[c] + 1;
2308 	}
2309 	if (!cjustflag && val >= 0) {
2310 		sprintf(valstr, "%i", val);
2311 		sx = PANEL_X + 592 - x;
2312 		len = strlen(valstr);
2313 		for (i = len - 1; i >= 0; i--) {
2314 			c = fontframe[gbFontTransTbl[(BYTE)valstr[i]]];
2315 			sx -= fontkern[c] + 1;
2316 			if (c != 0) {
2317 				PrintChar(out, sx, sy, c, col);
2318 			}
2319 		}
2320 	}
2321 	if (stextsel == y) {
2322 		CelDrawTo(out, cjustflag ? (xx + x + k + 4) : (PANEL_X + 596 - x), s + 45 + UI_OFFSET_Y, pSPentSpn2Cels, PentSpn2Spin(), 12);
2323 	}
2324 }
2325 
DrawSLine(CelOutputBuffer out,int y)2326 void DrawSLine(CelOutputBuffer out, int y)
2327 {
2328 	const int sy = y * 12;
2329 	BYTE *src, *dst;
2330 	int width;
2331 	if (stextsize) {
2332 		src = out.at(PANEL_LEFT + 26, 25 + UI_OFFSET_Y);
2333 		dst = out.at(26 + PANEL_X, sy + 38 + UI_OFFSET_Y);
2334 		width = 587; // BUGFIX: should be 587, not 586 (fixed)
2335 	} else {
2336 		src = out.at(PANEL_LEFT + 346, 25 + UI_OFFSET_Y);
2337 		dst = out.at(346 + PANEL_X, sy + 38 + UI_OFFSET_Y);
2338 		width = 267; // BUGFIX: should be 267, not 266 (fixed)
2339 	}
2340 
2341 	for (int i = 0; i < 3; i++, src += out.pitch(), dst += out.pitch())
2342 		memcpy(dst, src, width);
2343 }
2344 
DrawSTextHelp()2345 void DrawSTextHelp()
2346 {
2347 	stextsel = -1;
2348 	stextsize = true;
2349 }
2350 
ClearSText(int s,int e)2351 void ClearSText(int s, int e)
2352 {
2353 	int i;
2354 
2355 	for (i = s; i < e; i++) {
2356 		stext[i]._sx = 0;
2357 		stext[i]._syoff = 0;
2358 		stext[i]._sstr[0] = 0;
2359 		stext[i]._sjust = false;
2360 		stext[i]._sclr = COL_WHITE;
2361 		stext[i]._sline = 0;
2362 		stext[i]._ssel = FALSE;
2363 		stext[i]._sval = -1;
2364 	}
2365 }
2366 
StartStore(talk_id s)2367 void StartStore(talk_id s)
2368 {
2369 	sbookflag = FALSE;
2370 	invflag = FALSE;
2371 	chrflag = FALSE;
2372 	questlog = FALSE;
2373 	dropGoldFlag = FALSE;
2374 	ClearSText(0, STORE_LINES);
2375 	ReleaseStoreBtn();
2376 	switch (s) {
2377 	case STORE_SMITH:
2378 		S_StartSmith();
2379 		break;
2380 	case STORE_SBUY:
2381 		if (storenumh > 0)
2382 			S_StartSBuy();
2383 		else
2384 			S_StartSmith();
2385 		break;
2386 	case STORE_SSELL:
2387 		S_StartSSell();
2388 		break;
2389 	case STORE_SREPAIR:
2390 		S_StartSRepair();
2391 		break;
2392 	case STORE_WITCH:
2393 		S_StartWitch();
2394 		break;
2395 	case STORE_WBUY:
2396 		if (storenumh > 0)
2397 			S_StartWBuy();
2398 		break;
2399 	case STORE_WSELL:
2400 		S_StartWSell();
2401 		break;
2402 	case STORE_WRECHARGE:
2403 		S_StartWRecharge();
2404 		break;
2405 	case STORE_NOMONEY:
2406 		S_StartNoMoney();
2407 		break;
2408 	case STORE_NOROOM:
2409 		S_StartNoRoom();
2410 		break;
2411 	case STORE_CONFIRM:
2412 		S_StartConfirm();
2413 		break;
2414 	case STORE_BOY:
2415 		S_StartBoy();
2416 		break;
2417 	case STORE_BBOY:
2418 		S_StartBBoy();
2419 		break;
2420 	case STORE_HEALER:
2421 		S_StartHealer();
2422 		break;
2423 	case STORE_STORY:
2424 		S_StartStory();
2425 		break;
2426 	case STORE_HBUY:
2427 		if (storenumh > 0)
2428 			S_StartHBuy();
2429 		break;
2430 	case STORE_SIDENTIFY:
2431 		S_StartSIdentify();
2432 		break;
2433 	case STORE_SPBUY:
2434 		if (!S_StartSPBuy())
2435 			return;
2436 		break;
2437 	case STORE_GOSSIP:
2438 		S_StartTalk();
2439 		break;
2440 	case STORE_IDSHOW:
2441 		S_StartIdShow();
2442 		break;
2443 	case STORE_TAVERN:
2444 		S_StartTavern();
2445 		break;
2446 	case STORE_DRUNK:
2447 		S_StartDrunk();
2448 		break;
2449 	case STORE_BARMAID:
2450 		S_StartBarMaid();
2451 		break;
2452 	case STORE_NONE:
2453 		break;
2454 	}
2455 
2456 	stextsel = -1;
2457 	for (int i = 0; i < STORE_LINES; i++) {
2458 		if (stext[i]._ssel) {
2459 			stextsel = i;
2460 			break;
2461 		}
2462 	}
2463 
2464 	stextflag = s;
2465 }
2466 
DrawSText(CelOutputBuffer out)2467 void DrawSText(CelOutputBuffer out)
2468 {
2469 	int i;
2470 
2471 	if (!stextsize)
2472 		DrawSTextBack(out);
2473 	else
2474 		DrawQTextBack(out);
2475 
2476 	if (stextscrl) {
2477 		switch (stextflag) {
2478 		case STORE_SBUY:
2479 			S_ScrollSBuy(stextsval);
2480 			break;
2481 		case STORE_SSELL:
2482 		case STORE_SREPAIR:
2483 		case STORE_WSELL:
2484 		case STORE_WRECHARGE:
2485 		case STORE_SIDENTIFY:
2486 			S_ScrollSSell(stextsval);
2487 			break;
2488 		case STORE_WBUY:
2489 			S_ScrollWBuy(stextsval);
2490 			break;
2491 		case STORE_HBUY:
2492 			S_ScrollHBuy(stextsval);
2493 			break;
2494 		case STORE_SPBUY:
2495 			S_ScrollSPBuy(stextsval);
2496 			break;
2497 		default:
2498 			break;
2499 		}
2500 	}
2501 
2502 	for (i = 0; i < STORE_LINES; i++) {
2503 		if (stext[i]._sline)
2504 			DrawSLine(out, i);
2505 		if (stext[i]._sstr[0])
2506 			PrintSString(out, stext[i]._sx, i, stext[i]._sjust, stext[i]._sstr, stext[i]._sclr, stext[i]._sval);
2507 	}
2508 
2509 	if (stextscrl)
2510 		DrawSSlider(out, 4, 20);
2511 }
2512 
STextESC()2513 void STextESC()
2514 {
2515 	if (qtextflag) {
2516 		qtextflag = FALSE;
2517 		if (leveltype == DTYPE_TOWN)
2518 			stream_stop();
2519 	} else {
2520 		switch (stextflag) {
2521 		case STORE_SMITH:
2522 		case STORE_WITCH:
2523 		case STORE_BOY:
2524 		case STORE_BBOY:
2525 		case STORE_HEALER:
2526 		case STORE_STORY:
2527 		case STORE_TAVERN:
2528 		case STORE_DRUNK:
2529 		case STORE_BARMAID:
2530 			stextflag = STORE_NONE;
2531 			break;
2532 		case STORE_GOSSIP:
2533 			StartStore(stextshold);
2534 			stextsel = stextlhold;
2535 			break;
2536 		case STORE_SBUY:
2537 			StartStore(STORE_SMITH);
2538 			stextsel = 12;
2539 			break;
2540 		case STORE_SPBUY:
2541 			StartStore(STORE_SMITH);
2542 			stextsel = 14;
2543 			break;
2544 		case STORE_SSELL:
2545 			StartStore(STORE_SMITH);
2546 			stextsel = 16;
2547 			break;
2548 		case STORE_SREPAIR:
2549 			StartStore(STORE_SMITH);
2550 			stextsel = 18;
2551 			break;
2552 		case STORE_WBUY:
2553 			StartStore(STORE_WITCH);
2554 			stextsel = 14;
2555 			break;
2556 		case STORE_WSELL:
2557 			StartStore(STORE_WITCH);
2558 			stextsel = 16;
2559 			break;
2560 		case STORE_WRECHARGE:
2561 			StartStore(STORE_WITCH);
2562 			stextsel = 18;
2563 			break;
2564 		case STORE_HBUY:
2565 			StartStore(STORE_HEALER);
2566 			stextsel = 16;
2567 			break;
2568 		case STORE_SIDENTIFY:
2569 			StartStore(STORE_STORY);
2570 			stextsel = 14;
2571 			break;
2572 		case STORE_IDSHOW:
2573 			StartStore(STORE_SIDENTIFY);
2574 			break;
2575 		case STORE_NOMONEY:
2576 		case STORE_NOROOM:
2577 		case STORE_CONFIRM:
2578 			StartStore(stextshold);
2579 			stextsel = stextlhold;
2580 			stextsval = stextvhold;
2581 			break;
2582 		case STORE_NONE:
2583 			break;
2584 		}
2585 	}
2586 }
2587 
STextUp()2588 void STextUp()
2589 {
2590 	PlaySFX(IS_TITLEMOV);
2591 	if (stextsel == -1) {
2592 		return;
2593 	}
2594 
2595 	if (stextscrl) {
2596 		if (stextsel == stextup) {
2597 			if (stextsval)
2598 				stextsval--;
2599 			return;
2600 		}
2601 
2602 		stextsel--;
2603 		while (!stext[stextsel]._ssel) {
2604 			if (!stextsel)
2605 				stextsel = STORE_LINES - 1;
2606 			else
2607 				stextsel--;
2608 		}
2609 		return;
2610 	}
2611 
2612 	if (!stextsel)
2613 		stextsel = STORE_LINES - 1;
2614 	else
2615 		stextsel--;
2616 
2617 	while (!stext[stextsel]._ssel) {
2618 		if (!stextsel)
2619 			stextsel = STORE_LINES - 1;
2620 		else
2621 			stextsel--;
2622 	}
2623 }
2624 
STextDown()2625 void STextDown()
2626 {
2627 	PlaySFX(IS_TITLEMOV);
2628 	if (stextsel == -1) {
2629 		return;
2630 	}
2631 
2632 	if (stextscrl) {
2633 		if (stextsel == stextdown) {
2634 			if (stextsval < stextsmax)
2635 				stextsval++;
2636 			return;
2637 		}
2638 
2639 		stextsel++;
2640 		while (!stext[stextsel]._ssel) {
2641 			if (stextsel == STORE_LINES - 1)
2642 				stextsel = 0;
2643 			else
2644 				stextsel++;
2645 		}
2646 		return;
2647 	}
2648 
2649 	if (stextsel == STORE_LINES - 1)
2650 		stextsel = 0;
2651 	else
2652 		stextsel++;
2653 
2654 	while (!stext[stextsel]._ssel) {
2655 		if (stextsel == STORE_LINES - 1)
2656 			stextsel = 0;
2657 		else
2658 			stextsel++;
2659 	}
2660 }
2661 
STextPrior()2662 void STextPrior()
2663 {
2664 	PlaySFX(IS_TITLEMOV);
2665 	if (stextsel != -1 && stextscrl) {
2666 		if (stextsel == stextup) {
2667 			if (stextsval)
2668 				stextsval -= 4;
2669 			stextsval = stextsval;
2670 			if (stextsval < 0)
2671 				stextsval = 0;
2672 		} else {
2673 			stextsel = stextup;
2674 		}
2675 	}
2676 }
2677 
STextNext()2678 void STextNext()
2679 {
2680 	PlaySFX(IS_TITLEMOV);
2681 	if (stextsel != -1 && stextscrl) {
2682 		if (stextsel == stextdown) {
2683 			if (stextsval < stextsmax)
2684 				stextsval += 4;
2685 			if (stextsval > stextsmax)
2686 				stextsval = stextsmax;
2687 		} else {
2688 			stextsel = stextdown;
2689 		}
2690 	}
2691 }
2692 
SetGoldCurs(int pnum,int i)2693 void SetGoldCurs(int pnum, int i)
2694 {
2695 	SetPlrHandGoldCurs(&plr[pnum].InvList[i]);
2696 }
2697 
SetSpdbarGoldCurs(int pnum,int i)2698 void SetSpdbarGoldCurs(int pnum, int i)
2699 {
2700 	SetPlrHandGoldCurs(&plr[pnum].SpdList[i]);
2701 }
2702 
TakePlrsMoney(int cost)2703 void TakePlrsMoney(int cost)
2704 {
2705 	int i;
2706 
2707 	plr[myplr]._pGold = CalculateGold(myplr) - cost;
2708 	for (i = 0; i < MAXBELTITEMS && cost > 0; i++) {
2709 		if (plr[myplr].SpdList[i]._itype == ITYPE_GOLD && plr[myplr].SpdList[i]._ivalue != MaxGold) {
2710 			if (cost < plr[myplr].SpdList[i]._ivalue) {
2711 				plr[myplr].SpdList[i]._ivalue -= cost;
2712 				SetSpdbarGoldCurs(myplr, i);
2713 				cost = 0;
2714 			} else {
2715 				cost -= plr[myplr].SpdList[i]._ivalue;
2716 				RemoveSpdBarItem(myplr, i);
2717 				i = -1;
2718 			}
2719 		}
2720 	}
2721 	if (cost > 0) {
2722 		for (i = 0; i < MAXBELTITEMS && cost > 0; i++) {
2723 			if (plr[myplr].SpdList[i]._itype == ITYPE_GOLD) {
2724 				if (cost < plr[myplr].SpdList[i]._ivalue) {
2725 					plr[myplr].SpdList[i]._ivalue -= cost;
2726 					SetSpdbarGoldCurs(myplr, i);
2727 					cost = 0;
2728 				} else {
2729 					cost -= plr[myplr].SpdList[i]._ivalue;
2730 					RemoveSpdBarItem(myplr, i);
2731 					i = -1;
2732 				}
2733 			}
2734 		}
2735 	}
2736 	force_redraw = 255;
2737 	if (cost > 0) {
2738 		for (i = 0; i < plr[myplr]._pNumInv && cost > 0; i++) {
2739 			if (plr[myplr].InvList[i]._itype == ITYPE_GOLD && plr[myplr].InvList[i]._ivalue != MaxGold) {
2740 				if (cost < plr[myplr].InvList[i]._ivalue) {
2741 					plr[myplr].InvList[i]._ivalue -= cost;
2742 					SetGoldCurs(myplr, i);
2743 					cost = 0;
2744 				} else {
2745 					cost -= plr[myplr].InvList[i]._ivalue;
2746 					RemoveInvItem(myplr, i);
2747 					i = -1;
2748 				}
2749 			}
2750 		}
2751 		if (cost > 0) {
2752 			for (i = 0; i < plr[myplr]._pNumInv && cost > 0; i++) {
2753 				if (plr[myplr].InvList[i]._itype == ITYPE_GOLD) {
2754 					if (cost < plr[myplr].InvList[i]._ivalue) {
2755 						plr[myplr].InvList[i]._ivalue -= cost;
2756 						SetGoldCurs(myplr, i);
2757 						cost = 0;
2758 					} else {
2759 						cost -= plr[myplr].InvList[i]._ivalue;
2760 						RemoveInvItem(myplr, i);
2761 						i = -1;
2762 					}
2763 				}
2764 			}
2765 		}
2766 	}
2767 }
2768 
STextEnter()2769 void STextEnter()
2770 {
2771 	if (qtextflag) {
2772 		qtextflag = FALSE;
2773 		if (leveltype == DTYPE_TOWN)
2774 			stream_stop();
2775 
2776 		return;
2777 	}
2778 
2779 	PlaySFX(IS_TITLSLCT);
2780 	switch (stextflag) {
2781 	case STORE_SMITH:
2782 		S_SmithEnter();
2783 		break;
2784 	case STORE_SPBUY:
2785 		S_SPBuyEnter();
2786 		break;
2787 	case STORE_SBUY:
2788 		S_SBuyEnter();
2789 		break;
2790 	case STORE_SSELL:
2791 		S_SSellEnter();
2792 		break;
2793 	case STORE_SREPAIR:
2794 		S_SRepairEnter();
2795 		break;
2796 	case STORE_WITCH:
2797 		S_WitchEnter();
2798 		break;
2799 	case STORE_WBUY:
2800 		S_WBuyEnter();
2801 		break;
2802 	case STORE_WSELL:
2803 		S_WSellEnter();
2804 		break;
2805 	case STORE_WRECHARGE:
2806 		S_WRechargeEnter();
2807 		break;
2808 	case STORE_NOMONEY:
2809 	case STORE_NOROOM:
2810 		StartStore(stextshold);
2811 		stextsel = stextlhold;
2812 		stextsval = stextvhold;
2813 		break;
2814 	case STORE_CONFIRM:
2815 		S_ConfirmEnter();
2816 		break;
2817 	case STORE_BOY:
2818 		S_BoyEnter();
2819 		break;
2820 	case STORE_BBOY:
2821 		S_BBuyEnter();
2822 		break;
2823 	case STORE_HEALER:
2824 		S_HealerEnter();
2825 		break;
2826 	case STORE_STORY:
2827 		S_StoryEnter();
2828 		break;
2829 	case STORE_HBUY:
2830 		S_HBuyEnter();
2831 		break;
2832 	case STORE_SIDENTIFY:
2833 		S_SIDEnter();
2834 		break;
2835 	case STORE_GOSSIP:
2836 		S_TalkEnter();
2837 		break;
2838 	case STORE_IDSHOW:
2839 		StartStore(STORE_SIDENTIFY);
2840 		break;
2841 	case STORE_DRUNK:
2842 		S_DrunkEnter();
2843 		break;
2844 	case STORE_TAVERN:
2845 		S_TavernEnter();
2846 		break;
2847 	case STORE_BARMAID:
2848 		S_BarmaidEnter();
2849 		break;
2850 	case STORE_NONE:
2851 		break;
2852 	}
2853 }
2854 
CheckStoreBtn()2855 void CheckStoreBtn()
2856 {
2857 	int y;
2858 
2859 	if (qtextflag) {
2860 		qtextflag = FALSE;
2861 		if (leveltype == DTYPE_TOWN)
2862 			stream_stop();
2863 	} else if (stextsel != -1 && MouseY >= (32 + UI_OFFSET_Y) && MouseY <= (320 + UI_OFFSET_Y)) {
2864 		if (!stextsize) {
2865 			if (MouseX < 344 + PANEL_LEFT || MouseX > 616 + PANEL_LEFT)
2866 				return;
2867 		} else {
2868 			if (MouseX < 24 + PANEL_LEFT || MouseX > 616 + PANEL_LEFT)
2869 				return;
2870 		}
2871 		y = (MouseY - (32 + UI_OFFSET_Y)) / 12;
2872 		if (stextscrl && MouseX > 600 + PANEL_LEFT) {
2873 			if (y == 4) {
2874 				if (stextscrlubtn <= 0) {
2875 					STextUp();
2876 					stextscrlubtn = 10;
2877 				} else {
2878 					stextscrlubtn--;
2879 				}
2880 			}
2881 			if (y == 20) {
2882 				if (stextscrldbtn <= 0) {
2883 					STextDown();
2884 					stextscrldbtn = 10;
2885 				} else {
2886 					stextscrldbtn--;
2887 				}
2888 			}
2889 		} else if (y >= 5) {
2890 			if (y >= 23)
2891 				y = 22;
2892 			if (stextscrl && y < 21 && !stext[y]._ssel) {
2893 				if (stext[y - 2]._ssel) {
2894 					y -= 2;
2895 				} else if (stext[y - 1]._ssel) {
2896 					y--;
2897 				}
2898 			}
2899 			if (stext[y]._ssel || (stextscrl && y == 22)) {
2900 				stextsel = y;
2901 				STextEnter();
2902 			}
2903 		}
2904 	}
2905 }
2906 
ReleaseStoreBtn()2907 void ReleaseStoreBtn()
2908 {
2909 	stextscrlubtn = -1;
2910 	stextscrldbtn = -1;
2911 }
2912 
2913 DEVILUTION_END_NAMESPACE
2914