1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: updatecharactersheet.cpp
5 	Desc: contains updateCharacterSheet()
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 "../player.hpp"
18 #include "../colors.hpp"
19 #include "interface.hpp"
20 #include "../sound.hpp"
21 #include "../magic/magic.hpp"
22 #include "../menu.hpp"
23 #include "../net.hpp"
24 #include "../scores.hpp"
25 
26 void statsHoverText(Stat* tmpStat);
27 
28 /*-------------------------------------------------------------------------------
29 
30 	updateCharacterSheet
31 
32 	Draws the character sheet and processes all interaction with it
33 
34 -------------------------------------------------------------------------------*/
35 
updateCharacterSheet()36 void updateCharacterSheet()
37 {
38 	int i = 0;
39 	int x = 0;
40 	SDL_Rect pos;
41 	bool b = false;
42 	node_t* node = NULL;
43 	Entity* entity = NULL;
44 	Item* item = NULL;
45 	int c;
46 
47 	// draw window
48 	pos.x = 8;
49 	pos.y = 8;
50 	pos.w = 208;
51 	pos.h = 180;
52 	//drawImage(character_bmp, NULL, &pos);
53 	//pos.x=0; pos.y=196;
54 	//pos.w=222; pos.h=392-196;
55 	//drawTooltip(&pos);
56 	int statWindowY = 196;
57 	int statWindowY2 = 404;
58 	if ( uiscale_charactersheet )
59 	{
60 		pos.h = 236;
61 		pos.w = 276;
62 		statWindowY = pos.h + 16;
63 		statWindowY2 = 554;
64 	}
65 
66 
67 	drawWindowFancy(0, 0, pos.w + 16, pos.h + 16);
68 	drawRect(&pos, 0, 255);
69 	drawWindowFancy(0, pos.h + 16, pos.w + 16, statWindowY2);
70 
71 	interfaceCharacterSheet.x = pos.x - 8;
72 	interfaceCharacterSheet.y = pos.y - 8;
73 	interfaceCharacterSheet.w = pos.w + 16;
74 	interfaceCharacterSheet.h = statWindowY2;
75 
76 	// character sheet
77 	double ofov = fov;
78 	fov = 50;
79 	if (players[clientnum] != nullptr && players[clientnum]->entity != nullptr)
80 	{
81 		if (!softwaremode)
82 		{
83 			glClear(GL_DEPTH_BUFFER_BIT);
84 		}
85 		//TODO: These two NOT PLAYERSWAP
86 		//camera.x=players[clientnum]->x/16.0+.5*cos(players[clientnum]->yaw)-.4*sin(players[clientnum]->yaw);
87 		//camera.y=players[clientnum]->y/16.0+.5*sin(players[clientnum]->yaw)+.4*cos(players[clientnum]->yaw);
88 		camera_charsheet.x = players[clientnum]->entity->x / 16.0 + (.92 * cos(camera_charsheet_offsetyaw));
89 		camera_charsheet.y = players[clientnum]->entity->y / 16.0 + (.92 * sin(camera_charsheet_offsetyaw));
90 		camera_charsheet.z = players[clientnum]->entity->z * 2;
91 		//camera.ang=atan2(players[clientnum]->y/16.0-camera.y,players[clientnum]->x/16.0-camera.x); //TODO: _NOT_ PLAYERSWAP
92 		camera_charsheet.ang = (camera_charsheet_offsetyaw - PI); //5 * PI / 4;
93 		camera_charsheet.vang = PI / 20;
94 		camera_charsheet.winx = 8;
95 		camera_charsheet.winy = 8;
96 		camera_charsheet.winw = pos.w;
97 		camera_charsheet.winh = pos.h;
98 		b = players[clientnum]->entity->flags[BRIGHT];
99 		players[clientnum]->entity->flags[BRIGHT] = true;
100 		if ( !players[clientnum]->entity->flags[INVISIBLE] )
101 		{
102 			glDrawVoxel(&camera_charsheet, players[clientnum]->entity, REALCOLORS);
103 		}
104 		players[clientnum]->entity->flags[BRIGHT] = b;
105 		c = 0;
106 		if (multiplayer != CLIENT)
107 		{
108 			for (node = players[clientnum]->entity->children.first; node != nullptr; node = node->next)
109 			{
110 				if (c == 0)
111 				{
112 					c++;
113 					continue;
114 				}
115 				entity = (Entity*) node->element;
116 				if ( !entity->flags[INVISIBLE] )
117 				{
118 					b = entity->flags[BRIGHT];
119 					entity->flags[BRIGHT] = true;
120 					glDrawVoxel(&camera_charsheet, entity, REALCOLORS);
121 					entity->flags[BRIGHT] = b;
122 				}
123 				c++;
124 			}
125 			for ( node = map.entities->first; node != NULL; node = node->next )
126 			{
127 				entity = (Entity*) node->element;
128 				if ( (Sint32)entity->getUID() == -4 )
129 				{
130 					glDrawSprite(&camera_charsheet, entity, REALCOLORS);
131 				}
132 			}
133 		}
134 		else
135 		{
136 			for ( node = map.entities->first; node != NULL; node = node->next )
137 			{
138 				entity = (Entity*) node->element;
139 				if ( (entity->behavior == &actPlayerLimb && entity->skill[2] == clientnum && !entity->flags[INVISIBLE]) || (Sint32)entity->getUID() == -4 )
140 				{
141 					b = entity->flags[BRIGHT];
142 					entity->flags[BRIGHT] = true;
143 					if ( (Sint32)entity->getUID() == -4 )
144 					{
145 						glDrawSprite(&camera_charsheet, entity, REALCOLORS);
146 					}
147 					else
148 					{
149 						glDrawVoxel(&camera_charsheet, entity, REALCOLORS);
150 					}
151 					entity->flags[BRIGHT] = b;
152 				}
153 			}
154 		}
155 
156 		SDL_Rect rotateBtn;
157 		rotateBtn.w = 16;
158 		rotateBtn.h = 16;
159 		rotateBtn.x = camera_charsheet.winx + camera_charsheet.winw - rotateBtn.w;
160 		rotateBtn.y = camera_charsheet.winy + camera_charsheet.winh - rotateBtn.h;
161 		drawWindow(rotateBtn.x, rotateBtn.y, rotateBtn.x + rotateBtn.w, rotateBtn.y + rotateBtn.h);
162 		if ( mousestatus[SDL_BUTTON_LEFT] && !shootmode )
163 		{
164 			if ( mouseInBounds(rotateBtn.x, rotateBtn.x + rotateBtn.w, rotateBtn.y, rotateBtn.y + rotateBtn.h) )
165 			{
166 				camera_charsheet_offsetyaw += 0.05;
167 				if ( camera_charsheet_offsetyaw > 2 * PI )
168 				{
169 					camera_charsheet_offsetyaw -= 2 * PI;
170 				}
171 				drawDepressed(rotateBtn.x, rotateBtn.y, rotateBtn.x + rotateBtn.w, rotateBtn.y + rotateBtn.h);
172 			}
173 		}
174 		ttfPrintText(ttf12, rotateBtn.x + 2, rotateBtn.y + 2, ">");
175 
176 		rotateBtn.x = camera_charsheet.winx + camera_charsheet.winw - rotateBtn.w * 2 - 4;
177 		rotateBtn.y = camera_charsheet.winy + camera_charsheet.winh - rotateBtn.h;
178 		drawWindow(rotateBtn.x, rotateBtn.y, rotateBtn.x + rotateBtn.w, rotateBtn.y + rotateBtn.h);
179 		if ( mousestatus[SDL_BUTTON_LEFT] && !shootmode )
180 		{
181 			if ( mouseInBounds(rotateBtn.x, rotateBtn.x + rotateBtn.w, rotateBtn.y, rotateBtn.y + rotateBtn.h) )
182 			{
183 				camera_charsheet_offsetyaw -= 0.05;
184 				if ( camera_charsheet_offsetyaw < 0.f )
185 				{
186 					camera_charsheet_offsetyaw += 2 * PI;
187 				}
188 				drawDepressed(rotateBtn.x, rotateBtn.y, rotateBtn.x + rotateBtn.w, rotateBtn.y + rotateBtn.h);
189 			}
190 		}
191 		ttfPrintText(ttf12, rotateBtn.x, rotateBtn.y + 2, "<");
192 	}
193 	fov = ofov;
194 
195 	TTF_Font* fontStat = ttf12;
196 	int text_y = 0;
197 	int pad_y = 12;
198 	int fontWidth = TTF12_WIDTH;
199 	if ( uiscale_charactersheet )
200 	{
201 		fontStat = ttf16;
202 		pad_y = 18;
203 		fontWidth = TTF16_WIDTH;
204 	}
205 	text_y = statWindowY + 6;
206 	ttfPrintTextFormatted(fontStat, 8, text_y, "%s", stats[clientnum]->name);
207 	text_y += pad_y;
208 	ttfPrintTextFormatted(fontStat, 8, text_y, language[359], stats[clientnum]->LVL, playerClassLangEntry(client_classes[clientnum], clientnum));
209 	text_y += pad_y;
210 	ttfPrintTextFormatted(fontStat, 8, text_y, language[360], stats[clientnum]->EXP);
211 	text_y += pad_y;
212 	ttfPrintTextFormatted(fontStat, 8, text_y, language[361], currentlevel);
213 
214 	Entity* playerEntity = nullptr;
215 	if ( players[clientnum] )
216 	{
217 		playerEntity = players[clientnum]->entity;
218 	}
219 
220 	// attributes
221 	Sint32 statModifier = 0;
222 	char statText[64] = "";
223 	//Uint32 statColor = uint32ColorWhite(*mainsurface);
224 	text_y += pad_y * 2;
225 	snprintf(statText, 64, language[1200], stats[clientnum]->STR);
226 	ttfPrintTextFormatted(fontStat, 8, text_y, statText);
227 	printStatBonus(fontStat, stats[clientnum]->STR, statGetSTR(stats[clientnum], playerEntity), 8 + longestline(statText) * fontWidth, text_y);
228 
229 	text_y += pad_y;
230 	snprintf(statText, 64, language[1201], stats[clientnum]->DEX);
231 	ttfPrintTextFormatted(fontStat, 8, text_y, statText);
232 	printStatBonus(fontStat, stats[clientnum]->DEX, statGetDEX(stats[clientnum], playerEntity), 8 + longestline(statText) * fontWidth, text_y);
233 
234 	text_y += pad_y;
235 	snprintf(statText, 64, language[1202], stats[clientnum]->CON);
236 	ttfPrintTextFormatted(fontStat, 8, text_y, statText);
237 	printStatBonus(fontStat, stats[clientnum]->CON, statGetCON(stats[clientnum], playerEntity), 8 + longestline(statText) * fontWidth, text_y);
238 
239 	text_y += pad_y;
240 	snprintf(statText, 64, language[1203], stats[clientnum]->INT);
241 	ttfPrintTextFormatted(fontStat, 8, text_y, statText);
242 	printStatBonus(fontStat, stats[clientnum]->INT, statGetINT(stats[clientnum], playerEntity), 8 + longestline(statText) * fontWidth, text_y);
243 
244 	text_y += pad_y;
245 	snprintf(statText, 64, language[1204], stats[clientnum]->PER);
246 	ttfPrintTextFormatted(fontStat, 8, text_y, statText);
247 	printStatBonus(fontStat, stats[clientnum]->PER, statGetPER(stats[clientnum], playerEntity), 8 + longestline(statText) * fontWidth, text_y);
248 
249 	text_y += pad_y;
250 	snprintf(statText, 64, language[1205], stats[clientnum]->CHR);
251 	ttfPrintTextFormatted(fontStat, 8, text_y, statText);
252 	printStatBonus(fontStat, stats[clientnum]->CHR, statGetCHR(stats[clientnum], playerEntity), 8 + longestline(statText) * fontWidth, text_y);
253 
254 	// armor, gold, and weight
255 	int attackInfo[6] = { 0 };
256 	text_y += pad_y * 2;
257 	ttfPrintTextFormatted(fontStat, 8, text_y, language[2542], displayAttackPower(attackInfo));
258 
259 	text_y += pad_y;
260 	ttfPrintTextFormatted(fontStat, 8, text_y, language[371], AC(stats[clientnum]));
261 
262 	text_y += pad_y;
263 	ttfPrintTextFormatted(fontStat, 8, text_y, language[370], stats[clientnum]->GOLD);
264 	Uint32 weight = 0;
265 	for ( node = stats[clientnum]->inventory.first; node != NULL; node = node->next )
266 	{
267 		item = (Item*)node->element;
268 		int itemWeight = items[item->type].weight * item->count;
269 		if ( itemTypeIsQuiver(item->type) )
270 		{
271 			itemWeight = std::max(1, itemWeight / 5);
272 		}
273 		weight += itemWeight;
274 	}
275 	weight += stats[clientnum]->GOLD / 100;
276 	text_y += pad_y;
277 	ttfPrintTextFormatted(fontStat, 8, text_y, language[372], weight);
278 
279 	statsHoverText(stats[clientnum]);
280 	attackHoverText(attackInfo);
281 
282 	// gold hover text.
283 	SDL_Rect src;
284 	src.x = mousex + 16;
285 	src.y = mousey + 16;
286 	src.h = TTF12_HEIGHT + 8;
287 	src.w = ( longestline(language[2968]) + strlen(getInputName(impulses[IN_USE])) ) * TTF12_WIDTH + 4;
288 	if ( mouseInBounds(pos.x + 4, pos.x + pos.w, text_y - pad_y, text_y) )
289 	{
290 		drawTooltip(&src);
291 		ttfPrintTextFormatted(ttf12, src.x + 4, src.y + 6, language[2968], getInputName(impulses[IN_USE]));
292 		if ( *inputPressed(impulses[IN_USE]) )
293 		{
294 			consoleCommand("/dropgold");
295 			*inputPressed(impulses[IN_USE]) = 0;
296 		}
297 		else if ( *inputPressed(joyimpulses[INJOY_GAME_USE]) )
298 		{
299 			consoleCommand("/dropgold");
300 			*inputPressed(joyimpulses[INJOY_GAME_USE]) = 0;
301 		}
302 	}
303 }
304 
drawSkillsSheet()305 void drawSkillsSheet()
306 {
307 	SDL_Rect pos;
308 	pos.w = 208;
309 	pos.y = 32;
310 
311 	TTF_Font* fontSkill = ttf12;
312 	int fontHeight = TTF12_HEIGHT;
313 	int fontWidth = TTF12_WIDTH;
314 	if ( uiscale_skillspage )
315 	{
316 		fontSkill = ttf16;
317 		fontHeight = TTF16_HEIGHT;
318 		fontWidth = TTF16_WIDTH;
319 		pos.w = 276;
320 	}
321 	pos.x = xres - pos.w;
322 
323 
324 	pos.h = (NUMPROFICIENCIES * fontHeight) + (fontHeight * 3);
325 
326 	drawWindowFancy(pos.x, pos.y, pos.x + pos.w, pos.y + pos.h);
327 	interfaceSkillsSheet.x = pos.x;
328 	interfaceSkillsSheet.y = pos.y;
329 	interfaceSkillsSheet.w = pos.w;
330 	interfaceSkillsSheet.h = pos.h;
331 
332 	ttfPrintTextFormatted(fontSkill, pos.x + 4, pos.y + 8, language[1883]);
333 
334 	SDL_Rect button;
335 	button.x = xres - attributesright_bmp->w - 8;
336 	button.w = attributesright_bmp->w;
337 	button.y = pos.y;
338 	button.h = attributesright_bmp->h;
339 	if ( uiscale_skillspage )
340 	{
341 		button.w = attributesright_bmp->w * 1.3;
342 		button.x = xres - button.w - 8;
343 		button.y = pos.y;
344 		button.h = attributesright_bmp->h * 1.3;
345 	}
346 
347 	if ( mousestatus[SDL_BUTTON_LEFT] && !shootmode )
348 	{
349 		if ( omousex >= button.x && omousex <= button.x + button.w
350 			&& omousey >= button.y && omousey <= button.y + button.h )
351 		{
352 			buttonclick = 14;
353 			playSound(139, 64);
354 			if ( proficienciesPage == 0 )
355 			{
356 				proficienciesPage = 1;
357 			}
358 			else
359 			{
360 				proficienciesPage = 0;
361 			}
362 			mousestatus[SDL_BUTTON_LEFT] = 0;
363 		}
364 	}
365 	if ( buttonclick == 14 )
366 	{
367 		drawImageScaled(attributesright_bmp, nullptr, &button);
368 	}
369 	else
370 	{
371 		drawImageScaled(attributesrightunclicked_bmp, nullptr, &button);
372 	}
373 
374 	SDL_Rect lockbtn = button;
375 	lockbtn.h = 24;
376 	lockbtn.w = 24;
377 	lockbtn.y += 2;
378 	if ( uiscale_skillspage )
379 	{
380 		lockbtn.h = 24 * 1.3;
381 		lockbtn.w = 24 * 1.3;
382 		lockbtn.x -= 32 * 1.3;
383 	}
384 	else
385 	{
386 		lockbtn.x -= 32;
387 	}
388 	if ( lock_right_sidebar )
389 	{
390 		drawImageScaled(sidebar_lock_bmp, nullptr, &lockbtn);
391 	}
392 	else
393 	{
394 		drawImageScaled(sidebar_unlock_bmp, nullptr, &lockbtn);
395 	}
396 
397 	if ( mousestatus[SDL_BUTTON_LEFT] && !shootmode )
398 	{
399 		if ( omousex >= lockbtn.x && omousex <= lockbtn.x + lockbtn.w
400 			&& omousey >= lockbtn.y && omousey <= lockbtn.y + lockbtn.h )
401 		{
402 			playSound(139, 64);
403 			lock_right_sidebar = !lock_right_sidebar;
404 			mousestatus[SDL_BUTTON_LEFT] = 0;
405 		}
406 	}
407 
408 	pos.y += fontHeight * 2 + 8;
409 
410 	SDL_Rect initialSkillPos = pos;
411 	//Draw skill names.
412 	for ( int c = 0; c < (NUMPROFICIENCIES); ++c, pos.y += (fontHeight /** 2*/) )
413 	{
414 		ttfPrintTextFormatted(fontSkill, pos.x + 4, pos.y, "%s:", getSkillLangEntry(c));
415 	}
416 
417 	//Draw skill levels.
418 	pos = initialSkillPos;
419 	Uint32 color;
420 	for ( int i = 0; i < (NUMPROFICIENCIES); ++i, pos.y += (fontHeight /** 2*/) )
421 	{
422 		if ( skillCapstoneUnlocked(clientnum, i) )
423 		{
424 			color = uint32ColorGreen(*mainsurface);
425 		}
426 		else
427 		{
428 			color = uint32ColorWhite(*mainsurface);
429 		}
430 
431 
432 		if ( show_skill_values )
433 		{
434 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, "%15d / 100", stats[clientnum]->PROFICIENCIES[i]);
435 		}
436 		else if ( stats[clientnum]->PROFICIENCIES[i] == 0 )
437 		{
438 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, language[363]);
439 		}
440 		else if ( stats[clientnum]->PROFICIENCIES[i] < SKILL_LEVEL_BASIC )
441 		{
442 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, language[364]);
443 		}
444 		else if ( stats[clientnum]->PROFICIENCIES[i] >= SKILL_LEVEL_BASIC && stats[clientnum]->PROFICIENCIES[i] < SKILL_LEVEL_SKILLED )
445 		{
446 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, language[365]);
447 		}
448 		else if ( stats[clientnum]->PROFICIENCIES[i] >= SKILL_LEVEL_SKILLED && stats[clientnum]->PROFICIENCIES[i] < SKILL_LEVEL_EXPERT )
449 		{
450 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, language[366]);
451 		}
452 		else if ( stats[clientnum]->PROFICIENCIES[i] >= SKILL_LEVEL_EXPERT && stats[clientnum]->PROFICIENCIES[i] < SKILL_LEVEL_MASTER )
453 		{
454 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, language[367]);
455 		}
456 		else if ( stats[clientnum]->PROFICIENCIES[i] >= SKILL_LEVEL_MASTER && stats[clientnum]->PROFICIENCIES[i] < SKILL_LEVEL_LEGENDARY )
457 		{
458 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, language[368]);
459 		}
460 		else if ( stats[clientnum]->PROFICIENCIES[i] >= SKILL_LEVEL_LEGENDARY )
461 		{
462 			ttfPrintTextFormattedColor(fontSkill, pos.x + 4, pos.y, color, language[369]);
463 		}
464 	}
465 	pos = initialSkillPos;
466 	SDL_Rect skillTooltipRect;
467 	std::string skillTooltip;
468 	for ( int i = 0; !shootmode && i < (NUMPROFICIENCIES); ++i, pos.y += (fontHeight /** 2*/) )
469 	{
470 		if ( mouseInBounds(pos.x, pos.x + pos.w, pos.y, pos.y + fontHeight) && stats[clientnum] )
471 		{
472 			skillTooltipRect.w = (longestline(language[3255 + i]) * fontWidth) + 8;
473 			skillTooltip = language[3255 + i];
474 
475 			size_t n = std::count(skillTooltip.begin(), skillTooltip.end(), '\n'); // count newlines
476 			skillTooltipRect.h = fontHeight * (n + 2) + 8;
477 			skillTooltipRect.x = mousex - 16 - skillTooltipRect.w;
478 			skillTooltipRect.y = mousey + 16;
479 
480 			Uint32 capstoneTextColor = uint32ColorGray(*mainsurface);
481 			if ( skillCapstoneUnlocked(clientnum, i) )
482 			{
483 				capstoneTextColor = uint32ColorGreen(*mainsurface);
484 			}
485 
486 			switch ( i )
487 			{
488 				case PRO_LOCKPICKING:
489 					skillTooltipRect.h += 4 * fontHeight;
490 					drawTooltip(&skillTooltipRect);
491 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
492 						capstoneTextColor, language[3270], CAPSTONE_LOCKPICKING_CHEST_GOLD_AMOUNT);
493 					break;
494 				case PRO_STEALTH:
495 					skillTooltipRect.h += 4 * fontHeight + 4;
496 					drawTooltip(&skillTooltipRect);
497 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
498 						capstoneTextColor, language[3271]);
499 					break;
500 				case PRO_TRADING:
501 					skillTooltipRect.h += 2 * fontHeight;
502 					drawTooltip(&skillTooltipRect);
503 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
504 						capstoneTextColor, language[3272]);
505 					break;
506 				case PRO_APPRAISAL:
507 					skillTooltipRect.h += 2 * fontHeight;
508 					drawTooltip(&skillTooltipRect);
509 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
510 						capstoneTextColor, language[3273]);
511 					break;
512 				case PRO_SWIMMING:
513 					skillTooltipRect.h += fontHeight;
514 					drawTooltip(&skillTooltipRect);
515 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
516 						capstoneTextColor, language[3274]);
517 					break;
518 				case PRO_LEADERSHIP:
519 					skillTooltipRect.h += 2 * fontHeight + 4;
520 					drawTooltip(&skillTooltipRect);
521 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
522 						capstoneTextColor, language[3275]);
523 					break;
524 				case PRO_SPELLCASTING:
525 					skillTooltipRect.h += 2 * fontHeight;
526 					drawTooltip(&skillTooltipRect);
527 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
528 						capstoneTextColor, language[3276]);
529 					break;
530 				case PRO_MAGIC:
531 					break;
532 				case PRO_RANGED:
533 					skillTooltipRect.h += 2 * fontHeight + 4;
534 					drawTooltip(&skillTooltipRect);
535 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
536 						capstoneTextColor, language[3284]);
537 					break;
538 				case PRO_SWORD:
539 				{
540 					skillTooltipRect.h += 5 * fontHeight + 4;
541 					drawTooltip(&skillTooltipRect);
542 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
543 						capstoneTextColor, language[3278], language[3283]);
544 					break;
545 				}
546 				case PRO_MACE:
547 				{
548 					skillTooltipRect.h += 3 * fontHeight + 4;
549 					drawTooltip(&skillTooltipRect);
550 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
551 						capstoneTextColor, language[3279]);
552 					break;
553 				}
554 				case PRO_AXE:
555 				{
556 					skillTooltipRect.h += 3 * fontHeight + 4;
557 					drawTooltip(&skillTooltipRect);
558 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
559 						capstoneTextColor, language[3280]);
560 					break;
561 				}
562 				case PRO_POLEARM:
563 					skillTooltipRect.h += 3 * fontHeight + 4;
564 					drawTooltip(&skillTooltipRect);
565 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
566 						capstoneTextColor, language[3281]);
567 					break;
568 				case PRO_UNARMED:
569 					skillTooltipRect.h += 3 * fontHeight + 4;
570 					drawTooltip(&skillTooltipRect);
571 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
572 						capstoneTextColor, language[3282]);
573 					break;
574 				case PRO_SHIELD:
575 					skillTooltipRect.h += 2 * fontHeight;
576 					drawTooltip(&skillTooltipRect);
577 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16,
578 						capstoneTextColor, language[3283]);
579 					break;
580 				case PRO_ALCHEMY:
581 					skillTooltipRect.w = (longestline(language[3348]) * fontWidth) + 8;
582 					skillTooltipRect.x = mousex - 16 - skillTooltipRect.w;
583 					break;
584 				default:
585 					drawTooltip(&skillTooltipRect);
586 					break;
587 			}
588 
589 			Uint32 headerColor = uint32ColorBaronyBlue(*mainsurface);
590 			if ( skillCapstoneUnlocked(clientnum, i) )
591 			{
592 				headerColor = uint32ColorGreen(*mainsurface);
593 			}
594 
595 			if ( i != PRO_MAGIC && i != PRO_ALCHEMY )
596 			{
597 				ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 4, skillTooltipRect.y + 8,
598 					headerColor, "%s: (%d / 100)", getSkillLangEntry(i), stats[clientnum]->PROFICIENCIES[i]);
599 			}
600 
601 			real_t skillDetails[6] = { 0.f };
602 
603 			switch ( i )
604 			{
605 				case PRO_LOCKPICKING:
606 				{
607 					Sint32 PER = 0;
608 					if ( players[clientnum] && players[clientnum]->entity )
609 					{
610 						PER = statGetPER(stats[clientnum], players[clientnum]->entity);
611 					}
612 					statGetPER(stats[clientnum], players[clientnum]->entity);
613 					skillDetails[0] = stats[clientnum]->PROFICIENCIES[i] / 2.f; // lockpick chests/doors
614 					if ( stats[clientnum]->PROFICIENCIES[i] == SKILL_LEVEL_LEGENDARY )
615 					{
616 						skillDetails[0] = 100.f;
617 					}
618 					skillDetails[1] = std::min(100.f, stats[clientnum]->PROFICIENCIES[i] + 50.f);
619 					if ( stats[clientnum]->PROFICIENCIES[i] >= SKILL_LEVEL_EXPERT )
620 					{
621 						skillDetails[2] = 100.f; // lockpick automatons
622 					}
623 					else
624 					{
625 						skillDetails[2] = (100 - 100 / (static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20 + 1))); // lockpick automatons
626 					}
627 					skillDetails[3] = (100 - 100 / (std::max(1, static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 10)))); // disarm arrow traps
628 					if ( stats[clientnum]->PROFICIENCIES[i] < SKILL_LEVEL_BASIC )
629 					{
630 						skillDetails[3] = 0.f;
631 					}
632 					std::string canRepairItems = "  no";
633 					if ( (stats[clientnum]->PROFICIENCIES[i] + PER + (stats[clientnum]->type == AUTOMATON ? 20 : 0)) >= SKILL_LEVEL_LEGENDARY )
634 					{
635 						canRepairItems = "all";
636 					}
637 					else if ( (stats[clientnum]->PROFICIENCIES[i] + PER + (stats[clientnum]->type == AUTOMATON ? 20 : 0)) >= SKILL_LEVEL_MASTER )
638 					{
639 						canRepairItems = "2/0";
640 					}
641 					else if ( (stats[clientnum]->PROFICIENCIES[i] + PER + (stats[clientnum]->type == AUTOMATON ? 20 : 0)) >= SKILL_LEVEL_EXPERT )
642 					{
643 						canRepairItems = "1/0";
644 					}
645 					skillDetails[4] = maximumTinkeringBotsCanBeDeployed(stats[clientnum]);
646 
647 					// bonus scrapping chances.
648 					switch ( std::min(5, static_cast<int>((stats[clientnum]->PROFICIENCIES[i] + PER) / 20)) )
649 					{
650 						case 5:
651 							skillDetails[5] = 150.f;
652 							break;
653 						case 4:
654 							skillDetails[5] = 125.f;
655 							break;
656 						case 3:
657 							skillDetails[5] = 50.f;
658 							break;
659 						case 2:
660 							skillDetails[5] = 25.f;
661 							break;
662 						case 1:
663 							skillDetails[5] = 12.5;
664 							break;
665 						default:
666 							skillDetails[5] = 0.f;
667 							break;
668 					}
669 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
670 						uint32ColorWhite(*mainsurface), language[3255 + i],
671 						skillDetails[0], skillDetails[1], skillDetails[2], skillDetails[3], skillDetails[5], canRepairItems.c_str(), skillDetails[4], getInputName(impulses[IN_FOLLOWERMENU]));
672 					break;
673 				}
674 				case PRO_STEALTH:
675 					if ( players[clientnum] && players[clientnum]->entity )
676 					{
677 						skillDetails[0] = players[clientnum]->entity->entityLightAfterReductions(*stats[clientnum], nullptr);
678 						skillDetails[0] = std::max(1, (static_cast<int>(skillDetails[0] / 32))); // general visibility
679 						skillDetails[1] = stats[clientnum]->PROFICIENCIES[i] * 2 * 100 / 512.f; // % visibility reduction of above
680 						skillDetails[2] = (2 + (stats[clientnum]->PROFICIENCIES[PRO_STEALTH] / 40)); // night vision when sneaking
681 						skillDetails[3] = (stats[clientnum]->PROFICIENCIES[PRO_STEALTH] / 20 + 2) * 2; // backstab dmg
682 						if ( skillCapstoneUnlocked(clientnum, i) )
683 						{
684 							skillDetails[3] *= 2;
685 						}
686 					}
687 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
688 						uint32ColorWhite(*mainsurface), language[3255 + i],
689 						skillDetails[0], skillDetails[1], skillDetails[2], skillDetails[3]);
690 
691 					break;
692 				case PRO_TRADING:
693 					skillDetails[0] = 1 / ((50 + stats[clientnum]->PROFICIENCIES[PRO_TRADING]) / 150.f); // buy value
694 					skillDetails[1] = (50 + stats[clientnum]->PROFICIENCIES[PRO_TRADING]) / 150.f; // sell value
695 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
696 						uint32ColorWhite(*mainsurface), language[3255 + i],
697 						skillDetails[0], skillDetails[1]);
698 					break;
699 				case PRO_APPRAISAL:
700 					skillDetails[0] = (60.f / (stats[clientnum]->PROFICIENCIES[PRO_APPRAISAL] + 1)) / (TICKS_PER_SECOND); // appraisal time per gold value
701 					if ( players[clientnum] && players[clientnum]->entity )
702 					{
703 						skillDetails[1] = 10 * (stats[clientnum]->PROFICIENCIES[PRO_APPRAISAL] + players[clientnum]->entity->getPER() * 5); // max gold value can appraise
704 						if ( skillDetails[1] < 0.1 )
705 						{
706 							skillDetails[1] = 9;
707 						}
708 						if ( (stats[clientnum]->PROFICIENCIES[PRO_APPRAISAL] + players[clientnum]->entity->getPER() * 5) >= 100 )
709 						{
710 							ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
711 								uint32ColorWhite(*mainsurface), language[3255 + i],
712 								skillDetails[0], skillDetails[1], "yes");
713 						}
714 						else
715 						{
716 							ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
717 								uint32ColorWhite(*mainsurface), language[3255 + i],
718 								skillDetails[0], skillDetails[1], "no");
719 						}
720 					}
721 					else
722 					{
723 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
724 							uint32ColorWhite(*mainsurface), language[3255 + i],
725 							skillDetails[0], skillDetails[1], "no");
726 					}
727 					break;
728 				case PRO_SWIMMING:
729 					skillDetails[0] = (((stats[clientnum]->PROFICIENCIES[PRO_SWIMMING] / 100.f) * 50.f) + 50); // water movement speed
730 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
731 						uint32ColorWhite(*mainsurface), language[3255 + i],
732 						skillDetails[0]);
733 					break;
734 				case PRO_LEADERSHIP:
735 					skillDetails[0] = std::min(8, std::max(4, 2 * (stats[clientnum]->PROFICIENCIES[PRO_LEADERSHIP] / 20))); // max followers
736 					if ( players[clientnum] && players[clientnum]->entity )
737 					{
738 						skillDetails[1] = 1 + (stats[clientnum]->PROFICIENCIES[PRO_LEADERSHIP] / 20);
739 						skillDetails[2] = 80 + ((players[clientnum]->entity->getCHR() + stats[clientnum]->PROFICIENCIES[PRO_LEADERSHIP]) / 20) * 10;
740 					}
741 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
742 						uint32ColorWhite(*mainsurface), language[3255 + i],
743 						getInputName(impulses[IN_USE]),skillDetails[0], skillDetails[1], skillDetails[2], getInputName(impulses[IN_FOLLOWERMENU]));
744 					break;
745 				case PRO_SPELLCASTING:
746 					if ( players[clientnum] && players[clientnum]->entity )
747 					{
748 						skillDetails[0] = players[clientnum]->entity->getManaRegenInterval(*(stats[clientnum])) / (TICKS_PER_SECOND * 1.f);
749 						if ( players[clientnum]->entity->isSpellcasterBeginner() )
750 						{
751 							ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
752 								uint32ColorWhite(*mainsurface), language[3255 + i],
753 								skillDetails[0], "yes");
754 						}
755 						else
756 						{
757 							ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
758 								uint32ColorWhite(*mainsurface), language[3255 + i],
759 								skillDetails[0], "no");
760 						}
761 					}
762 					else
763 					{
764 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
765 							uint32ColorWhite(*mainsurface), language[3255 + i],
766 							skillDetails[0], "");
767 					}
768 					break;
769 				case PRO_MAGIC:
770 				{
771 					int skillLVL = 0;
772 					std::string magics = "";
773 					int lines = 0;
774 					if ( players[clientnum] && players[clientnum]->entity )
775 					{
776 						skillLVL = (stats[clientnum]->PROFICIENCIES[PRO_MAGIC] + players[clientnum]->entity->getINT());
777 						if ( stats[clientnum]->PROFICIENCIES[PRO_MAGIC] >= 100 )
778 						{
779 							skillLVL = 100;
780 						}
781 					}
782 					if ( skillLVL < 0 )
783 					{
784 						skillTooltip = "none";
785 					}
786 					else
787 					{
788 						skillLVL = skillLVL / 20;
789 						skillTooltip = "tier ";
790 						if ( skillLVL == 0 )
791 						{
792 							skillTooltip += "I";
793 						}
794 						else if ( skillLVL == 1 )
795 						{
796 							skillTooltip += "II";
797 						}
798 						else if ( skillLVL == 2 )
799 						{
800 							skillTooltip += "III";
801 						}
802 						else if ( skillLVL == 3 )
803 						{
804 							skillTooltip += "IV";
805 						}
806 						else if ( skillLVL == 4 )
807 						{
808 							skillTooltip += "V";
809 						}
810 						else if ( skillLVL >= 5 )
811 						{
812 							skillTooltip += "VI";
813 						}
814 						for ( auto it = allGameSpells.begin(); it != allGameSpells.end(); ++it )
815 						{
816 							auto spellEntry = *it;
817 							if ( spellEntry && spellEntry->difficulty == (skillLVL * 20) )
818 							{
819 								magics += " -[";
820 								magics += spellEntry->name;
821 								magics += "]\n";
822 								++lines;
823 							}
824 						}
825 					}
826 					skillTooltipRect.h += (1 + lines) * (fontHeight + lines / 6);
827 					drawTooltip(&skillTooltipRect);
828 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16 + (lines * (fontHeight + lines / 6)),
829 						capstoneTextColor, language[3277]);
830 
831 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 4, skillTooltipRect.y + 8,
832 						headerColor, "%s: (%d / 100)", getSkillLangEntry(i), stats[clientnum]->PROFICIENCIES[i]);
833 
834 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
835 						uint32ColorWhite(*mainsurface), language[3255 + i],
836 						skillTooltip.c_str());
837 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16 + (fontHeight) * 3, // print magic list
838 						uint32ColorBaronyBlue(*mainsurface), "%s",
839 						magics.c_str());
840 					break;
841 				}
842 				case PRO_RANGED:
843 				{
844 					skillDetails[0] = 100 - (100 - stats[clientnum]->PROFICIENCIES[PRO_RANGED]) / 2.f; // lowest damage roll
845 					skillDetails[1] = 50 + static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20) * 10;
846 					if ( stats[clientnum]->type == GOBLIN )
847 					{
848 						skillDetails[1] += 20;
849 						if ( stats[clientnum]->PROFICIENCIES[PRO_RANGED] < SKILL_LEVEL_LEGENDARY )
850 						{
851 							skillDetails[1] = std::min(skillDetails[1], 90.0);
852 						}
853 					}
854 					if ( players[clientnum] && players[clientnum]->entity )
855 					{
856 						skillDetails[2] = std::min(std::max(players[clientnum]->entity->getPER() / 2, 0), 50);
857 					}
858 					int skillLVL = stats[clientnum]->PROFICIENCIES[PRO_RANGED] / 20; // thrown dmg bonus
859 					skillDetails[3] = 100 * thrownDamageSkillMultipliers[std::min(skillLVL, 5)];
860 					if ( skillCapstoneUnlocked(clientnum, i) )
861 					{
862 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
863 							uint32ColorWhite(*mainsurface), language[3255 + i],
864 							skillDetails[0], 0.f, skillDetails[2], skillDetails[3]);
865 					}
866 					else
867 					{
868 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
869 							uint32ColorWhite(*mainsurface), language[3255 + i],
870 							skillDetails[0], 100 / skillDetails[1], skillDetails[2], skillDetails[3]);
871 					}
872 					break;
873 				}
874 				case PRO_SWORD:
875 				case PRO_AXE:
876 				case PRO_MACE:
877 				case PRO_POLEARM:
878 					if ( i == PRO_POLEARM )
879 					{
880 						skillDetails[0] = 100 - (100 - stats[clientnum]->PROFICIENCIES[i]) / 3.f; // lowest damage roll
881 					}
882 					else
883 					{
884 						skillDetails[0] = 100 - (100 - stats[clientnum]->PROFICIENCIES[i]) / 2.f; // lowest damage roll
885 					}
886 					if ( skillCapstoneUnlocked(clientnum, i) )
887 					{
888 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
889 							uint32ColorWhite(*mainsurface), language[3255 + i],
890 							skillDetails[0], 0.f, 0.f);
891 					}
892 					else
893 					{
894 						skillDetails[1] = 50 + (stats[clientnum]->type == GOBLIN ? 20 : 0); // chance to degrade on > 0 dmg
895 						skillDetails[2] = 4 + (stats[clientnum]->type == GOBLIN ? 4 : 0); // chance to degrade on 0 dmg
896 						skillDetails[1] += (static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20)) * 10;
897 						skillDetails[2] += static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20);
898 						if ( svFlags & SV_FLAG_HARDCORE )
899 						{
900 							skillDetails[1] *= 2;
901 							skillDetails[2] *= 2;
902 						}
903 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
904 							uint32ColorWhite(*mainsurface), language[3255 + i],
905 							skillDetails[0], 100 / skillDetails[1], 100 / skillDetails[2]);
906 					}
907 					break;
908 				case PRO_UNARMED:
909 					skillDetails[0] = 100 - (100 - stats[clientnum]->PROFICIENCIES[i]) / 2.f; // lowest damage roll
910 					skillDetails[3] = static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20);
911 					skillDetails[4] = static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20) * 20;
912 					if ( skillCapstoneUnlocked(clientnum, i) )
913 					{
914 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
915 							uint32ColorWhite(*mainsurface), language[3255 + i],
916 							skillDetails[0], 0.f, 0.f, skillDetails[3], skillDetails[4]);
917 					}
918 					else
919 					{
920 						skillDetails[1] = 100 + (stats[clientnum]->type == GOBLIN ? 20 : 0); // chance to degrade on > 0 dmg
921 						skillDetails[2] = 8 + (stats[clientnum]->type == GOBLIN ? 4 : 0); // chance to degrade on 0 dmg
922 						skillDetails[1] += (static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20)) * 10;
923 						skillDetails[2] += static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20);
924 						if ( svFlags & SV_FLAG_HARDCORE )
925 						{
926 							skillDetails[1] *= 2;
927 							skillDetails[2] *= 2;
928 						}
929 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
930 							uint32ColorWhite(*mainsurface), language[3255 + i],
931 							skillDetails[0], 100 / skillDetails[1], 100 / skillDetails[2], skillDetails[3], skillDetails[4]);
932 					}
933 					break;
934 				case PRO_SHIELD:
935 					skillDetails[0] = 5 + static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 5);
936 					if ( skillCapstoneUnlocked(clientnum, i) )
937 					{
938 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
939 							uint32ColorWhite(*mainsurface), language[3255 + i],
940 							skillDetails[0], 0.f, 0.f);
941 					}
942 					else
943 					{
944 						skillDetails[1] = 25 + (stats[clientnum]->type == GOBLIN ? 10 : 0); // degrade > 0 dmg taken
945 						skillDetails[2] = 10 + (stats[clientnum]->type == GOBLIN ? 10 : 0); // degrade on 0 dmg
946 						skillDetails[1] += (static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 10));
947 						skillDetails[2] += (static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 10));
948 						if ( svFlags & SV_FLAG_HARDCORE )
949 						{
950 							skillDetails[2] = 40 + (stats[clientnum]->type == GOBLIN ? 10 : 0);
951 						}
952 						ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
953 							uint32ColorWhite(*mainsurface), language[3255 + i],
954 							skillDetails[0], 100 / skillDetails[1], 100 / skillDetails[2]);
955 					}
956 					break;
957 				case PRO_ALCHEMY:
958 				{
959 					std::string baseIngredients;
960 					std::string secondaryIngredients;
961 					int lines = 0;
962 					int lines2 = 0;
963 					for ( auto it = clientLearnedAlchemyIngredients.begin(); it != clientLearnedAlchemyIngredients.end(); ++it )
964 					{
965 						auto alchemyEntry = *it;
966 						if ( GenericGUI.isItemBaseIngredient(alchemyEntry) )
967 						{
968 							baseIngredients += " -[";
969 							std::string itemName = items[alchemyEntry].name_identified;
970 							itemName = itemName.substr(10);
971 							baseIngredients += itemName;
972 							baseIngredients += "]\n";
973 							++lines;
974 						}
975 						if ( GenericGUI.isItemSecondaryIngredient(alchemyEntry) )
976 						{
977 							secondaryIngredients += " -[";
978 							std::string itemName = items[alchemyEntry].name_identified;
979 							itemName = itemName.substr(10);
980 							secondaryIngredients += itemName;
981 							secondaryIngredients += "]\n";
982 							++lines2;
983 						}
984 					}
985 					lines = std::max(lines, lines2);
986 					int skillLVL = stats[clientnum]->PROFICIENCIES[i] / 20;
987 					skillDetails[0] = 100 * potionDamageSkillMultipliers[std::min(skillLVL, 5)];
988 					skillDetails[1] = skillDetails[0];
989 					skillDetails[2] = 50.f + static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20) * 10;
990 					skillDetails[3] = std::min(80, (60 + static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20) * 10));
991 					skillDetails[4] = 50.f + static_cast<int>(stats[clientnum]->PROFICIENCIES[i] / 20) * 5;
992 
993 					skillTooltipRect.h = fontHeight * (5 + 2) + 8;
994 					skillTooltipRect.h += 4 + (6 + lines) * (fontHeight + lines / 6);
995 					drawTooltip(&skillTooltipRect);
996 					// legendary text
997 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 16 + (lines * (fontHeight + lines / 6)),
998 						capstoneTextColor, language[3347]);
999 					// header text
1000 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 4, skillTooltipRect.y + 8,
1001 						headerColor, "%s: (%d / 100)", getSkillLangEntry(i), stats[clientnum]->PROFICIENCIES[i]);
1002 					// effect text
1003 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 12,
1004 						uint32ColorWhite(*mainsurface), language[3348],
1005 						skillDetails[0], skillDetails[1], skillDetails[2], skillDetails[3], skillDetails[4]);
1006 					// base potions
1007 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8, skillTooltipRect.y + 20 + (fontHeight) * 9, // print potion list
1008 						uint32ColorBaronyBlue(*mainsurface), "%s",
1009 						baseIngredients.c_str());
1010 					// secondary potions
1011 					ttfPrintTextFormattedColor(fontSkill, skillTooltipRect.x + 8 + 18 * fontWidth, skillTooltipRect.y + 20 + (fontHeight) * 9, // print potion list
1012 						uint32ColorBaronyBlue(*mainsurface), "%s",
1013 						secondaryIngredients.c_str());
1014 					break;
1015 				}
1016 				default:
1017 					break;
1018 			}
1019 		}
1020 	}
1021 }
1022 
drawPartySheet()1023 void drawPartySheet()
1024 {
1025 	SDL_Rect pos;
1026 	pos.w = 208;
1027 
1028 	TTF_Font* fontPlayer = ttf12;
1029 	int fontHeight = TTF12_HEIGHT;
1030 	int fontWidth = TTF12_WIDTH;
1031 	if ( uiscale_skillspage )
1032 	{
1033 		fontPlayer = ttf16;
1034 		fontHeight = TTF16_HEIGHT;
1035 		fontWidth = TTF16_WIDTH;
1036 		pos.w = 276;
1037 	}
1038 	int playerCnt = 0;
1039 	for ( playerCnt = MAXPLAYERS - 1; playerCnt > 0; --playerCnt )
1040 	{
1041 		if ( !client_disconnected[playerCnt] )
1042 		{
1043 			break;
1044 		}
1045 	}
1046 	pos.x = xres - pos.w;
1047 	pos.y = 32;
1048 	pos.h = (fontHeight * 2 + 12) + ((fontHeight * 4) + 6) * (std::max(playerCnt + 1, 1));
1049 
1050 	int numFollowers = 0;
1051 	if ( stats[clientnum] )
1052 	{
1053 		numFollowers = list_Size(&stats[clientnum]->FOLLOWERS);
1054 	}
1055 
1056 	if ( playerCnt == 0 ) // 1 player.
1057 	{
1058 		if ( numFollowers == 0 )
1059 		{
1060 			if ( shootmode )
1061 			{
1062 				return; // don't show menu if not in inventory, no point reminding the player they have no friends!
1063 			}
1064 			pos.h = (fontHeight * 4 + 12);
1065 		}
1066 		else
1067 		{
1068 			pos.h = (fontHeight + 12);
1069 		}
1070 	}
1071 	drawWindowFancy(pos.x, pos.y, pos.x + pos.w, pos.y + pos.h);
1072 	interfacePartySheet.x = pos.x;
1073 	interfacePartySheet.y = pos.y;
1074 	interfacePartySheet.w = pos.w;
1075 	interfacePartySheet.h = pos.h;
1076 
1077 	ttfPrintTextFormatted(fontPlayer, pos.x + 4, pos.y + 8, "Party Stats");
1078 
1079 	SDL_Rect button;
1080 	button.x = xres - attributesright_bmp->w - 8;
1081 	button.w = attributesright_bmp->w;
1082 	button.y = pos.y;
1083 	button.h = attributesright_bmp->h;
1084 	if ( uiscale_skillspage )
1085 	{
1086 		button.w = attributesright_bmp->w * 1.3;
1087 		button.x = xres - button.w - 8;
1088 		button.y = pos.y;
1089 		button.h = attributesright_bmp->h * 1.3;
1090 	}
1091 
1092 
1093 	if ( mousestatus[SDL_BUTTON_LEFT] && !shootmode )
1094 	{
1095 		if ( omousex >= button.x && omousex <= button.x + button.w
1096 			&& omousey >= button.y && omousey <= button.y + button.h )
1097 		{
1098 			buttonclick = 14;
1099 			playSound(139, 64);
1100 			if ( proficienciesPage == 0 )
1101 			{
1102 				proficienciesPage = 1;
1103 			}
1104 			else
1105 			{
1106 				proficienciesPage = 0;
1107 			}
1108 			mousestatus[SDL_BUTTON_LEFT] = 0;
1109 		}
1110 	}
1111 	if ( buttonclick == 14 )
1112 	{
1113 		drawImageScaled(attributesright_bmp, nullptr, &button);
1114 	}
1115 	else
1116 	{
1117 		drawImageScaled(attributesrightunclicked_bmp, nullptr, &button);
1118 	}
1119 
1120 	SDL_Rect lockbtn = button;
1121 	lockbtn.h = 24;
1122 	lockbtn.w = 24;
1123 	lockbtn.y += 2;
1124 	if ( uiscale_skillspage )
1125 	{
1126 		lockbtn.h = 24 * 1.3;
1127 		lockbtn.w = 24 * 1.3;
1128 		lockbtn.x -= 32 * 1.3;
1129 	}
1130 	else
1131 	{
1132 		lockbtn.x -= 32;
1133 	}
1134 	if ( lock_right_sidebar )
1135 	{
1136 		drawImageScaled(sidebar_lock_bmp, nullptr, &lockbtn);
1137 	}
1138 	else
1139 	{
1140 		drawImageScaled(sidebar_unlock_bmp, nullptr, &lockbtn);
1141 	}
1142 
1143 	if ( mousestatus[SDL_BUTTON_LEFT] && !shootmode )
1144 	{
1145 		if ( omousex >= lockbtn.x && omousex <= lockbtn.x + lockbtn.w
1146 			&& omousey >= lockbtn.y && omousey <= lockbtn.y + lockbtn.h )
1147 		{
1148 			playSound(139, 64);
1149 			lock_right_sidebar = !lock_right_sidebar;
1150 			mousestatus[SDL_BUTTON_LEFT] = 0;
1151 		}
1152 	}
1153 
1154 	pos.y += fontHeight * 2 + 4;
1155 
1156 	SDL_Rect initialSkillPos = pos;
1157 	SDL_Rect playerBar;
1158 
1159 
1160 	if ( playerCnt == 0 && numFollowers == 0 ) // 1 player.
1161 	{
1162 		ttfPrintTextFormatted(fontPlayer, pos.x + 32, pos.y + 8, "No party members");
1163 	}
1164 
1165 	//Draw party stats
1166 	Uint32 color = uint32ColorWhite(*mainsurface);
1167 	if ( playerCnt > 0 )
1168 	{
1169 		for ( int i = 0; i < MAXPLAYERS; ++i, pos.y += (fontHeight * 4) + 6 )
1170 		{
1171 			if ( !client_disconnected[i] && stats[i] )
1172 			{
1173 
1174 				if ( strlen(stats[i]->name) > 16 )
1175 				{
1176 					char shortname[32] = "";
1177 					strncpy(shortname, stats[i]->name, 14);
1178 					strcat(shortname, "..");
1179 					ttfPrintTextFormattedColor(fontPlayer, pos.x + 12, pos.y, color, "[%d] %s", i, shortname);
1180 				}
1181 				else
1182 				{
1183 					ttfPrintTextFormattedColor(fontPlayer, pos.x + 12, pos.y, color, "[%d] %s", i, stats[i]->name);
1184 				}
1185 
1186 				ttfPrintTextFormattedColor(fontPlayer, pos.x + 12, pos.y + fontHeight, color, "%s", playerClassLangEntry(client_classes[i], i));
1187 				ttfPrintTextFormattedColor(fontPlayer, xres - 8 * 12, pos.y + fontHeight, color, "LVL %2d", stats[i]->LVL);
1188 
1189 				playerBar.x = pos.x + 64;
1190 				playerBar.w = 10 * 11;
1191 				if ( uiscale_skillspage )
1192 				{
1193 					playerBar.x += 10;
1194 					playerBar.w += 48;
1195 				}
1196 				playerBar.y = pos.y + fontHeight * 2 + 1;
1197 				playerBar.h = fontHeight;
1198 				// draw tooltip with blue outline
1199 				drawTooltip(&playerBar);
1200 				// draw faint red bar underneath
1201 				playerBar.x += 1;
1202 				drawRect(&playerBar, SDL_MapRGB(mainsurface->format, 48, 0, 0), 255);
1203 
1204 				// draw main red bar for current HP
1205 				playerBar.w = (playerBar.w) * (static_cast<double>(stats[i]->HP) / stats[i]->MAXHP);
1206 				drawRect(&playerBar, SDL_MapRGB(mainsurface->format, 128, 0, 0), 255);
1207 
1208 				// draw HP values
1209 				ttfPrintTextFormattedColor(fontPlayer, pos.x + 32, pos.y + fontHeight * 2 + 4, color, "HP:  %3d / %3d", stats[i]->HP, stats[i]->MAXHP);
1210 
1211 				playerBar.x = pos.x + 64;
1212 				playerBar.w = 10 * 11;
1213 				if ( uiscale_skillspage )
1214 				{
1215 					playerBar.x += 10;
1216 					playerBar.w += 48;
1217 				}
1218 				playerBar.y = pos.y + fontHeight * 3 + 1;
1219 				// draw tooltip with blue outline
1220 				drawTooltip(&playerBar);
1221 				playerBar.x += 1;
1222 				// draw faint blue bar underneath
1223 				drawRect(&playerBar, SDL_MapRGB(mainsurface->format, 0, 0, 48), 255);
1224 
1225 				// draw blue red bar for current MP
1226 				playerBar.w = (playerBar.w) * (static_cast<double>(stats[i]->MP) / stats[i]->MAXMP);
1227 				drawRect(&playerBar, SDL_MapRGB(mainsurface->format, 0, 24, 128), 255);
1228 
1229 				// draw MP values
1230 				ttfPrintTextFormattedColor(fontPlayer, pos.x + 32 , pos.y + fontHeight * 3 + 4, color, "MP:  %3d / %3d", stats[i]->MP, stats[i]->MAXMP);
1231 			}
1232 		}
1233 	}
1234 
1235 
1236 
1237 	// draw follower stats
1238 	if ( numFollowers > 0 )
1239 	{
1240 		int monstersToDisplay = FollowerMenu.maxMonstersToDraw;
1241 		if ( playerCnt != 0 )
1242 		{
1243 			pos.y -= (fontHeight * 4) * 2;
1244 			pos.y += std::max(playerCnt - 1, 0) * (fontHeight * 4 + 8);
1245 			monstersToDisplay = FollowerMenu.numMonstersToDrawInParty();
1246 		}
1247 		int i = 0;
1248 		SDL_Rect monsterEntryWindow;
1249 		monsterEntryWindow.x = pos.x + 8;
1250 		monsterEntryWindow.w = pos.w - 8;
1251 		if ( numFollowers > (monstersToDisplay + 1) )
1252 		{
1253 			monsterEntryWindow.w -= 16;
1254 		}
1255 		SDL_Rect slider = monsterEntryWindow;
1256 		slider.y = pos.y;
1257 
1258 		for ( node_t* node = stats[clientnum]->FOLLOWERS.first; node != nullptr; node = node->next, ++i )
1259 		{
1260 			Entity* follower = nullptr;
1261 			if ( (Uint32*)node->element )
1262 			{
1263 				follower = uidToEntity(*((Uint32*)node->element));
1264 			}
1265 			if ( follower )
1266 			{
1267 				Stat* followerStats = follower->getStats();
1268 				if ( followerStats )
1269 				{
1270 					monsterEntryWindow.y = pos.y;
1271 					monsterEntryWindow.h = fontHeight * 2 + 12;
1272 
1273 					bool hideDetail = false;
1274 					if ( numFollowers > monstersToDisplay )
1275 					{
1276 						if ( i < FollowerMenu.sidebarScrollIndex )
1277 						{
1278 							hideDetail = true;
1279 						}
1280 						else if ( i > FollowerMenu.sidebarScrollIndex + monstersToDisplay )
1281 						{
1282 							hideDetail = true;
1283 						}
1284 					}
1285 
1286 					if ( !hideDetail )
1287 					{
1288 						drawWindowFancy(monsterEntryWindow.x, monsterEntryWindow.y,
1289 							monsterEntryWindow.x + monsterEntryWindow.w, monsterEntryWindow.y + monsterEntryWindow.h);
1290 
1291 						if ( !FollowerMenu.recentEntity )
1292 						{
1293 							FollowerMenu.recentEntity = follower;
1294 						}
1295 						if ( FollowerMenu.recentEntity == follower )
1296 						{
1297 							// draw highlight on current selected monster.
1298 							drawRect(&monsterEntryWindow, uint32ColorBaronyBlue(*mainsurface), 32);
1299 							// ttfPrintText(ttf16, xres - 20, monsterEntryWindow.y + monsterEntryWindow.h / 2 - fontHeight / 2, "<");
1300 						}
1301 
1302 						if ( stats[clientnum] && stats[clientnum]->HP > 0 && !shootmode
1303 							&& (mousestatus[SDL_BUTTON_LEFT] || (*inputPressed(impulses[IN_USE]) || *inputPressed(joyimpulses[INJOY_GAME_USE]))) )
1304 						{
1305 							bool inBounds = mouseInBounds(monsterEntryWindow.x, monsterEntryWindow.x + monsterEntryWindow.w,
1306 								monsterEntryWindow.y, monsterEntryWindow.y + monsterEntryWindow.h);
1307 							if ( inBounds )
1308 							{
1309 								if ( mousestatus[SDL_BUTTON_LEFT] )
1310 								{
1311 									FollowerMenu.recentEntity = follower;
1312 									playSound(139, 64);
1313 									FollowerMenu.accessedMenuFromPartySheet = true;
1314 									FollowerMenu.partySheetMouseX = omousex;
1315 									FollowerMenu.partySheetMouseY = omousey;
1316 									mousestatus[SDL_BUTTON_LEFT] = 0;
1317 									if ( FollowerMenu.recentEntity )
1318 									{
1319 										createParticleFollowerCommand(FollowerMenu.recentEntity->x, FollowerMenu.recentEntity->y, 0, 174);
1320 									}
1321 								}
1322 								else if ( (*inputPressed(impulses[IN_USE]) || *inputPressed(joyimpulses[INJOY_GAME_USE])) )
1323 								{
1324 									FollowerMenu.followerToCommand = follower;
1325 									FollowerMenu.recentEntity = follower;
1326 									FollowerMenu.accessedMenuFromPartySheet = true;
1327 									FollowerMenu.partySheetMouseX = omousex;
1328 									FollowerMenu.partySheetMouseY = omousey;
1329 									FollowerMenu.initFollowerMenuGUICursor();
1330 									FollowerMenu.updateScrollPartySheet();
1331 									if ( FollowerMenu.recentEntity )
1332 									{
1333 										createParticleFollowerCommand(FollowerMenu.recentEntity->x, FollowerMenu.recentEntity->y, 0, 174);
1334 									}
1335 								}
1336 							}
1337 						}
1338 
1339 						pos.y += 6;
1340 						char name[16] = "";
1341 						if ( strcmp(followerStats->name, "") && strcmp(followerStats->name, "nothing") )
1342 						{
1343 							if ( strlen(followerStats->name) > 10 )
1344 							{
1345 								if ( followerStats->type == SKELETON )
1346 								{
1347 									if ( !strcmp(followerStats->name, "skeleton sentinel") )
1348 									{
1349 										strncpy(name, "sentinel", 8);
1350 									}
1351 									else if ( !strcmp(followerStats->name, "skeleton knight") )
1352 									{
1353 										strncpy(name, "knight", 6);
1354 									}
1355 									else
1356 									{
1357 										strncpy(name, followerStats->name, 8);
1358 										strcat(name, "..");
1359 									}
1360 								}
1361 								else
1362 								{
1363 									strncpy(name, followerStats->name, 8);
1364 									strcat(name, "..");
1365 								}
1366 								ttfPrintTextFormattedColor(fontPlayer, pos.x + 20, pos.y, color, "%s", name);
1367 							}
1368 							else
1369 							{
1370 								ttfPrintTextFormattedColor(fontPlayer, pos.x + 20, pos.y, color, "%s", followerStats->name);
1371 							}
1372 						}
1373 						else
1374 						{
1375 							if ( strlen(monstertypename[followerStats->type]) > 10 )
1376 							{
1377 								strncpy(name, monstertypename[followerStats->type], 8);
1378 								strcat(name, "..");
1379 								ttfPrintTextFormattedColor(fontPlayer, pos.x + 20, pos.y, color, "%s", name);
1380 							}
1381 							else
1382 							{
1383 								ttfPrintTextFormattedColor(fontPlayer, pos.x + 20, pos.y, color, "%s", monstertypename[followerStats->type]);
1384 							}
1385 						}
1386 						ttfPrintTextFormattedColor(fontPlayer, xres - 8 * 11, pos.y, color, "LVL %2d", followerStats->LVL);
1387 
1388 						playerBar.x = pos.x + 64;
1389 						playerBar.w = 10 * 11;
1390 						if ( uiscale_skillspage )
1391 						{
1392 							playerBar.x += 10;
1393 							playerBar.w += 48;
1394 						}
1395 						playerBar.y = pos.y + fontHeight + 1;
1396 						playerBar.h = fontHeight;
1397 						// draw tooltip with blue outline
1398 						drawTooltip(&playerBar);
1399 						// draw faint red bar underneath
1400 						playerBar.x += 1;
1401 						drawRect(&playerBar, SDL_MapRGB(mainsurface->format, 48, 0, 0), 255);
1402 
1403 						// draw main red bar for current HP
1404 						playerBar.w = (playerBar.w) * (static_cast<double>(followerStats->HP) / followerStats->MAXHP);
1405 						drawRect(&playerBar, SDL_MapRGB(mainsurface->format, 128, 0, 0), 255);
1406 
1407 						// draw HP values
1408 						ttfPrintTextFormattedColor(fontPlayer, pos.x + 32, pos.y + fontHeight + 4, color, "HP:  %3d / %3d", followerStats->HP, followerStats->MAXHP);
1409 						pos.y += (fontHeight * 2 + 6);
1410 					}
1411 				}
1412 			}
1413 		}
1414 		slider.x = xres - 16;
1415 		slider.w = 16;
1416 		slider.h = (fontHeight * 2 + 12) * (std::min(monstersToDisplay + 1, numFollowers));
1417 		interfacePartySheet.h += slider.h + 6;
1418 
1419 		if ( numFollowers > (monstersToDisplay + 1) )
1420 		{
1421 			drawDepressed(slider.x, slider.y, slider.x + slider.w,
1422 				slider.y + slider.h);
1423 
1424 			bool mouseInScrollbarTotalHeight = mouseInBounds(xres - monsterEntryWindow.w, xres, slider.y,
1425 				slider.y + slider.h);
1426 
1427 			if ( mousestatus[SDL_BUTTON_WHEELDOWN] && mouseInScrollbarTotalHeight )
1428 			{
1429 				mousestatus[SDL_BUTTON_WHEELDOWN] = 0;
1430 				FollowerMenu.sidebarScrollIndex = std::min(FollowerMenu.sidebarScrollIndex + 1, numFollowers - monstersToDisplay - 1);
1431 			}
1432 			else if ( mousestatus[SDL_BUTTON_WHEELUP] && mouseInScrollbarTotalHeight )
1433 			{
1434 				mousestatus[SDL_BUTTON_WHEELUP] = 0;
1435 				FollowerMenu.sidebarScrollIndex = std::max(FollowerMenu.sidebarScrollIndex - 1, 0);
1436 			}
1437 
1438 			slider.h *= (1 / static_cast<real_t>(std::max(1, numFollowers - monstersToDisplay)));
1439 			slider.y += slider.h * FollowerMenu.sidebarScrollIndex;
1440 			drawWindowFancy(slider.x, slider.y, slider.x + slider.w, slider.y + slider.h);
1441 			if ( mouseInScrollbarTotalHeight && mousestatus[SDL_BUTTON_LEFT] )
1442 			{
1443 				if ( !mouseInBounds(xres - monsterEntryWindow.w, xres, slider.y,
1444 					slider.y + slider.h) )
1445 				{
1446 					if ( omousey < slider.y )
1447 					{
1448 						FollowerMenu.sidebarScrollIndex = std::max(FollowerMenu.sidebarScrollIndex - 1, 0);
1449 						mousestatus[SDL_BUTTON_LEFT] = 0;
1450 					}
1451 					else if ( omousey > slider.y + slider.h )
1452 					{
1453 						FollowerMenu.sidebarScrollIndex = std::min(FollowerMenu.sidebarScrollIndex + 1, numFollowers - monstersToDisplay - 1);
1454 						mousestatus[SDL_BUTTON_LEFT] = 0;
1455 					}
1456 				}
1457 			}
1458 		}
1459 	}
1460 }
1461 
statsHoverText(Stat * tmpStat)1462 void statsHoverText(Stat* tmpStat)
1463 {
1464 	if ( tmpStat == nullptr )
1465 	{
1466 		return;
1467 	}
1468 
1469 	int pad_y = 262; // 262 px.
1470 	int pad_x = 8; // 8 px.
1471 	int off_h = TTF12_HEIGHT - 4; // 12px. height of stat line.
1472 	int off_w = 216; // 216px. width of stat line.
1473 	int i = 0;
1474 	int j = 0;
1475 	SDL_Rect src;
1476 	SDL_Rect pos;
1477 
1478 	if ( uiscale_charactersheet )
1479 	{
1480 		pad_y += 86;
1481 		off_h = TTF16_HEIGHT - 4;
1482 		off_w = 280;
1483 	}
1484 
1485 	int tooltip_offset_x = 16; // 16px.
1486 	int tooltip_offset_y = 16; // 16px.
1487 	int tooltip_base_h = TTF12_HEIGHT;
1488 	int tooltip_pad_h = 8;
1489 	int tooltip_text_pad_x = 8;
1490 
1491 	char tooltipHeader[6][128] =
1492 	{
1493 		"strength: ",
1494 		"dexterity: ",
1495 		"constitution: ",
1496 		"intelligence: ",
1497 		"perception: ",
1498 		"charisma: "
1499 	};
1500 
1501 	char tooltipText[6][5][128] =
1502 	{
1503 		{
1504 			"base:  %2d ",
1505 			"bonus: %2d ",
1506 			""
1507 		},
1508 		{
1509 			"base:  %2d ",
1510 			"bonus: %2d ",
1511 			""
1512 		},
1513 		{
1514 			"base:  %2d ",
1515 			"bonus: %2d ",
1516 			"HP regen rate: 1 / %2.1fs",
1517 			""
1518 		},
1519 		{
1520 			"base:  %2d ",
1521 			"bonus: %2d ",
1522 			"MP regen rate: 1 / %2.1fs",
1523 			"magic damage:     %3d%%",
1524 			"magic resistance: %2.1f%% "
1525 		},
1526 		{
1527 			"base:  %2d ",
1528 			"bonus: %2d ",
1529 			""
1530 		},
1531 		{
1532 			"base:  %2d ",
1533 			"bonus: %2d ",
1534 			""
1535 		}
1536 	};
1537 
1538 	char buf[128] = "";
1539 	int numInfoLines = 0;
1540 	Sint32 statBase = 0;
1541 	Sint32 statBonus = 0;
1542 
1543 	SDL_Surface *tmp_bmp = NULL;
1544 
1545 	Entity* playerEntity = nullptr;
1546 	if ( players[clientnum] )
1547 	{
1548 		playerEntity = players[clientnum]->entity;
1549 	}
1550 
1551 	if ( attributespage == 0 )
1552 	{
1553 		for ( i = 0; i < 6; i++ ) // cycle through 6 stats.
1554 		{
1555 			switch ( i )
1556 			{
1557 				// prepare the stat image.
1558 				case 0:
1559 					numInfoLines = 2;
1560 					tmp_bmp = str_bmp64;
1561 					statBase = tmpStat->STR;
1562 					statBonus = statGetSTR(tmpStat, playerEntity) - statBase;
1563 					break;
1564 				case 1:
1565 					numInfoLines = 2;
1566 					tmp_bmp = dex_bmp64;
1567 					statBase = tmpStat->DEX;
1568 					statBonus = statGetDEX(tmpStat, playerEntity) - statBase;
1569 					break;
1570 				case 2:
1571 					numInfoLines = 3;
1572 					tmp_bmp = con_bmp64;
1573 					statBase = tmpStat->CON;
1574 					statBonus = statGetCON(tmpStat, playerEntity) - statBase;
1575 					break;
1576 				case 3:
1577 					numInfoLines = 5;
1578 					tmp_bmp = int_bmp64;
1579 					statBase = tmpStat->INT;
1580 					statBonus = statGetINT(tmpStat, playerEntity) - statBase;
1581 					break;
1582 				case 4:
1583 					numInfoLines = 2;
1584 					tmp_bmp = per_bmp64;
1585 					statBase = tmpStat->PER;
1586 					statBonus = statGetPER(tmpStat, playerEntity) - statBase;
1587 					break;
1588 				case 5:
1589 					numInfoLines = 2;
1590 					tmp_bmp = chr_bmp64;
1591 					statBase = tmpStat->CHR;
1592 					statBonus = statGetCHR(tmpStat, playerEntity) - statBase;
1593 					break;
1594 				default:
1595 					numInfoLines = 0;
1596 					break;
1597 			}
1598 
1599 			if ( mouseInBounds(pad_x, pad_x + off_w, pad_y, pad_y + off_h) )
1600 			{
1601 				src.x = mousex + tooltip_offset_x;
1602 				src.y = mousey + tooltip_offset_y;
1603 				src.h = std::max(tooltip_base_h * (numInfoLines + 1) + tooltip_pad_h, tooltip_base_h * (2) + tooltip_pad_h);
1604 				src.w = 180;
1605 				for ( j = 0; j < numInfoLines; j++ )
1606 				{
1607 					src.w = std::max(longestline(tooltipText[i][j]) * 12, src.w);
1608 				}
1609 				drawTooltip(&src);
1610 
1611 				pos.x = src.x + 6;
1612 				pos.y = src.y + 4;
1613 				pos.h = 32;
1614 				pos.w = 32;
1615 
1616 				drawImageScaled(tmp_bmp, NULL, &pos);
1617 
1618 				src.x = pos.x + pos.w;
1619 				src.y += 2;
1620 
1621 				ttfPrintText(ttf12, src.x + 4, src.y + 4, tooltipHeader[i]);
1622 
1623 				for ( j = 0; j < numInfoLines && numInfoLines > 0; j++ )
1624 				{
1625 					int infoText_x = src.x + 4 + tooltip_text_pad_x;
1626 					int infoText_y = src.y + 4 + (tooltip_base_h * (j + 1));
1627 					Uint32 color = uint32ColorWhite(*mainsurface);
1628 
1629 					if ( j == 0 )
1630 					{
1631 						snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], statBase);
1632 					}
1633 					else if ( j == 1 )
1634 					{
1635 						snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], statBonus);
1636 						if ( statBonus > 0 )
1637 						{
1638 							color = uint32ColorGreen(*mainsurface);
1639 						}
1640 						else if ( statBonus < 0 )
1641 						{
1642 							color = uint32ColorRed(*mainsurface);
1643 						}
1644 					}
1645 					else if ( j == 2 )
1646 					{
1647 						if ( i == 3 )
1648 						{
1649 							Entity* tmp = nullptr;
1650 							if ( players[clientnum] && players[clientnum]->entity )
1651 							{
1652 								tmp = players[clientnum]->entity;
1653 								real_t regen = (static_cast<real_t>(tmp->getManaRegenInterval(*tmpStat)) / TICKS_PER_SECOND);
1654 								if ( stats[clientnum]->type == AUTOMATON )
1655 								{
1656 									if ( stats[clientnum]->HUNGER <= 300 )
1657 									{
1658 										regen /= 6; // degrade faster
1659 									}
1660 									else if ( stats[clientnum]->HUNGER > 1200 )
1661 									{
1662 										if ( stats[clientnum]->MP / static_cast<real_t>(std::max(1, stats[clientnum]->MAXMP)) <= 0.5 )
1663 										{
1664 											regen /= 4; // increase faster at < 50% mana
1665 										}
1666 										else
1667 										{
1668 											regen /= 2; // increase less faster at > 50% mana
1669 										}
1670 									}
1671 									else if ( stats[clientnum]->HUNGER > 300 )
1672 									{
1673 										// normal manaRegenInterval 300-1200 hunger.
1674 									}
1675 								}
1676 
1677 								if ( regen < 0.f /*stats[clientnum]->playerRace == RACE_INSECTOID && stats[clientnum]->appearance == 0*/ )
1678 								{
1679 									regen = 0.f;
1680 									snprintf(buf, longestline("MP regen rate: 0 / %2.1fs"), "MP regen rate: 0 / %2.1fs", (static_cast<real_t>(MAGIC_REGEN_TIME) / TICKS_PER_SECOND));
1681 								}
1682 								else
1683 								{
1684 									snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], regen);
1685 								}
1686 
1687 								if ( stats[clientnum]->type == AUTOMATON )
1688 								{
1689 									if ( stats[clientnum]->HUNGER <= 300 )
1690 									{
1691 										color = uint32ColorRed(*mainsurface);
1692 									}
1693 									else if ( regen < static_cast<real_t>(tmp->getBaseManaRegen(*tmpStat)) / TICKS_PER_SECOND )
1694 									{
1695 										color = uint32ColorGreen(*mainsurface);
1696 									}
1697 								}
1698 								else if ( stats[clientnum]->playerRace == RACE_INSECTOID && stats[clientnum]->appearance == 0 )
1699 								{
1700 									if ( !(svFlags & SV_FLAG_HUNGER) )
1701 									{
1702 										color = uint32ColorWhite(*mainsurface);
1703 									}
1704 									else
1705 									{
1706 										color = uint32ColorRed(*mainsurface);
1707 									}
1708 								}
1709 								else if ( regen < static_cast<real_t>(tmp->getBaseManaRegen(*tmpStat)) / TICKS_PER_SECOND)
1710 								{
1711 									color = uint32ColorGreen(*mainsurface);
1712 								}
1713 
1714 							}
1715 							else
1716 							{
1717 								snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], 0.f);
1718 							}
1719 						}
1720 						else if ( i == 2 )
1721 						{
1722 							Entity* tmp = nullptr;
1723 							if ( players[clientnum] && players[clientnum]->entity )
1724 							{
1725 								tmp = players[clientnum]->entity;
1726 								real_t regen = (static_cast<real_t>(tmp->getHealthRegenInterval(*tmpStat)) / TICKS_PER_SECOND);
1727 								if ( tmpStat->type == SKELETON )
1728 								{
1729 									if ( !(svFlags & SV_FLAG_HUNGER) )
1730 									{
1731 										regen = HEAL_TIME * 4 / TICKS_PER_SECOND;
1732 									}
1733 								}
1734 								if ( regen < 0 )
1735 								{
1736 									regen = 0.f;
1737 									if ( !(svFlags & SV_FLAG_HUNGER) )
1738 									{
1739 										color = uint32ColorWhite(*mainsurface);
1740 									}
1741 									else
1742 									{
1743 										color = uint32ColorRed(*mainsurface);
1744 									}
1745 									snprintf(buf, longestline("HP regen rate: 0 / %2.1fs"), "HP regen rate: 0 / %2.1fs", (static_cast<real_t>(HEAL_TIME) / TICKS_PER_SECOND));
1746 								}
1747 								else if ( regen < HEAL_TIME / TICKS_PER_SECOND )
1748 								{
1749 									color = uint32ColorGreen(*mainsurface);
1750 								}
1751 								if ( regen > 0.f )
1752 								{
1753 									snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], regen);
1754 								}
1755 							}
1756 							else
1757 							{
1758 								snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], 0.f);
1759 							}
1760 						}
1761 					}
1762 					else if ( j == 3 )
1763 					{
1764 						if ( i == 3 )
1765 						{
1766 							int bonusDamage = 100;
1767 							if ( players[clientnum] && players[clientnum]->entity )
1768 							{
1769 								bonusDamage += 100 * (getBonusFromCasterOfSpellElement(players[clientnum]->entity, nullptr));
1770 							}
1771 							snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], bonusDamage);
1772 						}
1773 					}
1774 					else if ( j == 4 )
1775 					{
1776 						if ( i == 3 )
1777 						{
1778 							Entity* tmp = nullptr;
1779 							real_t resistance = 0.f;
1780 							if ( players[clientnum] && players[clientnum]->entity )
1781 							{
1782 								tmp = players[clientnum]->entity;
1783 								real_t resistance = 100 - 100 / (tmp->getMagicResistance() + 1);
1784 								snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], resistance);
1785 								if ( resistance > 0.f )
1786 								{
1787 									color = uint32ColorGreen(*mainsurface);
1788 								}
1789 							}
1790 							else
1791 							{
1792 								snprintf(buf, longestline(tooltipText[i][j]), tooltipText[i][j], 0);
1793 							}
1794 						}
1795 					}
1796 					ttfPrintTextColor(ttf12, infoText_x, infoText_y, color, false, buf);
1797 				}
1798 			}
1799 			numInfoLines = 0;
1800 			pad_y += off_h;
1801 		}
1802 	}
1803 }
1804 
displayAttackPower(Sint32 output[6])1805 Sint32 displayAttackPower(Sint32 output[6])
1806 {
1807 	Sint32 attack = 0;
1808 	Entity* entity = nullptr;
1809 	if ( players[clientnum] && (entity = players[clientnum]->entity) )
1810 	{
1811 		if ( stats[clientnum] )
1812 		{
1813 			bool shapeshiftUseMeleeAttack = false;
1814 			if ( entity->effectShapeshift != NOTHING )
1815 			{
1816 				shapeshiftUseMeleeAttack = true;
1817 				if ( entity->effectShapeshift == CREATURE_IMP
1818 					&& stats[clientnum]->weapon && itemCategory(stats[clientnum]->weapon) == MAGICSTAFF )
1819 				{
1820 					shapeshiftUseMeleeAttack = false;
1821 				}
1822 			}
1823 
1824 			if ( !stats[clientnum]->weapon || shapeshiftUseMeleeAttack )
1825 			{
1826 				// fists
1827 				attack += entity->getAttack();
1828 				output[0] = 0; // melee
1829 				output[1] = attack;
1830 				output[2] = (stats[clientnum]->PROFICIENCIES[PRO_UNARMED] / 20); // bonus from proficiency
1831 				output[3] = entity->getSTR(); // bonus from main attribute
1832 				output[5] = attack - entity->getSTR() - BASE_PLAYER_UNARMED_DAMAGE - output[2]; // bonus from equipment
1833 				// get damage variances.
1834 				output[4] = (attack / 2) * (100 - stats[clientnum]->PROFICIENCIES[PRO_UNARMED]) / 100.f;
1835 				attack -= (output[4] / 2); // attack is the midpoint between max and min damage.
1836 				output[4] = ((output[4] / 2) / static_cast<real_t>(attack)) * 100.f;// return percent variance
1837 				output[1] = attack;
1838 			}
1839 			else
1840 			{
1841 				int weaponskill = getWeaponSkill(stats[clientnum]->weapon);
1842 				real_t variance = 0;
1843 				if ( weaponskill == PRO_RANGED )
1844 				{
1845 					if ( isRangedWeapon(*stats[clientnum]->weapon) )
1846 					{
1847 						attack += entity->getRangedAttack();
1848 						output[0] = 1; // ranged
1849 						output[1] = attack;
1850 						output[2] = stats[clientnum]->weapon->weaponGetAttack(stats[clientnum]); // bonus from weapon
1851 						output[5] = 0;
1852 						if ( stats[clientnum]->shield && rangedWeaponUseQuiverOnAttack(stats[clientnum]) )
1853 						{
1854 							int quiverATK = stats[clientnum]->shield->weaponGetAttack(stats[clientnum]);
1855 							output[5] += quiverATK;
1856 							attack += quiverATK;
1857 						}
1858 						output[3] = entity->getDEX(); // bonus from main attribute
1859 						//output[4] = attack - output[2] - output[3] - BASE_RANGED_DAMAGE; // bonus from proficiency
1860 
1861 						output[4] = (attack / 2) * (100 - stats[clientnum]->PROFICIENCIES[weaponskill]) / 100.f;
1862 						attack -= (output[4] / 2);
1863 						output[4] = ((output[4] / 2) / static_cast<real_t>(attack)) * 100.f;// return percent variance
1864 						output[1] = attack;
1865 					}
1866 					else if ( stats[clientnum]->weapon && stats[clientnum]->weapon->type == TOOL_WHIP )
1867 					{
1868 						attack += entity->getAttack();
1869 						output[0] = 6; // ranged
1870 						output[1] = attack;
1871 						output[2] = stats[clientnum]->weapon->weaponGetAttack(stats[clientnum]); // bonus from weapon
1872 						int atk = entity->getSTR() + entity->getDEX();
1873 						atk = std::min(atk / 2, atk);
1874 						output[3] = atk; // bonus from main attribute
1875 						//output[4] = attack - output[2] - output[3] - BASE_RANGED_DAMAGE; // bonus from proficiency
1876 
1877 						output[4] = (attack / 2) * (100 - stats[clientnum]->PROFICIENCIES[weaponskill]) / 100.f;
1878 						attack -= (output[4] / 2);
1879 						output[4] = ((output[4] / 2) / static_cast<real_t>(attack)) * 100.f;// return percent variance
1880 						output[1] = attack;
1881 					}
1882 					else
1883 					{
1884 						int skillLVL = stats[clientnum]->PROFICIENCIES[PRO_RANGED] / 20;
1885 						attack += entity->getThrownAttack();
1886 						output[0] = 2; // thrown
1887 						output[1] = attack;
1888 						// bonus from weapon
1889 						output[2] = stats[clientnum]->weapon->weaponGetAttack(stats[clientnum]);
1890 						// bonus from dex
1891 						if ( itemCategory(stats[clientnum]->weapon) != POTION )
1892 						{
1893 							output[3] = entity->getDEX() / 4;
1894 						}
1895 						else
1896 						{
1897 							output[3] = 0.f;
1898 						}
1899 						// bonus from proficiency
1900 						output[4] = attack - output[2] - output[3] - BASE_THROWN_DAMAGE;
1901 						output[5] = 0; // bonus from equipment
1902 					}
1903 				}
1904 				else if ( (weaponskill >= PRO_SWORD && weaponskill <= PRO_POLEARM) )
1905 				{
1906 					// melee weapon
1907 					attack += entity->getAttack();
1908 					output[0] = 3; // melee
1909 					output[1] = attack;
1910 					output[2] = stats[clientnum]->weapon->weaponGetAttack(stats[clientnum]); // bonus from weapon
1911 					output[3] = entity->getSTR(); // bonus from main attribute
1912 					if ( weaponskill == PRO_AXE )
1913 					{
1914 						output[5] = 1; // bonus from equipment
1915 						attack += 1;
1916 					}
1917 					// get damage variances.
1918 					if ( weaponskill == PRO_POLEARM )
1919 					{
1920 						output[4] = (attack / 3) * (100 - stats[clientnum]->PROFICIENCIES[weaponskill]) / 100.f;
1921 					}
1922 					else
1923 					{
1924 						output[4] = (attack / 2) * (100 - stats[clientnum]->PROFICIENCIES[weaponskill]) / 100.f;
1925 					}
1926 					attack -= (output[4] / 2); // attack is the midpoint between max and min damage.
1927 					output[4] = ((output[4] / 2) / static_cast<real_t>(attack)) * 100.f;// return percent variance
1928 					output[1] = attack;
1929 				}
1930 				else if ( itemCategory(stats[clientnum]->weapon) == MAGICSTAFF ) // staffs.
1931 				{
1932 					attack = 0;
1933 					output[0] = 5; // staffs
1934 					output[1] = attack;
1935 					output[2] = 0; // bonus from weapon
1936 					output[3] = 0; // bonus from main attribute
1937 					output[4] = 0; // bonus from proficiency
1938 					output[5] = 0; // bonus from equipment
1939 				}
1940 				else // tools etc.
1941 				{
1942 					attack += entity->getAttack();
1943 					output[0] = 4; // tools
1944 					output[1] = attack;
1945 					output[2] = 0; // bonus from weapon
1946 					output[3] = entity->getSTR(); // bonus from main attribute
1947 					output[4] = 0; // bonus from proficiency
1948 					output[5] = attack - entity->getSTR() - BASE_MELEE_DAMAGE; // bonus from equipment
1949 				}
1950 			}
1951 		}
1952 	}
1953 	else
1954 	{
1955 		attack = 0;
1956 	}
1957 	return attack;
1958 }
1959 
attackHoverText(Sint32 input[6])1960 void attackHoverText(Sint32 input[6])
1961 {
1962 	int pad_y = 346; // 262 px.
1963 	int pad_x = 8; // 8 px.
1964 	int off_h = TTF12_HEIGHT - 4; // 12px. height of stat line.
1965 	int off_w = 216; // 216px. width of stat line.
1966 	int i = 0;
1967 	int j = 0;
1968 	SDL_Rect src;
1969 	SDL_Rect pos;
1970 	int tooltip_offset_x = 16; // 16px.
1971 	int tooltip_offset_y = 16; // 16px.
1972 	int tooltip_base_h = TTF12_HEIGHT;
1973 	int tooltip_pad_h = 8;
1974 	int tooltip_text_pad_x = 16;
1975 	int numInfoLines = 3;
1976 	char buf[128] = "";
1977 
1978 	if ( uiscale_charactersheet )
1979 	{
1980 		off_h = TTF16_HEIGHT - 4;
1981 		pad_y += 126;
1982 		off_w = 280;
1983 	}
1984 
1985 	if ( attributespage == 0 )
1986 	{
1987 		if ( mouseInBounds(pad_x, pad_x + off_w, pad_y, pad_y + off_h) )
1988 		{
1989 			char tooltipHeader[32] = "";
1990 			switch ( input[0] )
1991 			{
1992 				case 0: // fists
1993 					snprintf(tooltipHeader, strlen(language[2529]), language[2529]);
1994 					numInfoLines = 4;
1995 					break;
1996 				case 1: // ranged
1997 					snprintf(tooltipHeader, strlen(language[2530]), language[2530]);
1998 					numInfoLines = 4;
1999 					break;
2000 				case 2: // thrown
2001 					snprintf(tooltipHeader, strlen(language[2531]), language[2531]);
2002 					numInfoLines = 3;
2003 					break;
2004 				case 3: // melee
2005 					snprintf(tooltipHeader, strlen(language[2532]), language[2532]);
2006 					numInfoLines = 4;
2007 					break;
2008 				case 4: // tools
2009 					snprintf(tooltipHeader, strlen(language[2540]), language[2540]);
2010 					numInfoLines = 2;
2011 					break;
2012 				case 5: // staffs
2013 					snprintf(tooltipHeader, strlen(language[2541]), language[2541]);
2014 					numInfoLines = 0;
2015 					break;
2016 				case 6: // whip
2017 					snprintf(tooltipHeader, strlen(language[2530]), language[2530]);
2018 					numInfoLines = 3;
2019 					break;
2020 				default:
2021 					break;
2022 			}
2023 
2024 			// get tooltip draw location.
2025 			src.x = mousex + tooltip_offset_x;
2026 			src.y = mousey + tooltip_offset_y;
2027 			src.h = std::max(tooltip_base_h * (numInfoLines + 1) + tooltip_pad_h, tooltip_base_h * (2) + tooltip_pad_h);
2028 			src.w = 256;
2029 			if ( input[0] == 6 ) // whip tooltip wider
2030 			{
2031 				src.w += 32;
2032 			}
2033 			drawTooltip(&src);
2034 
2035 			// draw header
2036 			Uint32 color = uint32ColorWhite(*mainsurface);
2037 			ttfPrintTextColor(ttf12, src.x + 4, src.y + 4, color, false, tooltipHeader);
2038 			if ( input[1] >= 0 )
2039 			{
2040 				// attack >= 0
2041 				color = SDL_MapRGB(mainsurface->format, 0, 255, 255);
2042 			}
2043 			else
2044 			{
2045 				// attack < 0
2046 				color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
2047 			}
2048 			snprintf(tooltipHeader, 32, language[2533], input[1]);
2049 			ttfPrintTextColor(ttf12, src.x + 4, src.y + 4, color, false, tooltipHeader);
2050 
2051 			for ( j = 0; j < numInfoLines && numInfoLines > 0; j++ )
2052 			{
2053 				int infoText_x = src.x + 4 + tooltip_text_pad_x;
2054 				int infoText_y = src.y + 4 + (tooltip_base_h * (j + 1));
2055 				Uint32 color = uint32ColorWhite(*mainsurface);
2056 
2057 				if ( input[0] == 0 ) // fists
2058 				{
2059 					switch ( j )
2060 					{
2061 						case 0:
2062 							snprintf(buf, longestline(language[3209]), language[3209], input[2]);
2063 							break;
2064 						case 1:
2065 							snprintf(buf, longestline(language[2534]), language[2534], input[3]);
2066 							break;
2067 						case 2:
2068 							snprintf(buf, longestline(language[2539]), language[2539], input[4]);
2069 							break;
2070 						case 3:
2071 							snprintf(buf, longestline(language[2536]), language[2536], input[5]);
2072 						default:
2073 							break;
2074 					}
2075 				}
2076 				else if ( input[0] == 1 ) // ranged
2077 				{
2078 					switch ( j )
2079 					{
2080 						case 0:
2081 							snprintf(buf, longestline(language[2538]), language[2538], input[2]);
2082 							break;
2083 						case 1:
2084 							snprintf(buf, longestline(language[2535]), language[2535], input[3]);
2085 							break;
2086 						case 2:
2087 							snprintf(buf, longestline(language[2539]), language[2539], input[4]);
2088 							break;
2089 						case 3:
2090 							snprintf(buf, longestline(language[2536]), language[2536], input[5]);
2091 							break;
2092 						default:
2093 							break;
2094 					}
2095 				}
2096 				else if ( input[0] == 2 ) // thrown
2097 				{
2098 					switch ( j )
2099 					{
2100 						case 0:
2101 							snprintf(buf, longestline(language[2538]), language[2538], input[2]);
2102 							break;
2103 						case 1:
2104 							snprintf(buf, longestline(language[2535]), language[2535], input[3]);
2105 							break;
2106 						case 2:
2107 							snprintf(buf, longestline(language[2537]), language[2537], input[4]);
2108 							break;
2109 						default:
2110 							break;
2111 					}
2112 				}
2113 				else if ( input[0] == 3 ) // melee weapons
2114 				{
2115 					switch ( j )
2116 					{
2117 						case 0:
2118 							snprintf(buf, longestline(language[2538]), language[2538], input[2]);
2119 							break;
2120 						case 1:
2121 							snprintf(buf, longestline(language[2534]), language[2534], input[3]);
2122 							break;
2123 						case 2:
2124 							snprintf(buf, longestline(language[2539]), language[2539], input[4]);
2125 							break;
2126 						case 3:
2127 							snprintf(buf, longestline(language[2536]), language[2536], input[5]);
2128 						default:
2129 							break;
2130 					}
2131 				}
2132 				else if ( input[0] == 4 ) // tools
2133 				{
2134 					switch ( j )
2135 					{
2136 						case 0:
2137 							snprintf(buf, longestline(language[2534]), language[2534], input[3]);
2138 							break;
2139 						case 1:
2140 							snprintf(buf, longestline(language[2536]), language[2536], input[5]);
2141 							break;
2142 						default:
2143 							break;
2144 					}
2145 				}
2146 				else if ( input[0] == 5 ) // staff
2147 				{
2148 
2149 				}
2150 				else if ( input[0] == 6 ) // whip
2151 				{
2152 					switch ( j )
2153 					{
2154 						case 0:
2155 							snprintf(buf, 127, language[2538], input[2]);
2156 							break;
2157 						case 1:
2158 							snprintf(buf, longestline(language[3458]), language[3458], input[3]);
2159 							break;
2160 						case 2:
2161 							snprintf(buf, longestline(language[2539]), language[2539], input[4]);
2162 							break;
2163 						default:
2164 							break;
2165 					}
2166 				}
2167 				ttfPrintTextColor(ttf12, infoText_x, infoText_y, color, false, buf);
2168 			}
2169 		}
2170 	}
2171 }
2172 
printStatBonus(TTF_Font * outputFont,Sint32 stat,Sint32 statWithModifiers,int x,int y)2173 void printStatBonus(TTF_Font* outputFont, Sint32 stat, Sint32 statWithModifiers, int x, int y)
2174 {
2175 	Uint32 color = 0;
2176 	char bonusText[4] = "";
2177 
2178 	if ( statWithModifiers - stat == 0 )
2179 	{
2180 		color = uint32ColorWhite(*mainsurface);
2181 		snprintf(bonusText, 4, "%2d", statWithModifiers);
2182 	}
2183 	else if ( statWithModifiers - stat < 0 )
2184 	{
2185 		color = uint32ColorRed(*mainsurface);
2186 		snprintf(bonusText, 4, "%2d", statWithModifiers);
2187 	}
2188 	if ( statWithModifiers - stat > 0 )
2189 	{
2190 		color = uint32ColorGreen(*mainsurface);
2191 		snprintf(bonusText, 4, "%2d", statWithModifiers);
2192 	}
2193 
2194 	ttfPrintTextFormattedColor(outputFont, x, y, color, bonusText);
2195 }
2196