1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: item_usage_funcs.cpp
5 	Desc: implements the functions that handle item usage (eg handle
6 	potion effects, zap a staff, whatever else you can think of).
7 
8 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
9 	See LICENSE for details.
10 
11 -------------------------------------------------------------------------------*/
12 
13 #include "main.hpp"
14 #include "game.hpp"
15 #include "stat.hpp"
16 #include "items.hpp"
17 #include "sound.hpp"
18 #include "entity.hpp"
19 #include "magic/magic.hpp"
20 #include "interface/interface.hpp"
21 #include "scores.hpp"
22 #include "net.hpp"
23 #include "monster.hpp"
24 #include "player.hpp"
25 #include "collision.hpp"
26 #include "scores.hpp"
27 
item_PotionWater(Item * & item,Entity * entity,Entity * usedBy)28 bool item_PotionWater(Item*& item, Entity* entity, Entity* usedBy)
29 {
30 	if ( !entity )
31 	{
32 		return false;
33 	}
34 
35 	int skillLVL = 0;
36 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
37 	{
38 		Stat* usedByStats = usedBy->getStats();
39 		if ( usedByStats )
40 		{
41 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
42 		}
43 	}
44 
45 	node_t* node;
46 	int player = -1;
47 	Stat* stats;
48 
49 	if ( entity->behavior == &actPlayer )
50 	{
51 		player = entity->skill[2];
52 	}
53 	stats = entity->getStats();
54 	if ( !stats )
55 	{
56 		return false;
57 	}
58 
59 	if ( stats->amulet != NULL )
60 	{
61 		if ( stats->amulet->type == AMULET_STRANGULATION )
62 		{
63 			if ( player == clientnum )
64 			{
65 				messagePlayer(player, language[750]);
66 			}
67 			return false;
68 		}
69 	}
70 	if ( stats->EFFECTS[EFF_VOMITING] )
71 	{
72 		if ( player == clientnum )
73 		{
74 			messagePlayer(player, language[751]);
75 		}
76 		return false;
77 	}
78 
79 	if ( multiplayer != CLIENT ) // server/singleplayer
80 	{
81 		// play drink sound
82 		if ( item->beatitude > 0 )
83 		{
84 			if ( stats->type == GHOUL ||
85 				stats->type == LICH ||
86 				stats->type == LICH_FIRE ||
87 				stats->type == LICH_ICE ||
88 				stats->type == SHADOW ||
89 				stats->type == SKELETON ||
90 				stats->type == VAMPIRE )
91 			{
92 				//Blessed water damages undead.
93 				int damage = -(20 * item->beatitude);
94 				entity->modHP(damage);
95 				playSoundEntity(entity, 28, 64);
96 				playSoundEntity(entity, 249, 128);
97 				entity->setObituary(language[1533]);
98 			}
99 			else
100 			{
101 				if ( stats->type != AUTOMATON )
102 				{
103 					entity->modHP(5 * item->beatitude);
104 					playSoundEntity(entity, 168, 128);
105 					spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
106 				}
107 				playSoundEntity(entity, 52, 64);
108 			}
109 		}
110 		else
111 		{
112 			if ( stats->type == VAMPIRE )
113 			{
114 				entity->modHP(-5);
115 				playSoundEntity(entity, 28, 64);
116 				playSoundEntity(entity, 249, 128);
117 				entity->setObituary(language[1533]);
118 			}
119 			else
120 			{
121 				playSoundEntity(entity, 52, 64);
122 			}
123 		}
124 		if ( player >= 0 && player < MAXPLAYERS )
125 		{
126 			if ( stats && stats->EFFECTS[EFF_POLYMORPH] )
127 			{
128 				if ( stats->EFFECTS[EFF_POLYMORPH] )
129 				{
130 					entity->setEffect(EFF_POLYMORPH, false, 0, true);
131 					entity->effectPolymorph = 0;
132 					serverUpdateEntitySkill(entity, 50);
133 
134 					messagePlayer(player, language[3192]);
135 					messagePlayer(player, language[3185]);
136 				}
137 				/*if ( stats->EFFECTS[EFF_SHAPESHIFT] )
138 				{
139 					entity->setEffect(EFF_SHAPESHIFT, false, 0, true);
140 					entity->effectShapeshift = 0;
141 					serverUpdateEntitySkill(entity, 53);
142 
143 					messagePlayer(player, language[3418]);
144 					messagePlayer(player, language[3417]);
145 				}*/
146 				playSoundEntity(entity, 400, 92);
147 				createParticleDropRising(entity, 593, 1.f);
148 				serverSpawnMiscParticles(entity, PARTICLE_EFFECT_RISING_DROP, 593);
149 			}
150 			if ( stats->type == AUTOMATON )
151 			{
152 				Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
153 				messagePlayerColor(player, color, language[3700]);
154 				stats->HUNGER -= 200; //Lose boiler
155 				int mpAmount = 3 + rand() % 6;
156 				if ( item->beatitude > 0 )
157 				{
158 					mpAmount += 2 + rand() % 4;
159 				}
160 				players[player]->entity->modMP(mpAmount); //Raise temperature because steam.
161 				serverUpdateHunger(player);
162 			}
163 		}
164 		if ( player != clientnum )
165 		{
166 			consumeItem(item, player);
167 			return true;
168 		}
169 	}
170 
171 	auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
172 	auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
173 
174 	// code below is only run by the player that drank the potion.
175 	// if it was thrown, then the function returns in the above code as processed by the server.
176 
177 	if ( item->beatitude == 0 )
178 	{
179 		if ( stats->type == VAMPIRE )
180 		{
181 			Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
182 			messagePlayerColor(player, color, language[3183]);
183 			camera_shakex += .1;
184 			camera_shakey += 10;
185 		}
186 		else if ( stats->type != AUTOMATON )
187 		{
188 			messagePlayer(player, language[752]);
189 		}
190 	}
191 	else if ( item->beatitude > 0 )
192 	{
193 		if ( stats->type == SKELETON )
194 		{
195 			Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
196 			messagePlayerColor(player, color, language[3184]);
197 			camera_shakex += .1;
198 			camera_shakey += 10;
199 		}
200 		else if ( stats->type == GHOUL ||
201 			stats->type == LICH ||
202 			stats->type == LICH_FIRE ||
203 			stats->type == LICH_ICE ||
204 			stats->type == SHADOW ||
205 			stats->type == VAMPIRE )
206 		{
207 			Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
208 			messagePlayerColor(player, color, language[3183]);
209 			camera_shakex += .1;
210 			camera_shakey += 10;
211 		}
212 		else if ( stats->type != AUTOMATON )
213 		{
214 			messagePlayer(player, language[753]);
215 		}
216 	}
217 	else if ( item->beatitude < 0 )
218 	{
219 		if ( stats->type == VAMPIRE )
220 		{
221 			Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
222 			messagePlayerColor(player, color, language[3183]);
223 			camera_shakex += .1;
224 			camera_shakey += 10;
225 		}
226 		messagePlayer(player, language[755]);
227 
228 		// choose a random piece of worn equipment to curse!
229 		int tryIndex = rand() % 8;
230 		int startIndex = tryIndex;
231 		int armornum = 0;
232 		bool breakloop = false;
233 		Item* toCurse = nullptr;
234 		// curse random item.
235 		while ( !toCurse && !breakloop )
236 		{
237 			switch ( tryIndex )
238 			{
239 				// intentional fall throughs...
240 				case 0:
241 					if ( stats->weapon != nullptr && itemCategory(stats->weapon) != POTION
242 						&& stats->weapon->beatitude >= 0 )
243 					{
244 						toCurse = stats->weapon;
245 						armornum = 0;
246 						break;
247 					}
248 				case 1:
249 					if ( stats->helmet != nullptr && stats->helmet->beatitude >= 0 )
250 					{
251 						toCurse = stats->helmet;
252 						armornum = 1;
253 						break;
254 					}
255 				case 2:
256 					if ( stats->breastplate != nullptr && stats->breastplate->beatitude >= 0 )
257 					{
258 						toCurse = stats->breastplate;
259 						armornum = 2;
260 						break;
261 					}
262 				case 3:
263 					if ( stats->gloves != nullptr && stats->gloves->beatitude >= 0 )
264 					{
265 						toCurse = stats->gloves;
266 						armornum = 3;
267 						break;
268 					}
269 				case 4:
270 					if ( stats->shoes != nullptr && stats->shoes->beatitude >= 0 )
271 					{
272 						toCurse = stats->shoes;
273 						armornum = 4;
274 						break;
275 					}
276 				case 5:
277 					if ( stats->shield != nullptr && stats->shield->beatitude >= 0 )
278 					{
279 						toCurse = stats->shield;
280 						armornum = 5;
281 						break;
282 					}
283 				case 6:
284 					if ( stats->cloak != nullptr && stats->cloak->beatitude >= 0 )
285 					{
286 						toCurse = stats->cloak;
287 						armornum = 6;
288 						break;
289 					}
290 				case 7:
291 					if ( stats->mask != nullptr && stats->mask->beatitude >= 0 )
292 					{
293 						toCurse = stats->mask;
294 						armornum = 7;
295 						break;
296 					}
297 					++tryIndex;
298 					if ( tryIndex > 7 )
299 					{
300 						// loop back around.
301 						tryIndex = 0;
302 					}
303 					if ( tryIndex == startIndex )
304 					{
305 						// couldn't find a piece of armor, break.
306 						breakloop = true;
307 						toCurse = nullptr;
308 						break;
309 					}
310 				default:
311 					break;
312 			}
313 		}
314 
315 		if ( toCurse )
316 		{
317 			if ( toCurse->beatitude <= 0 )
318 			{
319 				--toCurse->beatitude;
320 			}
321 			else
322 			{
323 				toCurse->beatitude = -toCurse->beatitude;
324 				if ( itemCategory(toCurse) == WEAPON && stats->type == SUCCUBUS )
325 				{
326 					steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
327 				}
328 			}
329 			messagePlayer(player, language[858], toCurse->getName());
330 			if ( multiplayer == CLIENT )
331 			{
332 				strcpy((char*)net_packet->data, "BEAT");
333 				net_packet->data[4] = clientnum;
334 				net_packet->data[5] = armornum;
335 				net_packet->data[6] = toCurse->beatitude + 100;
336 				net_packet->address.host = net_server.host;
337 				net_packet->address.port = net_server.port;
338 				net_packet->len = 7;
339 				sendPacketSafe(net_sock, -1, net_packet, 0);
340 				//messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
341 			}
342 			consumeItem(item, player);
343 			return true;
344 		}
345 
346 		// else randomly curse an item in the entity's inventory, item must be +0 or higher.
347 		int items = 0;
348 		for ( node = stats->inventory.first; node != NULL; node = node->next )
349 		{
350 			Item* target = (Item*)node->element;
351 			if ( target && !itemIsEquipped(target, player) && itemCategory(target) != SPELL_CAT && target->beatitude >= 0 )
352 			{
353 				items++;
354 			}
355 		}
356 		if ( items == 0 )
357 		{
358 			consumeItem(item, player);
359 			return true;
360 		}
361 		int itemToCurse = rand() % items;
362 		items = 0;
363 		for ( node = stats->inventory.first; node != NULL; node = node->next )
364 		{
365 			Item* target = (Item*)node->element;
366 			if ( target && !itemIsEquipped(target, player) && itemCategory(target) != SPELL_CAT && target->beatitude >= 0 )
367 			{
368 				if ( items == itemToCurse )
369 				{
370 					messagePlayer(player, language[858], target->getName());
371 					if ( target->beatitude <= 0 )
372 					{
373 						--target->beatitude;
374 					}
375 					else
376 					{
377 						target->beatitude = -target->beatitude;
378 						if ( itemCategory(target) == WEAPON && stats->type == SUCCUBUS )
379 						{
380 							steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
381 						}
382 					}
383 					break;
384 				}
385 				items++;
386 			}
387 		}
388 	}
389 	consumeItem(item, player);
390 	return true;
391 }
392 
item_PotionBooze(Item * & item,Entity * entity,Entity * usedBy,bool shouldConsumeItem)393 bool item_PotionBooze(Item*& item, Entity* entity, Entity* usedBy, bool shouldConsumeItem)
394 {
395 	if (!entity)
396 	{
397 		return false;
398 	}
399 
400 	int skillLVL = 0;
401 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
402 	{
403 		Stat* usedByStats = usedBy->getStats();
404 		if ( usedByStats )
405 		{
406 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
407 		}
408 	}
409 
410 	int player = -1;
411 	Stat* stats;
412 
413 	if ( entity->behavior == &actPlayer )
414 	{
415 		player = entity->skill[2];
416 	}
417 	stats = entity->getStats();
418 	if ( !stats )
419 	{
420 		return false;
421 	}
422 
423 	if ( stats->amulet != nullptr )
424 	{
425 		if ( stats->amulet->type == AMULET_STRANGULATION )
426 		{
427 			if ( player == clientnum )
428 			{
429 				messagePlayer(player, language[750]);
430 			}
431 			return false;
432 		}
433 	}
434 	if ( stats->EFFECTS[EFF_VOMITING] )
435 	{
436 		if ( player == clientnum )
437 		{
438 			messagePlayer(player, language[751]);
439 		}
440 		return false;
441 	}
442 	if ( multiplayer == CLIENT )
443 	{
444 		consumeItem(item, player);
445 		return true;
446 	}
447 
448 	messagePlayer(player, language[758]);
449 	messagePlayer(player, language[759]);
450 	stats->EFFECTS[EFF_DRUNK] = true;
451 	if ( player >= 0 )
452 	{
453 		stats->EFFECTS_TIMERS[EFF_DRUNK] = 2400 + rand() % 1200;
454 		if ( stats->type != GOATMAN )
455 		{
456 			stats->EFFECTS_TIMERS[EFF_DRUNK] = std::max(300, stats->EFFECTS_TIMERS[EFF_DRUNK] - (entity->getPER() + entity->getCON()) * 40);
457 		}
458 		if ( stats->EFFECTS[EFF_WITHDRAWAL] )
459 		{
460 			int hangoverReliefDuration = EFFECT_WITHDRAWAL_BASE_TIME; // 8 minutes
461 			switch ( rand() % 3 )
462 			{
463 				case 0:
464 					hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 8); // 8 + 8 minutes
465 					break;
466 				case 1:
467 					hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 4); // 8 + 4 minutes
468 					break;
469 				case 2:
470 					// intentional fall through
471 				default:
472 					break;
473 			}
474 			entity->setEffect(EFF_WITHDRAWAL, false, hangoverReliefDuration, true);
475 			serverUpdatePlayerGameplayStats(player, STATISTICS_FUNCTIONAL, 1);
476 			messagePlayerColor(player, SDL_MapRGB(mainsurface->format, 0, 255, 0), language[3250]);
477 		}
478 		else if ( stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] > 0 && stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] < EFFECT_WITHDRAWAL_BASE_TIME )
479 		{
480 			stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] = EFFECT_WITHDRAWAL_BASE_TIME;
481 		}
482 	}
483 	else
484 	{
485 		stats->EFFECTS_TIMERS[EFF_DRUNK] = 2400 + rand() % 1200;
486 	}
487 
488 	if ( svFlags & SV_FLAG_HUNGER )
489 	{
490 		if ( entity->behavior == &actPlayer )
491 		{
492 			if ( stats->type != SKELETON && stats->type != AUTOMATON )
493 			{
494 				if ( stats->HUNGER < 1500 )
495 				{
496 					stats->HUNGER = std::min(1499, stats->HUNGER + 100);
497 				}
498 			}
499 			if ( stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
500 			{
501 				stats->HUNGER += 250;
502 			}
503 		}
504 	}
505 	else
506 	{
507 		// hunger off.
508 		if ( entity->behavior == &actPlayer && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
509 		{
510 			entity->modMP(5 * (1 + item->beatitude));
511 		}
512 	}
513 	entity->modHP(5 * (1 + item->beatitude));
514 	// results of eating
515 	updateHungerMessages(entity, stats, item);
516 	serverUpdateEffects(player);
517 
518 	// play drink sound
519 	playSoundEntity(entity, 52, 64);
520 	playSoundEntity(entity, 168, 128);
521 	spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
522 	if ( shouldConsumeItem )
523 	{
524 		consumeItem(item, player);
525 		return true;
526 	}
527 	return false;
528 }
529 
item_PotionJuice(Item * & item,Entity * entity,Entity * usedBy)530 bool item_PotionJuice(Item*& item, Entity* entity, Entity* usedBy)
531 {
532 	if (!entity)
533 	{
534 		return false;
535 	}
536 
537 	int skillLVL = 0;
538 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
539 	{
540 		Stat* usedByStats = usedBy->getStats();
541 		if ( usedByStats )
542 		{
543 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
544 		}
545 	}
546 
547 	int player = -1;
548 	Stat* stats;
549 
550 	if ( entity->behavior == &actPlayer )
551 	{
552 		player = entity->skill[2];
553 	}
554 	stats = entity->getStats();
555 	if ( !stats )
556 	{
557 		return false;
558 	}
559 
560 	if ( stats->amulet != NULL )
561 	{
562 		if ( stats->amulet->type == AMULET_STRANGULATION )
563 		{
564 			if ( player == clientnum )
565 			{
566 				messagePlayer(player, language[750]);
567 			}
568 			return false;
569 		}
570 	}
571 	if ( stats->EFFECTS[EFF_VOMITING] )
572 	{
573 		if ( player == clientnum )
574 		{
575 			messagePlayer(player, language[751]);
576 		}
577 		return false;
578 	}
579 	if ( multiplayer == CLIENT )
580 	{
581 		consumeItem(item, player);
582 		return true;
583 	}
584 
585 	if ( item->beatitude < 0 )
586 	{
587 		//Cursed effect inebriates you.
588 		messagePlayer(player, language[2900]);
589 		messagePlayer(player, language[758]);
590 		messagePlayer(player, language[759]);
591 		stats->EFFECTS[EFF_DRUNK] = true;
592 		if ( player >= 0 )
593 		{
594 			stats->EFFECTS_TIMERS[EFF_DRUNK] = 2400 + rand() % 1200;
595 			if ( stats->type != GOATMAN )
596 			{
597 				stats->EFFECTS_TIMERS[EFF_DRUNK] = std::max(300, stats->EFFECTS_TIMERS[EFF_DRUNK] - (entity->getPER() + entity->getCON()) * 40);
598 			}
599 			if ( stats->EFFECTS[EFF_WITHDRAWAL] )
600 			{
601 				int hangoverReliefDuration = EFFECT_WITHDRAWAL_BASE_TIME; // 8 minutes
602 				switch ( rand() % 3 )
603 				{
604 					case 0:
605 						hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 8); // 8 + 8 minutes
606 						break;
607 					case 1:
608 						hangoverReliefDuration += (TICKS_PER_SECOND * 60 * 4); // 8 + 4 minutes
609 						break;
610 					case 2:
611 						// intentional fall through
612 					default:
613 						break;
614 				}
615 				entity->setEffect(EFF_WITHDRAWAL, false, hangoverReliefDuration, true);
616 				serverUpdatePlayerGameplayStats(player, STATISTICS_FUNCTIONAL, 1);
617 				messagePlayerColor(player, SDL_MapRGB(mainsurface->format, 0, 255, 0), language[3250]);
618 			}
619 			else if ( stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] > 0 && stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] < EFFECT_WITHDRAWAL_BASE_TIME )
620 			{
621 				stats->EFFECTS_TIMERS[EFF_WITHDRAWAL] = EFFECT_WITHDRAWAL_BASE_TIME;
622 			}
623 		}
624 		else
625 		{
626 			stats->EFFECTS_TIMERS[EFF_DRUNK] = 1000 + rand() % 300;
627 		}
628 		entity->modHP(5);
629 
630 		if ( svFlags & SV_FLAG_HUNGER )
631 		{
632 			if ( entity->behavior == &actPlayer )
633 			{
634 				if ( stats->type != SKELETON && stats->type != AUTOMATON )
635 				{
636 					if ( stats->HUNGER < 1500 )
637 					{
638 						stats->HUNGER = std::min(1499, stats->HUNGER + 50);
639 					}
640 				}
641 				if ( stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
642 				{
643 					stats->HUNGER += 200;
644 				}
645 			}
646 		}
647 		else
648 		{
649 			// hunger off.
650 			if ( entity->behavior == &actPlayer && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
651 			{
652 				entity->modMP(5);
653 			}
654 		}
655 
656 		serverUpdateEffects(player);
657 	}
658 	else
659 	{
660 		messagePlayer(player, language[760]);
661 		entity->modHP(5 * (1 + item->beatitude));
662 
663 		if ( svFlags & SV_FLAG_HUNGER )
664 		{
665 			if ( entity->behavior == &actPlayer )
666 			{
667 				if ( stats->type != SKELETON && stats->type != AUTOMATON )
668 				{
669 					if ( stats->HUNGER < 1500 )
670 					{
671 						stats->HUNGER = std::min(1499, stats->HUNGER + 50);
672 					}
673 				}
674 				if ( stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
675 				{
676 					stats->HUNGER += 200;
677 				}
678 			}
679 		}
680 		else
681 		{
682 			// hunger off.
683 			if ( entity->behavior == &actPlayer && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
684 			{
685 				entity->modMP(5 * (1 + item->beatitude));
686 			}
687 		}
688 	}
689 
690 	// results of eating
691 	updateHungerMessages(entity, stats, item);
692 
693 	// play drink sound
694 	playSoundEntity(entity, 52, 64);
695 	playSoundEntity(entity, 168, 128);
696 	spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
697 	consumeItem(item, player);
698 	return true;
699 }
700 
item_PotionSickness(Item * & item,Entity * entity,Entity * usedBy)701 bool item_PotionSickness(Item*& item, Entity* entity, Entity* usedBy)
702 {
703 	if (!entity)
704 	{
705 		return false;
706 	}
707 
708 	int skillLVL = 0;
709 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
710 	{
711 		Stat* usedByStats = usedBy->getStats();
712 		if ( usedByStats )
713 		{
714 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
715 		}
716 	}
717 
718 	int player = -1;
719 	Stat* stats;
720 
721 	if ( entity->behavior == &actPlayer )
722 	{
723 		player = entity->skill[2];
724 	}
725 	stats = entity->getStats();
726 	if ( !stats )
727 	{
728 		return false;
729 	}
730 
731 	auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
732 	auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
733 
734 	if ( entity == NULL )
735 	{
736 		return false;
737 	}
738 	if ( stats->amulet != NULL )
739 	{
740 		if ( stats->amulet->type == AMULET_STRANGULATION )
741 		{
742 			if ( player == clientnum )
743 			{
744 				messagePlayer(player, language[750]);
745 			}
746 			return false;
747 		}
748 	}
749 	if ( stats->EFFECTS[EFF_VOMITING] )
750 	{
751 		if ( player == clientnum )
752 		{
753 			messagePlayer(player, language[751]);
754 		}
755 		return false;
756 	}
757 	if ( multiplayer == CLIENT || player == 0 )
758 	{
759 		camera_shakex += .1;
760 		camera_shakey += 10;
761 		if ( multiplayer == CLIENT )
762 		{
763 			consumeItem(item, player);
764 			return true;
765 		}
766 	}
767 
768 	int damage = (5 + 5 * abs(item->beatitude)) * potionDamageSkillMultipliers[std::min(skillLVL, 5)];
769 	int chance = damage / 8;
770 	if ( player >= 0 && usedBy == entity )
771 	{
772 		damage /= 2;
773 	}
774 	else
775 	{
776 		damage -= (rand() % (1 + chance));
777 	}
778 	messagePlayer(player, language[761]);
779 	entity->modHP(-damage);
780 	stats->EFFECTS[EFF_POISONED] = true;
781 	if ( stats->type == LICH || stats->type == SHOPKEEPER || stats->type == DEVIL
782 		|| stats->type == MINOTAUR || stats->type == LICH_FIRE || stats->type == LICH_ICE )
783 	{
784 		stats->EFFECTS_TIMERS[EFF_POISONED] = TICKS_PER_SECOND * 15;
785 	}
786 	playSoundEntity(entity, 28, 64);
787 	serverUpdateEffects(player);
788 
789 	// set obituary
790 	entity->setObituary(language[1535]);
791 
792 	// play drink sound
793 	playSoundEntity(entity, 52, 64);
794 	consumeItem(item, player);
795 	return true;
796 }
797 
item_PotionConfusion(Item * & item,Entity * entity,Entity * usedBy)798 bool item_PotionConfusion(Item*& item, Entity* entity, Entity* usedBy)
799 {
800 	if (!entity)
801 	{
802 		return false;
803 	}
804 
805 	int skillLVL = 0;
806 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
807 	{
808 		Stat* usedByStats = usedBy->getStats();
809 		if ( usedByStats )
810 		{
811 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
812 		}
813 	}
814 
815 	int player = -1;
816 	Stat* stats;
817 
818 	if ( entity->behavior == &actPlayer )
819 	{
820 		player = entity->skill[2];
821 	}
822 	stats = entity->getStats();
823 	if ( !stats )
824 	{
825 		return false;
826 	}
827 
828 	if ( stats->amulet != NULL )
829 	{
830 		if ( stats->amulet->type == AMULET_STRANGULATION )
831 		{
832 			if ( player == clientnum )
833 			{
834 				messagePlayer(player, language[750]);
835 			}
836 			return false;
837 		}
838 	}
839 	if ( stats->EFFECTS[EFF_VOMITING] )
840 	{
841 		if ( player == clientnum )
842 		{
843 			messagePlayer(player, language[751]);
844 		}
845 		return false;
846 	}
847 	if ( multiplayer == CLIENT )
848 	{
849 		consumeItem(item, player);
850 		return true;
851 	}
852 
853 	messagePlayer(player, language[762]);
854 	stats->EFFECTS[EFF_CONFUSED] = true;
855 	if ( player >= 0 )
856 	{
857 		stats->EFFECTS_TIMERS[EFF_CONFUSED] = std::max(300, 1800 - (entity->getPER() + entity->getCON()) * 20);
858 	}
859 	else
860 	{
861 		stats->EFFECTS_TIMERS[EFF_CONFUSED] = 1800;
862 	}
863 	if ( entity->behavior == &actMonster )
864 	{
865 		entity->monsterTarget = 0; // monsters forget what they're doing
866 	}
867 	serverUpdateEffects(player);
868 
869 	// play drink sound
870 	playSoundEntity(entity, 52, 64);
871 	consumeItem(item, player);
872 	return true;
873 }
874 
item_PotionCureAilment(Item * & item,Entity * entity,Entity * usedBy)875 bool item_PotionCureAilment(Item*& item, Entity* entity, Entity* usedBy)
876 {
877 	if (!entity)
878 	{
879 		return false;
880 	}
881 
882 	int skillLVL = 0;
883 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
884 	{
885 		Stat* usedByStats = usedBy->getStats();
886 		if ( usedByStats )
887 		{
888 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
889 		}
890 	}
891 
892 	int player = -1;
893 	Stat* stats;
894 	int c;
895 
896 	if ( entity->behavior == &actPlayer )
897 	{
898 		player = entity->skill[2];
899 	}
900 	stats = entity->getStats();
901 	if ( !stats )
902 	{
903 		return false;
904 	}
905 
906 	if ( stats->amulet != NULL )
907 	{
908 		if ( stats->amulet->type == AMULET_STRANGULATION )
909 		{
910 			if ( player == clientnum )
911 			{
912 				messagePlayer(player, language[750]);
913 			}
914 			return false;
915 		}
916 	}
917 	if ( stats->EFFECTS[EFF_VOMITING] )
918 	{
919 		if ( player == clientnum )
920 		{
921 			messagePlayer(player, language[751]);
922 		}
923 		return false;
924 	}
925 	if ( entity->flags[BURNING] )
926 	{
927 		entity->flags[BURNING] = false;
928 		serverUpdateEntityFlag(entity, BURNING);
929 	}
930 	if ( multiplayer == CLIENT )
931 	{
932 		consumeItem(item, player);
933 		return true;
934 	}
935 
936 	if ( item->beatitude < 0 )
937 	{
938 		messagePlayer(player, language[2900]);
939 	}
940 
941 	Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
942 	messagePlayerColor(player, color, language[763]);
943 	for ( c = 0; c < NUMEFFECTS; c++ )   //This does a whole lot more than just cure ailments.
944 	{
945 		if ( !(c == EFF_VAMPIRICAURA && stats->EFFECTS_TIMERS[c] == -2)
946 			&& c != EFF_WITHDRAWAL && c != EFF_SHAPESHIFT )
947 		{
948 			stats->EFFECTS[c] = false;
949 			stats->EFFECTS_TIMERS[c] = 0;
950 		}
951 	}
952 
953 	if ( stats->EFFECTS[EFF_WITHDRAWAL] )
954 	{
955 		entity->setEffect(EFF_WITHDRAWAL, false, EFFECT_WITHDRAWAL_BASE_TIME, true);
956 		serverUpdatePlayerGameplayStats(player, STATISTICS_FUNCTIONAL, 1);
957 	}
958 
959 	if ( item->beatitude < 0 )
960 	{
961 		messagePlayer(player, language[2903]);
962 		stats->EFFECTS[EFF_POISONED] = true;
963 		stats->EFFECTS_TIMERS[EFF_POISONED] = std::max(200, 300 - entity->getCON() * 20);
964 	}
965 	else if ( item->beatitude > 0 )
966 	{
967 		stats->EFFECTS[EFF_HP_REGEN] = true;
968 		stats->EFFECTS[EFF_MP_REGEN] = true;
969 		stats->EFFECTS_TIMERS[EFF_HP_REGEN] = 4 * item->beatitude * TICKS_PER_SECOND;
970 		stats->EFFECTS_TIMERS[EFF_MP_REGEN] = 4 * item->beatitude * TICKS_PER_SECOND;
971 	}
972 
973 	serverUpdateEffects(player);
974 
975 	// play drink sound
976 	playSoundEntity(entity, 52, 64);
977 	consumeItem(item, player);
978 	return true;
979 }
980 
item_PotionBlindness(Item * & item,Entity * entity,Entity * usedBy)981 bool item_PotionBlindness(Item*& item, Entity* entity, Entity* usedBy)
982 {
983 	if (!entity)
984 	{
985 		return false;
986 	}
987 
988 	int skillLVL = 0;
989 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
990 	{
991 		Stat* usedByStats = usedBy->getStats();
992 		if ( usedByStats )
993 		{
994 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
995 		}
996 	}
997 
998 	int player = -1;
999 	Stat* stats;
1000 
1001 	if ( entity->behavior == &actPlayer )
1002 	{
1003 		player = entity->skill[2];
1004 	}
1005 	stats = entity->getStats();
1006 	if ( !stats )
1007 	{
1008 		return false;
1009 	}
1010 
1011 	if ( stats->amulet != NULL )
1012 	{
1013 		if ( stats->amulet->type == AMULET_STRANGULATION )
1014 		{
1015 			if ( player == clientnum )
1016 			{
1017 				messagePlayer(player, language[750]);
1018 			}
1019 			return false;
1020 		}
1021 	}
1022 	if ( stats->EFFECTS[EFF_VOMITING] )
1023 	{
1024 		if ( player == clientnum )
1025 		{
1026 			messagePlayer(player, language[751]);
1027 		}
1028 		return false;
1029 	}
1030 	if ( multiplayer == CLIENT )
1031 	{
1032 		consumeItem(item, player);
1033 		return true;
1034 	}
1035 
1036 	if ( entity->behavior == &actMonster && !entity->isBossMonster() )
1037 	{
1038 		entity->monsterReleaseAttackTarget();
1039 	}
1040 	messagePlayer(player, language[765]);
1041 	stats->EFFECTS[EFF_BLIND] = true;
1042 	if ( player >= 0 )
1043 	{
1044 		stats->EFFECTS_TIMERS[EFF_BLIND] = 660 + rand() % 480;
1045 		stats->EFFECTS_TIMERS[EFF_BLIND] = std::max(300, stats->EFFECTS_TIMERS[EFF_BLIND] - (entity->getPER() + entity->getCON()) * 5);
1046 	}
1047 	else
1048 	{
1049 		entity->setEffect(EFF_BLIND, true, 660 + rand() % 240, true);
1050 	}
1051 	serverUpdateEffects(player);
1052 
1053 	// play drink sound
1054 	playSoundEntity(entity, 52, 64);
1055 	consumeItem(item, player);
1056 	return true;
1057 }
1058 
item_PotionInvisibility(Item * & item,Entity * entity,Entity * usedBy)1059 bool item_PotionInvisibility(Item*& item, Entity* entity, Entity* usedBy)
1060 {
1061 	if (!entity)
1062 	{
1063 		return false;
1064 	}
1065 
1066 	int skillLVL = 0;
1067 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1068 	{
1069 		Stat* usedByStats = usedBy->getStats();
1070 		if ( usedByStats )
1071 		{
1072 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1073 		}
1074 	}
1075 
1076 	int player = -1;
1077 	Stat* stats;
1078 
1079 	if ( entity->behavior == &actPlayer )
1080 	{
1081 		player = entity->skill[2];
1082 	}
1083 	stats = entity->getStats();
1084 	if ( !stats )
1085 	{
1086 		return false;
1087 	}
1088 
1089 	if ( stats->amulet != NULL )
1090 	{
1091 		if ( stats->amulet->type == AMULET_STRANGULATION )
1092 		{
1093 			if ( player == clientnum )
1094 			{
1095 				messagePlayer(player, language[750]);
1096 			}
1097 			return false;
1098 		}
1099 	}
1100 	if ( stats->EFFECTS[EFF_VOMITING] )
1101 	{
1102 		if ( player == clientnum )
1103 		{
1104 			messagePlayer(player, language[751]);
1105 		}
1106 		return false;
1107 	}
1108 	if ( multiplayer == CLIENT )
1109 	{
1110 		consumeItem(item, player);
1111 		return true;
1112 	}
1113 
1114 	messagePlayer(player, language[766]);
1115 
1116 	if ( !entity->isInvisible() )
1117 	{
1118 		for ( node_t* node = map.creatures->first; node != nullptr; node = node->next )
1119 		{
1120 			Entity* creature = (Entity*)node->element;
1121 			if ( creature && creature->behavior == &actMonster && creature->monsterTarget == entity->getUID() )
1122 			{
1123 				if ( !creature->isBossMonster() )
1124 				{
1125 					//Abort if invalid creature (boss, shopkeep, etc).
1126 					real_t dist = entityDist(entity, creature);
1127 					if ( dist > STRIKERANGE * 3 )
1128 					{
1129 						// lose track of invis target.
1130 						creature->monsterReleaseAttackTarget();
1131 					}
1132 				}
1133 			}
1134 		}
1135 	}
1136 	stats->EFFECTS[EFF_INVISIBLE] = true;
1137 	stats->EFFECTS_TIMERS[EFF_INVISIBLE] = 1800 + rand() % 1800;
1138 	if ( item->beatitude > 0 )
1139 	{
1140 		stats->EFFECTS_TIMERS[EFF_INVISIBLE] += item->beatitude * 600;
1141 	}
1142 	serverUpdateEffects(player);
1143 
1144 	// play drink sound
1145 	playSoundEntity(entity, 52, 64);
1146 	consumeItem(item, player);
1147 	return true;
1148 }
1149 
item_PotionLevitation(Item * & item,Entity * entity,Entity * usedBy)1150 bool item_PotionLevitation(Item*& item, Entity* entity, Entity* usedBy)
1151 {
1152 	if (!entity)
1153 	{
1154 		return false;
1155 	}
1156 
1157 	int skillLVL = 0;
1158 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1159 	{
1160 		Stat* usedByStats = usedBy->getStats();
1161 		if ( usedByStats )
1162 		{
1163 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1164 		}
1165 	}
1166 
1167 	int player = -1;
1168 	Stat* stats;
1169 
1170 	if ( entity->behavior == &actPlayer )
1171 	{
1172 		player = entity->skill[2];
1173 	}
1174 	stats = entity->getStats();
1175 	if ( !stats )
1176 	{
1177 		return false;
1178 	}
1179 
1180 	if ( stats->amulet != NULL )
1181 	{
1182 		if ( stats->amulet->type == AMULET_STRANGULATION )
1183 		{
1184 			if ( player == clientnum )
1185 			{
1186 				messagePlayer(player, language[750]);
1187 			}
1188 			return false;
1189 		}
1190 	}
1191 	if ( stats->EFFECTS[EFF_VOMITING] )
1192 	{
1193 		if ( player == clientnum )
1194 		{
1195 			messagePlayer(player, language[751]);
1196 		}
1197 		return false;
1198 	}
1199 	if ( multiplayer == CLIENT )
1200 	{
1201 		consumeItem(item, player);
1202 		return true;
1203 	}
1204 
1205 	if ( item->beatitude < 0 )
1206 	{
1207 		//Cursed effect slows you.
1208 		messagePlayer(player, language[2900]);
1209 		messagePlayer(player, language[2901]);
1210 		stats->EFFECTS[EFF_SLOW] = true;
1211 		stats->EFFECTS_TIMERS[EFF_SLOW] = 1800;
1212 	}
1213 	else
1214 	{
1215 		messagePlayer(player, language[767]);
1216 		stats->EFFECTS[EFF_LEVITATING] = true;
1217 		stats->EFFECTS_TIMERS[EFF_LEVITATING] = 1800 + item->beatitude * 600;
1218 	}
1219 	serverUpdateEffects(player);
1220 
1221 	// play drink sound
1222 	playSoundEntity(entity, 52, 64);
1223 	consumeItem(item, player);
1224 	return true;
1225 }
1226 
item_PotionSpeed(Item * & item,Entity * entity,Entity * usedBy)1227 bool item_PotionSpeed(Item*& item, Entity* entity, Entity* usedBy)
1228 {
1229 	if (!entity)
1230 	{
1231 		return false;
1232 	}
1233 
1234 	int skillLVL = 0;
1235 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1236 	{
1237 		Stat* usedByStats = usedBy->getStats();
1238 		if ( usedByStats )
1239 		{
1240 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1241 		}
1242 	}
1243 
1244 	int player = -1;
1245 	Stat* stats;
1246 
1247 	if ( entity->behavior == &actPlayer )
1248 	{
1249 		player = entity->skill[2];
1250 	}
1251 	stats = entity->getStats();
1252 	if ( !stats )
1253 	{
1254 		return false;
1255 	}
1256 
1257 	if ( stats->amulet != NULL )
1258 	{
1259 		if ( stats->amulet->type == AMULET_STRANGULATION )
1260 		{
1261 			if ( player == clientnum )
1262 			{
1263 				messagePlayer(player, language[750]);
1264 			}
1265 			return false;
1266 		}
1267 	}
1268 	if ( stats->EFFECTS[EFF_VOMITING] )
1269 	{
1270 		if ( player == clientnum )
1271 		{
1272 			messagePlayer(player, language[751]);
1273 		}
1274 		return false;
1275 	}
1276 	if ( multiplayer == CLIENT )
1277 	{
1278 		consumeItem(item, player);
1279 		return true;
1280 	}
1281 
1282 
1283 	if ( item->beatitude < 0 )
1284 	{
1285 		messagePlayer(player, language[2900]);
1286 		//Cursed effect slows you.
1287 		if ( stats->EFFECTS[EFF_FAST] )
1288 		{
1289 			messagePlayer(player, language[769]);
1290 			stats->EFFECTS[EFF_FAST] = false;
1291 			stats->EFFECTS_TIMERS[EFF_FAST] = 0;
1292 		}
1293 		else
1294 		{
1295 			messagePlayer(player, language[2902]);
1296 			stats->EFFECTS[EFF_SLOW] = true;
1297 			stats->EFFECTS_TIMERS[EFF_SLOW] = 1800;
1298 		}
1299 	}
1300 	else
1301 	{
1302 		if ( !stats->EFFECTS[EFF_SLOW] )
1303 		{
1304 			messagePlayer(player, language[768]);
1305 			stats->EFFECTS[EFF_FAST] = true;
1306 			stats->EFFECTS_TIMERS[EFF_FAST] += 3000;
1307 			if ( item->beatitude > 0 )
1308 			{
1309 				stats->EFFECTS_TIMERS[EFF_FAST] += 3000 * item->beatitude;
1310 			}
1311 		}
1312 		else
1313 		{
1314 			messagePlayer(player, language[769]);
1315 			stats->EFFECTS[EFF_SLOW] = false;
1316 			stats->EFFECTS_TIMERS[EFF_SLOW] = 0;
1317 		}
1318 	}
1319 	serverUpdateEffects(player);
1320 
1321 	// play drink sound
1322 	playSoundEntity(entity, 52, 64);
1323 	consumeItem(item, player);
1324 	return true;
1325 }
1326 
item_PotionStrength(Item * & item,Entity * entity,Entity * usedBy)1327 bool item_PotionStrength(Item*& item, Entity* entity, Entity* usedBy)
1328 {
1329 	if ( !entity )
1330 	{
1331 		return false;
1332 	}
1333 
1334 	int skillLVL = 0;
1335 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1336 	{
1337 		Stat* usedByStats = usedBy->getStats();
1338 		if ( usedByStats )
1339 		{
1340 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1341 		}
1342 	}
1343 
1344 	int player = -1;
1345 	Stat* stats;
1346 
1347 	if ( entity->behavior == &actPlayer )
1348 	{
1349 		player = entity->skill[2];
1350 	}
1351 	stats = entity->getStats();
1352 	if ( !stats )
1353 	{
1354 		return false;
1355 	}
1356 
1357 	if ( stats->amulet != NULL )
1358 	{
1359 		if ( stats->amulet->type == AMULET_STRANGULATION )
1360 		{
1361 			if ( player == clientnum )
1362 			{
1363 				messagePlayer(player, language[750]);
1364 			}
1365 			return false;
1366 		}
1367 	}
1368 	if ( stats->EFFECTS[EFF_VOMITING] )
1369 	{
1370 		if ( player == clientnum )
1371 		{
1372 			messagePlayer(player, language[751]);
1373 		}
1374 		return false;
1375 	}
1376 	if ( multiplayer == CLIENT )
1377 	{
1378 		consumeItem(item, player);
1379 		return true;
1380 	}
1381 
1382 
1383 	if ( item->beatitude < 0 )
1384 	{
1385 		messagePlayer(player, language[2900]);
1386 		//Cursed effect blinds you.
1387 		messagePlayer(player, language[765]);
1388 		stats->EFFECTS[EFF_BLIND] = true;
1389 		if ( player >= 0 )
1390 		{
1391 			stats->EFFECTS_TIMERS[EFF_BLIND] = 660 + rand() % 480;
1392 			stats->EFFECTS_TIMERS[EFF_BLIND] = std::max(300, stats->EFFECTS_TIMERS[EFF_BLIND] - (entity->getPER() + entity->getCON()) * 5);
1393 		}
1394 		else
1395 		{
1396 			entity->setEffect(EFF_BLIND, true, 660 + rand() % 240, true);
1397 		}
1398 	}
1399 	else
1400 	{
1401 		messagePlayer(player, language[3354]);
1402 		stats->EFFECTS[EFF_POTION_STR] = true;
1403 		stats->EFFECTS_TIMERS[EFF_POTION_STR] = 3000; // 60 seconds
1404 		if ( item->beatitude > 0 )
1405 		{
1406 			stats->EFFECTS_TIMERS[EFF_POTION_STR] += 3000 * item->beatitude; // 60 seconds each blessing
1407 		}
1408 	}
1409 	serverUpdateEffects(player);
1410 
1411 	// play drink sound
1412 	playSoundEntity(entity, 52, 64);
1413 	consumeItem(item, player);
1414 	return true;
1415 }
1416 
item_PotionAcid(Item * & item,Entity * entity,Entity * usedBy)1417 bool item_PotionAcid(Item*& item, Entity* entity, Entity* usedBy)
1418 {
1419 	if (!entity)
1420 	{
1421 		return false;
1422 	}
1423 
1424 	int skillLVL = 0;
1425 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1426 	{
1427 		Stat* usedByStats = usedBy->getStats();
1428 		if ( usedByStats )
1429 		{
1430 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1431 		}
1432 	}
1433 
1434 	int player = -1;
1435 	Stat* stats;
1436 
1437 	if ( entity->behavior == &actPlayer )
1438 	{
1439 		player = entity->skill[2];
1440 	}
1441 	stats = entity->getStats();
1442 	if ( !stats )
1443 	{
1444 		return false;
1445 	}
1446 
1447 	auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
1448 	auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
1449 
1450 	if ( entity == NULL )
1451 	{
1452 		return false;
1453 	}
1454 	if ( stats->amulet != NULL )
1455 	{
1456 		if ( stats->amulet->type == AMULET_STRANGULATION )
1457 		{
1458 			if ( player == clientnum )
1459 			{
1460 				messagePlayer(player, language[750]);
1461 			}
1462 			return false;
1463 		}
1464 	}
1465 	if ( stats->EFFECTS[EFF_VOMITING] )
1466 	{
1467 		if ( player == clientnum )
1468 		{
1469 			messagePlayer(player, language[751]);
1470 		}
1471 		return false;
1472 	}
1473 	if ( multiplayer == CLIENT || player == 0 )
1474 	{
1475 		camera_shakex += .1;
1476 		camera_shakey += 10;
1477 		if ( multiplayer == CLIENT )
1478 		{
1479 			consumeItem(item, player);
1480 			return true;
1481 		}
1482 	}
1483 
1484 	int damage = (10 + 5 * abs(item->beatitude)) * potionDamageSkillMultipliers[std::min(skillLVL, 5)];
1485 	int chance = damage / 8;
1486 	if ( player >= 0 && usedBy == entity )
1487 	{
1488 		damage /= 2;
1489 	}
1490 	else
1491 	{
1492 		damage -= (rand() % (1 + chance));
1493 	}
1494 	messagePlayer(player, language[770]);
1495 	entity->modHP(-damage);
1496 	playSoundEntity(entity, 28, 64);
1497 
1498 	// set obituary
1499 	entity->setObituary(language[1535]);
1500 
1501 	// play drink sound
1502 	playSoundEntity(entity, 52, 64);
1503 	consumeItem(item, player);
1504 	return true;
1505 }
1506 
item_PotionUnstableStorm(Item * & item,Entity * entity,Entity * usedBy,Entity * thrownPotion)1507 bool item_PotionUnstableStorm(Item*& item, Entity* entity, Entity* usedBy, Entity* thrownPotion)
1508 {
1509 	if ( !entity )
1510 	{
1511 		return false;
1512 	}
1513 
1514 	int skillLVL = 0;
1515 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1516 	{
1517 		Stat* usedByStats = usedBy->getStats();
1518 		if ( usedByStats )
1519 		{
1520 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1521 		}
1522 	}
1523 
1524 	int player = -1;
1525 	Stat* stats;
1526 
1527 	if ( entity->behavior == &actPlayer )
1528 	{
1529 		player = entity->skill[2];
1530 	}
1531 	stats = entity->getStats();
1532 	if ( !stats )
1533 	{
1534 		return false;
1535 	}
1536 
1537 	auto& camera_shakex = cameravars[player >= 0 ? player : 0].shakex;
1538 	auto& camera_shakey = cameravars[player >= 0 ? player : 0].shakey;
1539 
1540 	if ( entity == NULL )
1541 	{
1542 		return false;
1543 	}
1544 	if ( stats->amulet != NULL )
1545 	{
1546 		if ( stats->amulet->type == AMULET_STRANGULATION )
1547 		{
1548 			if ( player == clientnum )
1549 			{
1550 				messagePlayer(player, language[750]);
1551 			}
1552 			return false;
1553 		}
1554 	}
1555 	if ( stats->EFFECTS[EFF_VOMITING] )
1556 	{
1557 		if ( player == clientnum )
1558 		{
1559 			messagePlayer(player, language[751]);
1560 		}
1561 		return false;
1562 	}
1563 	if ( multiplayer == CLIENT || player == 0 )
1564 	{
1565 		if ( player == clientnum )
1566 		{
1567 			camera_shakex += .1;
1568 			camera_shakey += 10;
1569 		}
1570 		if ( multiplayer == CLIENT )
1571 		{
1572 			consumeItem(item, player);
1573 			return true;
1574 		}
1575 	}
1576 
1577 	bool playerAutomatonDrink = false;
1578 	if ( item->type == POTION_FIRESTORM && !thrownPotion && usedBy && usedBy == entity
1579 		&& usedBy->behavior == &actPlayer && stats->type == AUTOMATON )
1580 	{
1581 		playerAutomatonDrink = true;
1582 	}
1583 
1584 	int damage = (10 + 5 * abs(item->beatitude)) * potionDamageSkillMultipliers[std::min(skillLVL, 5)];
1585 	int chance = damage / 8;
1586 	if ( player >= 0 && usedBy == entity )
1587 	{
1588 		damage /= 2;
1589 	}
1590 	else
1591 	{
1592 		damage -= (rand() % (1 + chance));
1593 	}
1594 	if ( playerAutomatonDrink )
1595 	{
1596 		damage = 0;
1597 	}
1598 	else
1599 	{
1600 		messagePlayer(player, language[770]);
1601 		entity->modHP(-damage);
1602 		playSoundEntity(entity, 28, 64);
1603 	}
1604 
1605 	// set obituary
1606 	entity->setObituary(language[1535]);
1607 
1608 	real_t x = entity->x;
1609 	real_t y = entity->y;
1610 	if ( thrownPotion )
1611 	{
1612 		// rather spawn at the potion impact rather than on the hit entity's coords.
1613 		x = thrownPotion->x;
1614 		y = thrownPotion->y;
1615 	}
1616 	if ( item->type == POTION_FIRESTORM )
1617 	{
1618 		if ( playerAutomatonDrink )
1619 		{
1620 			spawnMagicTower(usedBy, x, y, SPELL_FIREBALL, nullptr);
1621 			stats->HUNGER = std::min(stats->HUNGER + 1500, 1500);
1622 			players[player]->entity->modMP(stats->MAXMP);
1623 			Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
1624 			messagePlayerColor(player, color, language[3699]); // superheats
1625 			serverUpdateHunger(player);
1626 			for ( int c = 0; c < 100; c++ )
1627 			{
1628 				Entity* entity = spawnFlame(players[player]->entity, SPRITE_FLAME);
1629 				entity->sprite = 16;
1630 				double vel = rand() % 10;
1631 				entity->vel_x = vel * cos(entity->yaw) * cos(entity->pitch) * .1;
1632 				entity->vel_y = vel * sin(entity->yaw) * cos(entity->pitch) * .1;
1633 				entity->vel_z = vel * sin(entity->pitch) * .2;
1634 				entity->skill[0] = 5 + rand() % 10;
1635 			}
1636 		}
1637 		else
1638 		{
1639 			spawnMagicTower(usedBy, x, y, SPELL_FIREBALL, entity);
1640 		}
1641 	}
1642 	else if ( item->type == POTION_ICESTORM )
1643 	{
1644 		spawnMagicTower(usedBy, x, y, SPELL_COLD, entity);
1645 	}
1646 	else if ( item->type == POTION_THUNDERSTORM )
1647 	{
1648 		spawnMagicTower(usedBy, x, y, SPELL_LIGHTNING, entity);
1649 	}
1650 
1651 	// play drink sound
1652 	playSoundEntity(entity, 52, 64);
1653 	consumeItem(item, player);
1654 	return true;
1655 }
1656 
item_PotionParalysis(Item * & item,Entity * entity,Entity * usedBy)1657 bool item_PotionParalysis(Item*& item, Entity* entity, Entity* usedBy)
1658 {
1659 	if (!entity)
1660 	{
1661 		return false;
1662 	}
1663 
1664 	int skillLVL = 0;
1665 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1666 	{
1667 		Stat* usedByStats = usedBy->getStats();
1668 		if ( usedByStats )
1669 		{
1670 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1671 		}
1672 	}
1673 
1674 	int player = -1;
1675 	Stat* stats;
1676 
1677 	if ( entity->behavior == &actPlayer )
1678 	{
1679 		player = entity->skill[2];
1680 	}
1681 	stats = entity->getStats();
1682 	if ( !stats )
1683 	{
1684 		return false;
1685 	}
1686 
1687 	if ( stats->amulet != NULL )
1688 	{
1689 		if ( stats->amulet->type == AMULET_STRANGULATION )
1690 		{
1691 			if ( player == clientnum )
1692 			{
1693 				messagePlayer(player, language[750]);
1694 			}
1695 			return false;
1696 		}
1697 	}
1698 	if ( stats->EFFECTS[EFF_VOMITING] )
1699 	{
1700 		if ( player == clientnum )
1701 		{
1702 			messagePlayer(player, language[751]);
1703 		}
1704 		return false;
1705 	}
1706 	if ( multiplayer == CLIENT )
1707 	{
1708 		consumeItem(item, player);
1709 		return true;
1710 	}
1711 
1712 	messagePlayer(player, language[771]);
1713 	int effectDuration = 0;
1714 	if ( player >= 0 )
1715 	{
1716 		effectDuration = 420 + rand() % 180;
1717 		effectDuration = std::max(300, effectDuration - (entity->getCON()) * 5);
1718 	}
1719 	else
1720 	{
1721 		effectDuration = 420 + rand() % 180;
1722 	}
1723 	if ( item->beatitude != 0 )
1724 	{
1725 		effectDuration += (abs(item->beatitude) * 100);
1726 	}
1727 
1728 	entity->setEffect(EFF_PARALYZED, true, effectDuration, false);
1729 	serverUpdateEffects(player);
1730 
1731 	// play drink sound
1732 	playSoundEntity(entity, 52, 64);
1733 	consumeItem(item, player);
1734 	return true;
1735 }
1736 
item_PotionHealing(Item * & item,Entity * entity,Entity * usedBy,bool shouldConsumeItem)1737 bool item_PotionHealing(Item*& item, Entity* entity, Entity* usedBy, bool shouldConsumeItem)
1738 {
1739 	if (!entity)
1740 	{
1741 		return false;
1742 	}
1743 
1744 	int skillLVL = 0;
1745 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1746 	{
1747 		Stat* usedByStats = usedBy->getStats();
1748 		if ( usedByStats )
1749 		{
1750 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1751 		}
1752 	}
1753 
1754 	int player = -1;
1755 	Stat* stats;
1756 
1757 	if ( entity->behavior == &actPlayer )
1758 	{
1759 		player = entity->skill[2];
1760 	}
1761 	stats = entity->getStats();
1762 	if ( !stats )
1763 	{
1764 		return false;
1765 	}
1766 
1767 	if ( stats->amulet != nullptr )
1768 	{
1769 		if ( stats->amulet->type == AMULET_STRANGULATION )
1770 		{
1771 			if ( player == clientnum )
1772 			{
1773 				messagePlayer(player, language[750]);
1774 			}
1775 			return false;
1776 		}
1777 	}
1778 	if ( stats->EFFECTS[EFF_VOMITING] )
1779 	{
1780 		if ( player == clientnum )
1781 		{
1782 			messagePlayer(player, language[751]);
1783 		}
1784 		return false;
1785 	}
1786 	if ( multiplayer == CLIENT )
1787 	{
1788 		consumeItem(item, player);
1789 		return true;
1790 	}
1791 	if ( stats->HP == stats->MAXHP )
1792 	{
1793 		playSoundEntity(entity, 52, 64);
1794 		playSoundEntity(entity, 168, 128);
1795 		spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
1796 		if ( item->beatitude < 0 )
1797 		{
1798 			messagePlayer(player, language[2900]);
1799 			messagePlayer(player, language[2903]);
1800 			stats->EFFECTS[EFF_POISONED] = true;
1801 		}
1802 		else
1803 		{
1804 			messagePlayer(player, language[772]);
1805 			// stop bleeding
1806 			if ( stats->EFFECTS[EFF_BLEEDING] )
1807 			{
1808 				entity->setEffect(EFF_BLEEDING, false, 0, false);
1809 			}
1810 		}
1811 		if ( shouldConsumeItem )
1812 		{
1813 			consumeItem(item, player);
1814 			return true;
1815 		}
1816 		return false;
1817 	}
1818 
1819 	int amount = std::max(7 + item->status, 0);
1820 	int multiplier = std::max(5, item->beatitude + 5);
1821 
1822 	amount *= multiplier / 5.f;
1823 	if ( stats->type == GOATMAN && entity->behavior == &actMonster )
1824 	{
1825 		amount *= GOATMAN_HEALINGPOTION_MOD; //Goatman special.
1826 		stats->EFFECTS[EFF_FAST] = true;
1827 		stats->EFFECTS_TIMERS[EFF_FAST] = GOATMAN_HEALING_POTION_SPEED_BOOST_DURATION;
1828 	}
1829 
1830 	//Bonus from CON, to scale up healing potions as the game progresses.
1831 	if ( stats->CON > 0 )
1832 	{
1833 		amount += 2 * stats->CON;
1834 	}
1835 
1836 	if ( item->beatitude < 0 )
1837 	{
1838 		amount /= (std::abs(item->beatitude) * 2);
1839 	}
1840 
1841 	int oldHP = entity->getHP();
1842 
1843 	entity->modHP(amount);
1844 
1845 	int heal = std::max(entity->getHP() - oldHP, 0);
1846 	if ( heal > 0 )
1847 	{
1848 		serverUpdatePlayerGameplayStats(player, STATISTICS_HEAL_BOT, heal);
1849 	}
1850 
1851 	// play drink sound
1852 	playSoundEntity(entity, 52, 64);
1853 	playSoundEntity(entity, 168, 128);
1854 	spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
1855 	Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
1856 
1857 	if ( item->beatitude < 0 )
1858 	{
1859 		messagePlayer(player, language[2900]);
1860 		messagePlayer(player, language[2903]);
1861 		stats->EFFECTS[EFF_POISONED] = true;
1862 		stats->EFFECTS_TIMERS[EFF_POISONED] = std::max(200, 300 - entity->getCON() * 20);
1863 	}
1864 	else
1865 	{
1866 		messagePlayerColor(player, color, language[773]);
1867 		// stop bleeding
1868 		if ( stats->EFFECTS[EFF_BLEEDING] )
1869 		{
1870 			entity->setEffect(EFF_BLEEDING, false, 0, false);
1871 		}
1872 	}
1873 
1874 	if ( shouldConsumeItem )
1875 	{
1876 		consumeItem(item, player);
1877 		return true;
1878 	}
1879 	return false;
1880 }
1881 
item_PotionExtraHealing(Item * & item,Entity * entity,Entity * usedBy,bool shouldConsumeItem)1882 bool item_PotionExtraHealing(Item*& item, Entity* entity, Entity* usedBy, bool shouldConsumeItem)
1883 {
1884 	if (!entity)
1885 	{
1886 		return false;
1887 	}
1888 
1889 	int skillLVL = 0;
1890 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
1891 	{
1892 		Stat* usedByStats = usedBy->getStats();
1893 		if ( usedByStats )
1894 		{
1895 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
1896 		}
1897 	}
1898 
1899 	int player = -1;
1900 	Stat* stats;
1901 
1902 	if ( entity->behavior == &actPlayer )
1903 	{
1904 		player = entity->skill[2];
1905 	}
1906 	stats = entity->getStats();
1907 	if ( !stats )
1908 	{
1909 		return false;
1910 	}
1911 
1912 	if ( stats->amulet != nullptr )
1913 	{
1914 		if ( stats->amulet->type == AMULET_STRANGULATION )
1915 		{
1916 			if ( player == clientnum )
1917 			{
1918 				messagePlayer(player, language[750]);
1919 			}
1920 			return false;
1921 		}
1922 	}
1923 	if ( stats->EFFECTS[EFF_VOMITING] )
1924 	{
1925 		if ( player == clientnum )
1926 		{
1927 			messagePlayer(player, language[751]);
1928 		}
1929 		return false;
1930 	}
1931 	if ( multiplayer == CLIENT )
1932 	{
1933 		consumeItem(item, player);
1934 		return true;
1935 	}
1936 	if ( stats->HP == stats->MAXHP )
1937 	{
1938 		playSoundEntity(entity, 52, 64);
1939 		playSoundEntity(entity, 168, 128);
1940 		spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
1941 		if ( item->beatitude < 0 )
1942 		{
1943 			messagePlayer(player, language[2900]);
1944 			messagePlayer(player, language[2903]);
1945 			stats->EFFECTS[EFF_POISONED] = true;
1946 		}
1947 		else
1948 		{
1949 			messagePlayer(player, language[772]);
1950 			// stop bleeding
1951 			if ( stats->EFFECTS[EFF_BLEEDING] )
1952 			{
1953 				entity->setEffect(EFF_BLEEDING, false, 0, false);
1954 			}
1955 		}
1956 		if ( shouldConsumeItem )
1957 		{
1958 			consumeItem(item, player);
1959 			return true;
1960 		}
1961 		return false;
1962 	}
1963 
1964 	int amount = std::max(15 + item->status, 0);
1965 	int multiplier = std::max(5, item->beatitude + 5);
1966 
1967 	amount *= multiplier;
1968 	if ( stats->type == GOATMAN && entity->behavior == &actMonster )
1969 	{
1970 		amount *= GOATMAN_HEALINGPOTION_MOD; //Goatman special.
1971 		stats->EFFECTS[EFF_FAST] = true;
1972 		stats->EFFECTS_TIMERS[EFF_FAST] = GOATMAN_HEALING_POTION_SPEED_BOOST_DURATION;
1973 	}
1974 
1975 	//Bonus from CON, to scale up healing potions as the game progresses.
1976 	if ( stats->CON > 0 )
1977 	{
1978 		amount += 4 * stats->CON;
1979 	}
1980 
1981 	if ( item->beatitude < 0 )
1982 	{
1983 		amount /= (std::abs(item->beatitude) * 2);
1984 	}
1985 
1986 	int oldHP = entity->getHP();
1987 
1988 	entity->modHP(amount);
1989 
1990 	int heal = std::max(entity->getHP() - oldHP, 0);
1991 	if ( heal > 0 )
1992 	{
1993 		serverUpdatePlayerGameplayStats(player, STATISTICS_HEAL_BOT, heal);
1994 	}
1995 
1996 	// play drink sound
1997 	playSoundEntity(entity, 52, 64);
1998 	playSoundEntity(entity, 168, 128);
1999 	spawnMagicEffectParticles(entity->x, entity->y, entity->z, 169);
2000 	Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
2001 	if ( item->beatitude < 0 )
2002 	{
2003 		messagePlayer(player, language[2900]);
2004 		messagePlayer(player, language[2903]);
2005 		stats->EFFECTS[EFF_POISONED] = true;
2006 		stats->EFFECTS_TIMERS[EFF_POISONED] = std::max(300, 600 - entity->getCON() * 20);
2007 	}
2008 	else
2009 	{
2010 		messagePlayerColor(player, color, language[773]);
2011 		// stop bleeding
2012 		if ( stats->EFFECTS[EFF_BLEEDING] )
2013 		{
2014 			entity->setEffect(EFF_BLEEDING, false, 0, false);
2015 		}
2016 	}
2017 
2018 	if ( shouldConsumeItem )
2019 	{
2020 		consumeItem(item, player);
2021 		return true;
2022 	}
2023 	return false;
2024 }
2025 
item_PotionRestoreMagic(Item * & item,Entity * entity,Entity * usedBy)2026 bool item_PotionRestoreMagic(Item*& item, Entity* entity, Entity* usedBy)
2027 {
2028 	if (!entity)
2029 	{
2030 		return false;
2031 	}
2032 
2033 	int skillLVL = 0;
2034 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
2035 	{
2036 		Stat* usedByStats = usedBy->getStats();
2037 		if ( usedByStats )
2038 		{
2039 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
2040 		}
2041 	}
2042 
2043 	int player = -1;
2044 	Stat* stats;
2045 
2046 	if ( entity->behavior == &actPlayer )
2047 	{
2048 		player = entity->skill[2];
2049 	}
2050 	stats = entity->getStats();
2051 	if ( !stats )
2052 	{
2053 		return false;
2054 	}
2055 
2056 	if ( entity == NULL )
2057 	{
2058 		return false;
2059 	}
2060 	if ( stats->amulet != NULL )
2061 	{
2062 		if ( stats->amulet->type == AMULET_STRANGULATION )
2063 		{
2064 			if ( player == clientnum )
2065 			{
2066 				messagePlayer(player, language[750]);
2067 			}
2068 			return false;
2069 		}
2070 	}
2071 	if ( stats->EFFECTS[EFF_VOMITING] )
2072 	{
2073 		if ( player == clientnum )
2074 		{
2075 			messagePlayer(player, language[751]);
2076 		}
2077 		return false;
2078 	}
2079 	if ( multiplayer == CLIENT )
2080 	{
2081 		consumeItem(item, player);
2082 		return true;
2083 	}
2084 	if ( stats->MP == stats->MAXMP )
2085 	{
2086 		playSoundEntity(entity, 52, 64);
2087 		if ( item->beatitude < 0 )
2088 		{
2089 			messagePlayer(player, language[774]);
2090 			messagePlayer(player, language[2902]);
2091 			stats->EFFECTS[EFF_SLOW] = true;
2092 			stats->EFFECTS_TIMERS[EFF_SLOW] = 600;
2093 		}
2094 		else
2095 		{
2096 			messagePlayer(player, language[772]);
2097 		}
2098 		consumeItem(item, player);
2099 		return true;
2100 	}
2101 
2102 	int amount = std::max(7 + item->status, 0);
2103 	int multiplier = std::max(5, item->beatitude + 5);
2104 
2105 	amount *= multiplier;
2106 
2107 	if ( stats->INT > 0 )
2108 	{
2109 		amount += std::min(30, 2 * stats->INT); // extra mana scaling from 1 to 15 INT, capped at +30 MP
2110 	}
2111 
2112 	if ( item->beatitude < 0 )
2113 	{
2114 		amount /= (std::abs(item->beatitude) * 2);
2115 		messagePlayer(player, language[774]);
2116 		messagePlayer(player, language[2902]);
2117 		stats->EFFECTS[EFF_SLOW] = true;
2118 		stats->EFFECTS_TIMERS[EFF_SLOW] = 600;
2119 	}
2120 	else
2121 	{
2122 		messagePlayer(player, language[774]);
2123 	}
2124 	entity->modMP(amount);
2125 
2126 	if ( svFlags & SV_FLAG_HUNGER )
2127 	{
2128 		if ( player >= 0 && stats->playerRace == RACE_INSECTOID && stats->appearance == 0 )
2129 		{
2130 			Sint32 hungerPointPerMana = entity->playerInsectoidHungerValueOfManaPoint(*stats);
2131 			Sint32 oldHunger = stats->HUNGER;
2132 			stats->HUNGER += amount * hungerPointPerMana;
2133 			stats->HUNGER = std::min(999, stats->HUNGER);
2134 			updateHungerMessages(entity, stats, item);
2135 			if ( player > 0 )
2136 			{
2137 				serverUpdateHunger(player);
2138 			}
2139 		}
2140 	}
2141 
2142 	// play drink sound
2143 	playSoundEntity(entity, 52, 64);
2144 
2145 	consumeItem(item, player);
2146 	return true;
2147 }
2148 
item_PotionPolymorph(Item * & item,Entity * entity,Entity * usedBy)2149 Entity* item_PotionPolymorph(Item*& item, Entity* entity, Entity* usedBy)
2150 {
2151 	if ( !entity )
2152 	{
2153 		return nullptr;
2154 	}
2155 
2156 	int skillLVL = 0;
2157 	if ( multiplayer != CLIENT && usedBy && usedBy->behavior == &actPlayer )
2158 	{
2159 		Stat* usedByStats = usedBy->getStats();
2160 		if ( usedByStats )
2161 		{
2162 			skillLVL = usedByStats->PROFICIENCIES[PRO_ALCHEMY] / 20;
2163 		}
2164 	}
2165 
2166 	int player = -1;
2167 	Stat* stats;
2168 
2169 	if ( entity->behavior == &actPlayer )
2170 	{
2171 		player = entity->skill[2];
2172 	}
2173 	stats = entity->getStats();
2174 	if ( !stats )
2175 	{
2176 		return nullptr;
2177 	}
2178 
2179 	if ( stats->amulet != NULL )
2180 	{
2181 		if ( stats->amulet->type == AMULET_STRANGULATION )
2182 		{
2183 			if ( player == clientnum )
2184 			{
2185 				messagePlayer(player, language[750]);
2186 			}
2187 			return nullptr;
2188 		}
2189 	}
2190 	if ( stats->EFFECTS[EFF_VOMITING] )
2191 	{
2192 		if ( player == clientnum )
2193 		{
2194 			messagePlayer(player, language[751]);
2195 		}
2196 		return nullptr;
2197 	}
2198 	if ( multiplayer == CLIENT )
2199 	{
2200 		consumeItem(item, player);
2201 		return nullptr;
2202 	}
2203 
2204 	// play drink sound
2205 	if ( !usedBy ) // drinking rather than throwing.
2206 	{
2207 		playSoundEntity(entity, 52, 64);
2208 		if ( player >= 0 )
2209 		{
2210 			messagePlayer(player, language[3190]);
2211 		}
2212 	}
2213 	Entity* transformedEntity = nullptr;
2214 
2215 	if ( entity->behavior == &actMonster || entity->behavior == &actPlayer )
2216 	{
2217 		transformedEntity = spellEffectPolymorph(entity, stats, usedBy, false);
2218 	}
2219 
2220 	consumeItem(item, player);
2221 
2222 	return transformedEntity;
2223 }
2224 
item_ScrollMail(Item * item,int player)2225 void item_ScrollMail(Item* item, int player)
2226 {
2227 	if (players[player] == nullptr || players[player]->entity == nullptr)
2228 	{
2229 		return;
2230 	}
2231 
2232 	if ( player != clientnum )
2233 	{
2234 		return;
2235 	}
2236 
2237 	if (players[player]->entity->isBlind())
2238 	{
2239 		messagePlayer(player, language[775]);
2240 		return;
2241 	}
2242 
2243 	if ( player == clientnum )
2244 	{
2245 		conductIlliterate = false;
2246 	}
2247 	item->identified = 1;
2248 	switch ( item->appearance % 25 )
2249 	{
2250 		case 0:
2251 			messagePlayer(player, language[776]);
2252 			break;
2253 		case 1:
2254 			messagePlayer(player, language[780]);
2255 			messagePlayer(player, language[781]);
2256 			break;
2257 		case 2:
2258 			messagePlayer(player, language[786]);
2259 			break;
2260 		case 3:
2261 			messagePlayer(player, language[790]);
2262 			break;
2263 		case 4:
2264 			messagePlayer(player, language[793], language[158 + item->appearance % 26], language[184 + item->appearance % 9]);
2265 			break;
2266 		case 5:
2267 			messagePlayer(player, language[796]);
2268 			break;
2269 		case 6:
2270 			messagePlayer(player, language[799]);
2271 			break;
2272 		case 7:
2273 			messagePlayer(player, language[801]);
2274 			messagePlayer(player, language[802]);
2275 			break;
2276 		case 8:
2277 			messagePlayer(player, language[807]);
2278 			break;
2279 		case 9:
2280 			messagePlayer(player, language[811]);
2281 			messagePlayer(player, language[812]);
2282 			break;
2283 		case 10:
2284 			messagePlayer(player, language[816]);
2285 			break;
2286 		case 11:
2287 			messagePlayer(player, language[817]);
2288 			break;
2289 		case 12:
2290 			messagePlayer(player, language[822]);
2291 			break;
2292 		case 13:
2293 			messagePlayer(player, language[824]);
2294 			break;
2295 		case 14:
2296 			messagePlayer(player, language[826]);
2297 			break;
2298 		case 15:
2299 			messagePlayer(player, language[828]);
2300 			break;
2301 		case 16:
2302 			messagePlayer(player, language[830]);
2303 			break;
2304 		case 17:
2305 			messagePlayer(player, language[834]);
2306 			break;
2307 		case 18:
2308 			messagePlayer(player, language[836]);
2309 			break;
2310 		case 19:
2311 			messagePlayer(player, language[838]);
2312 			break;
2313 		case 20:
2314 			messagePlayer(player, language[840]);
2315 			break;
2316 		case 21:
2317 			messagePlayer(player, language[843]);
2318 			break;
2319 		default:
2320 			messagePlayer(player, language[846]);
2321 			break;
2322 	}
2323 }
2324 
item_ScrollIdentify(Item * item,int player)2325 void item_ScrollIdentify(Item* item, int player)
2326 {
2327 	if (players[player] == nullptr || players[player]->entity == nullptr)
2328 	{
2329 		return;
2330 	}
2331 
2332 	if (player != clientnum)
2333 	{
2334 		return;
2335 	}
2336 
2337 	if (players[player]->entity->isBlind())
2338 	{
2339 		messagePlayer(player, language[775]);
2340 		return;
2341 	}
2342 
2343 	//identifygui_mode = true;
2344 	identifygui_active = true;
2345 	identifygui_appraising = false;
2346 	shootmode = false;
2347 	openStatusScreen(GUI_MODE_INVENTORY, INVENTORY_MODE_ITEM); // Reset the GUI to the inventory.
2348 
2349 	if ( removecursegui_active )
2350 	{
2351 		closeRemoveCurseGUI();
2352 	}
2353 
2354 	GenericGUI.closeGUI();
2355 
2356 	if ( openedChest[clientnum] )
2357 	{
2358 		openedChest[clientnum]->closeChest();
2359 	}
2360 
2361 	//Initialize Identify GUI game controller code here.
2362 	initIdentifyGUIControllerCode();
2363 }
2364 
item_ScrollLight(Item * item,int player)2365 void item_ScrollLight(Item* item, int player)
2366 {
2367 	int c;
2368 
2369 	if (players[player] == nullptr || players[player]->entity == nullptr)
2370 	{
2371 		return;
2372 	}
2373 
2374 	if (multiplayer == CLIENT)
2375 	{
2376 		return;
2377 	}
2378 
2379 	if (players[player]->entity->isBlind())
2380 	{
2381 		messagePlayer(player, language[775]);
2382 		return;
2383 	}
2384 
2385 	if ( player == clientnum )
2386 	{
2387 		conductIlliterate = false;
2388 	}
2389 	item->identified = 1;
2390 	messagePlayer(player, language[848]);
2391 
2392 	messagePlayer(player, language[851]);
2393 	lightSphereShadow(players[player]->entity->x / 16, players[player]->entity->y / 16, 8, 150);
2394 
2395 	// send new light info to clients
2396 	if (multiplayer == SERVER)
2397 	{
2398 		for (c = 1; c < MAXPLAYERS; c++)
2399 		{
2400 			if (client_disconnected[c] == true)
2401 			{
2402 				continue;
2403 			}
2404 			strcpy((char*)net_packet->data, "LITS");
2405 			SDLNet_Write16(players[player]->entity->x / 16, &net_packet->data[4]);
2406 			SDLNet_Write16(players[player]->entity->y / 16, &net_packet->data[6]);
2407 			SDLNet_Write16(8, &net_packet->data[8]);
2408 			SDLNet_Write16(150, &net_packet->data[10]);
2409 			net_packet->address.host = net_clients[c - 1].host;
2410 			net_packet->address.port = net_clients[c - 1].port;
2411 			net_packet->len = 12;
2412 			sendPacketSafe(net_sock, -1, net_packet, c - 1);
2413 		}
2414 	}
2415 }
2416 
item_ScrollBlank(Item * item,int player)2417 void item_ScrollBlank(Item* item, int player)
2418 {
2419 	if (players[player] == nullptr || players[player]->entity == nullptr)
2420 	{
2421 		return;
2422 	}
2423 
2424 	if (player != clientnum)
2425 	{
2426 		return;
2427 	}
2428 
2429 	if (players[player]->entity->isBlind())
2430 	{
2431 		messagePlayer(player, language[775]);
2432 		return;
2433 	}
2434 
2435 	if (player == clientnum)
2436 	{
2437 		conductIlliterate = false;
2438 	}
2439 	item->identified = 1;
2440 	messagePlayer(player, language[852]);
2441 }
2442 
item_ScrollEnchantWeapon(Item * item,int player)2443 void item_ScrollEnchantWeapon(Item* item, int player)
2444 {
2445 	if (players[player] == nullptr || players[player]->entity == nullptr)
2446 	{
2447 		return;
2448 	}
2449 
2450 	if ( player != clientnum )
2451 	{
2452 		consumeItem(item, player);
2453 		return;
2454 	}
2455 
2456 	if (players[player]->entity->isBlind())
2457 	{
2458 		messagePlayer(player, language[775]);
2459 		return;
2460 	}
2461 
2462 	conductIlliterate = false;
2463 
2464 	item->identified = 1;
2465 
2466 	messagePlayer(player, language[848]);
2467 
2468 	Item** toEnchant = nullptr;
2469 	bool hasMeleeGloves = false;
2470 	if ( stats[player]->gloves )
2471 	{
2472 		switch ( stats[player]->gloves->type )
2473 		{
2474 			case BRASS_KNUCKLES:
2475 			case IRON_KNUCKLES:
2476 			case SPIKED_GAUNTLETS:
2477 				hasMeleeGloves = true;
2478 				break;
2479 			default:
2480 				break;
2481 		}
2482 	}
2483 
2484 	if ( stats[player]->weapon )
2485 	{
2486 		toEnchant = &stats[player]->weapon;
2487 	}
2488 	else if ( hasMeleeGloves )
2489 	{
2490 		toEnchant = &stats[player]->gloves;
2491 	}
2492 
2493 	if ( toEnchant == nullptr)
2494 	{
2495 		messagePlayer(player, language[853]);
2496 	}
2497 	else
2498 	{
2499 		if (item->beatitude < 0)
2500 		{
2501 			if ( toEnchant == &stats[player]->gloves )
2502 			{
2503 				messagePlayer(player, language[858], (*toEnchant)->getName());
2504 			}
2505 			else
2506 			{
2507 				messagePlayer(player, language[854]);
2508 			}
2509 
2510 			if ( (*toEnchant)->beatitude > 0 )
2511 			{
2512 				(*toEnchant)->beatitude = -(*toEnchant)->beatitude;
2513 				if ( stats[clientnum]->type == SUCCUBUS )
2514 				{
2515 					steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
2516 				}
2517 			}
2518 			else
2519 			{
2520 				(*toEnchant)->beatitude -= 1;
2521 			}
2522 		}
2523 		else
2524 		{
2525 			if (item->beatitude == 0)
2526 			{
2527 				if ( toEnchant == &stats[player]->gloves )
2528 				{
2529 					messagePlayer(player, language[859], (*toEnchant)->getName());
2530 				}
2531 				else
2532 				{
2533 					messagePlayer(player, language[855]);
2534 				}
2535 			}
2536 			else
2537 			{
2538 				if ( toEnchant == &stats[player]->gloves )
2539 				{
2540 					messagePlayer(player, language[860], (*toEnchant)->getName());
2541 				}
2542 				else
2543 				{
2544 					messagePlayer(player, language[856]);
2545 				}
2546 			}
2547 			(*toEnchant)->beatitude += 1 + item->beatitude;
2548 		}
2549 
2550 		if ( multiplayer == CLIENT )
2551 		{
2552 			strcpy((char*)net_packet->data, "BEAT");
2553 			net_packet->data[4] = clientnum;
2554 			net_packet->data[5] = 0; // weapon index
2555 			net_packet->data[6] = (*toEnchant)->beatitude + 100;
2556 			net_packet->address.host = net_server.host;
2557 			net_packet->address.port = net_server.port;
2558 			net_packet->len = 7;
2559 			sendPacketSafe(net_sock, -1, net_packet, 0);
2560 			//messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
2561 		}
2562 	}
2563 	consumeItem(item, player);
2564 }
2565 
item_ScrollEnchantArmor(Item * item,int player)2566 void item_ScrollEnchantArmor(Item* item, int player)
2567 {
2568 	Item* armor = nullptr;
2569 	if (players[player] == nullptr || players[player]->entity == nullptr)
2570 	{
2571 		return;
2572 	}
2573 
2574 	if ( !item )
2575 	{
2576 		return;
2577 	}
2578 
2579 	if ( player != clientnum )
2580 	{
2581 		consumeItem(item, player);
2582 		return;
2583 	}
2584 
2585 	if (players[player]->entity->isBlind())
2586 	{
2587 		messagePlayer(player, language[775]);
2588 		return;
2589 	}
2590 
2591 	conductIlliterate = false;
2592 
2593 	item->identified = 1;
2594 	messagePlayer(player, language[848]);
2595 
2596 	// choose a random piece of worn equipment to curse!
2597 	int tryIndex = 1 + rand() % 7;
2598 	int startIndex = tryIndex;
2599 	int armornum = 0;
2600 	bool breakloop = false;
2601 
2602 	// curse random item.
2603 	while ( !armor && !breakloop )
2604 	{
2605 		switch ( tryIndex )
2606 		{
2607 			// intentional fall throughs...
2608 			case 0:
2609 				/*if ( stats[player]->weapon != nullptr && itemCategory(stats[player]->weapon) != POTION )
2610 				{
2611 					toCurse = stats[player]->weapon;
2612 					armornum = 0;
2613 					break;
2614 				}*/
2615 			case 1:
2616 				if ( stats[player]->helmet != nullptr )
2617 				{
2618 					armor = stats[player]->helmet;
2619 					armornum = 1;
2620 					break;
2621 				}
2622 			case 2:
2623 				if ( stats[player]->breastplate != nullptr )
2624 				{
2625 					armor = stats[player]->breastplate;
2626 					armornum = 2;
2627 					break;
2628 				}
2629 			case 3:
2630 				if ( stats[player]->gloves != nullptr )
2631 				{
2632 					armor = stats[player]->gloves;
2633 					armornum = 3;
2634 					break;
2635 				}
2636 			case 4:
2637 				if ( stats[player]->shoes != nullptr )
2638 				{
2639 					armor = stats[player]->shoes;
2640 					armornum = 4;
2641 					break;
2642 				}
2643 			case 5:
2644 				if ( stats[player]->shield != nullptr )
2645 				{
2646 					armor = stats[player]->shield;
2647 					armornum = 5;
2648 					break;
2649 				}
2650 			case 6:
2651 				if ( stats[player]->cloak != nullptr )
2652 				{
2653 					armor = stats[player]->cloak;
2654 					armornum = 6;
2655 					break;
2656 				}
2657 			case 7:
2658 				if ( stats[player]->mask != nullptr )
2659 				{
2660 					armor = stats[player]->mask;
2661 					armornum = 7;
2662 					break;
2663 				}
2664 				++tryIndex;
2665 				if ( tryIndex > 7 )
2666 				{
2667 					// loop back around.
2668 					tryIndex = 0;
2669 				}
2670 				if ( tryIndex == startIndex )
2671 				{
2672 					// couldn't find a piece of armor, break.
2673 					breakloop = true;
2674 					armor = nullptr;
2675 					break;
2676 				}
2677 			default:
2678 				break;
2679 		}
2680 	}
2681 
2682 	if (armor == nullptr)
2683 	{
2684 		messagePlayer(player, language[857]);
2685 	}
2686 	else if ( armor != nullptr )
2687 	{
2688 		if (item->beatitude < 0)
2689 		{
2690 			messagePlayer(player, language[858], armor->getName());
2691 
2692 			if ( armor->beatitude > 0 )
2693 			{
2694 				armor->beatitude = -armor->beatitude;
2695 			}
2696 			else
2697 			{
2698 				armor->beatitude -= 1;
2699 			}
2700 		}
2701 		else
2702 		{
2703 			if (item->beatitude == 0)
2704 			{
2705 				messagePlayer(player, language[859], armor->getName());
2706 			}
2707 			else
2708 			{
2709 				messagePlayer(player, language[860], armor->getName());
2710 			}
2711 			armor->beatitude += 1 + item->beatitude;
2712 		}
2713 
2714 		if ( multiplayer == CLIENT )
2715 		{
2716 			strcpy((char*)net_packet->data, "BEAT");
2717 			net_packet->data[4] = clientnum;
2718 			net_packet->data[5] = armornum;
2719 			net_packet->data[6] = armor->beatitude + 100;
2720 			net_packet->address.host = net_server.host;
2721 			net_packet->address.port = net_server.port;
2722 			net_packet->len = 7;
2723 			sendPacketSafe(net_sock, -1, net_packet, 0);
2724 			//messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
2725 		}
2726 	}
2727 	consumeItem(item, player);
2728 }
2729 
item_ScrollRemoveCurse(Item * item,int player)2730 void item_ScrollRemoveCurse(Item* item, int player)
2731 {
2732 	if (players[player] == nullptr || players[player]->entity == nullptr)
2733 	{
2734 		return;
2735 	}
2736 
2737 	if ( player != clientnum )
2738 	{
2739 		consumeItem(item, player);
2740 		return;
2741 	}
2742 
2743 	if (players[player]->entity->isBlind())
2744 	{
2745 		messagePlayer(player, language[775]);
2746 		return;
2747 	}
2748 
2749 	if (item->beatitude >= 0)
2750 	{
2751 		// Uncurse an item
2752 		shootmode = false;
2753 		openStatusScreen(GUI_MODE_INVENTORY, INVENTORY_MODE_ITEM); // Reset the GUI to the inventory.
2754 		removecursegui_active = true;
2755 		if ( identifygui_active )
2756 		{
2757 			CloseIdentifyGUI();
2758 		}
2759 		GenericGUI.closeGUI();
2760 
2761 		if ( openedChest[player] )
2762 		{
2763 			openedChest[player]->closeChest();
2764 		}
2765 
2766 		initRemoveCurseGUIControllerCode();
2767 		consumeItem(item, player);
2768 		return;
2769 	}
2770 	else
2771 	{
2772 		// choose a random piece of worn equipment to curse!
2773 		int tryIndex = rand() % 8;
2774 		int startIndex = tryIndex;
2775 		int armornum = 0;
2776 		bool breakloop = false;
2777 		Item* toCurse = nullptr;
2778 		// curse random item.
2779 		while ( !toCurse && !breakloop )
2780 		{
2781 			switch ( tryIndex )
2782 			{
2783 				// intentional fall throughs...
2784 				case 0:
2785 					if ( stats[player]->weapon != nullptr && itemCategory(stats[player]->weapon) != POTION )
2786 					{
2787 						toCurse = stats[player]->weapon;
2788 						armornum = 0;
2789 						break;
2790 					}
2791 				case 1:
2792 					if ( stats[player]->helmet != nullptr )
2793 					{
2794 						toCurse = stats[player]->helmet;
2795 						armornum = 1;
2796 						break;
2797 					}
2798 				case 2:
2799 					if ( stats[player]->breastplate != nullptr )
2800 					{
2801 						toCurse = stats[player]->breastplate;
2802 						armornum = 2;
2803 						break;
2804 					}
2805 				case 3:
2806 					if ( stats[player]->gloves != nullptr )
2807 					{
2808 						toCurse = stats[player]->gloves;
2809 						armornum = 3;
2810 						break;
2811 					}
2812 				case 4:
2813 					if ( stats[player]->shoes != nullptr )
2814 					{
2815 						toCurse = stats[player]->shoes;
2816 						armornum = 4;
2817 						break;
2818 					}
2819 				case 5:
2820 					if ( stats[player]->shield != nullptr )
2821 					{
2822 						toCurse = stats[player]->shield;
2823 						armornum = 5;
2824 						break;
2825 					}
2826 				case 6:
2827 					if ( stats[player]->cloak != nullptr )
2828 					{
2829 						toCurse = stats[player]->cloak;
2830 						armornum = 6;
2831 						break;
2832 					}
2833 				case 7:
2834 					if ( stats[player]->mask != nullptr )
2835 					{
2836 						toCurse = stats[player]->mask;
2837 						armornum = 7;
2838 						break;
2839 					}
2840 					++tryIndex;
2841 					if ( tryIndex > 7 )
2842 					{
2843 						// loop back around.
2844 						tryIndex = 0;
2845 					}
2846 					if ( tryIndex == startIndex )
2847 					{
2848 						// couldn't find a piece of armor, break.
2849 						breakloop = true;
2850 						toCurse = nullptr;
2851 						break;
2852 					}
2853 				default:
2854 					break;
2855 			}
2856 		}
2857 		if ( toCurse )
2858 		{
2859 			if ( toCurse->beatitude <= 0 )
2860 			{
2861 				--toCurse->beatitude;
2862 			}
2863 			else
2864 			{
2865 				toCurse->beatitude = -toCurse->beatitude;
2866 				if ( itemCategory(toCurse) == WEAPON && stats[clientnum]->type == SUCCUBUS )
2867 				{
2868 					steamAchievement("BARONY_ACH_THE_WAY_YOU_LIKE_IT");
2869 				}
2870 			}
2871 			messagePlayer(player, language[858], toCurse->getName());
2872 			if ( multiplayer == CLIENT )
2873 			{
2874 				strcpy((char*)net_packet->data, "BEAT");
2875 				net_packet->data[4] = clientnum;
2876 				net_packet->data[5] = armornum;
2877 				net_packet->data[6] = toCurse->beatitude + 100;
2878 				net_packet->address.host = net_server.host;
2879 				net_packet->address.port = net_server.port;
2880 				net_packet->len = 7;
2881 				sendPacketSafe(net_sock, -1, net_packet, 0);
2882 				//messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
2883 			}
2884 		}
2885 		else
2886 		{
2887 			messagePlayer(player, language[862]);
2888 		}
2889 	}
2890 	consumeItem(item, player);
2891 }
2892 
item_ScrollFire(Item * item,int player)2893 bool item_ScrollFire(Item* item, int player)
2894 {
2895 	if (multiplayer == CLIENT)
2896 	{
2897 		return false;
2898 	}
2899 
2900 	if (players[player] == nullptr || players[player]->entity == nullptr)
2901 	{
2902 		return false;
2903 	}
2904 
2905 	if (players[player]->entity->isBlind())
2906 	{
2907 		messagePlayer(player, language[775]);
2908 		return false;
2909 	}
2910 
2911 	if (player == clientnum)
2912 	{
2913 		conductIlliterate = false;
2914 	}
2915 
2916 	if ( stats[player]->type != AUTOMATON )
2917 	{
2918 		serverUpdatePlayerGameplayStats(player, STATISTICS_FIRE_MAYBE_DIFFERENT, 1);
2919 	}
2920 
2921 	item->identified = 1;
2922 	if (item->beatitude < 0)
2923 	{
2924 		messagePlayer(player, language[863]);
2925 		return false;
2926 	}
2927 	else
2928 	{
2929 		playSoundEntity(players[player]->entity, 153, 128); // "FireballExplode.ogg"
2930 		messagePlayer(player, language[864]); // "The scroll erupts in a tower of flame!"
2931 
2932 		// Attempt to set the Player on fire
2933 		players[player]->entity->SetEntityOnFire();
2934 
2935 		int c;
2936 		for (c = 0; c < 100; c++)
2937 		{
2938 			Entity* entity = spawnFlame(players[player]->entity, SPRITE_FLAME);
2939 			entity->sprite = 16;
2940 			double vel = rand() % 10;
2941 			entity->vel_x = vel * cos(entity->yaw) * cos(entity->pitch) * .1;
2942 			entity->vel_y = vel * sin(entity->yaw) * cos(entity->pitch) * .1;
2943 			entity->vel_z = vel * sin(entity->pitch) * .2;
2944 			entity->skill[0] = 5 + rand() % 10;
2945 		}
2946 		return true;
2947 	}
2948 	return false;
2949 }
2950 
item_ScrollFood(Item * item,int player)2951 void item_ScrollFood(Item* item, int player)
2952 {
2953 	Item* target;
2954 	node_t* node, *nextnode;
2955 	int foundfood = 0;
2956 
2957 	if (players[player] == nullptr || players[player]->entity == nullptr)
2958 	{
2959 		return;
2960 	}
2961 
2962 	// this is a CLIENT function
2963 	if (player != clientnum)
2964 	{
2965 		return;
2966 	}
2967 
2968 	if (players[player]->entity->isBlind())
2969 	{
2970 		messagePlayer(player, language[775]);
2971 		return;
2972 	}
2973 
2974 	if ( player == clientnum )
2975 	{
2976 		conductIlliterate = false;
2977 	}
2978 	item->identified = 1;
2979 	messagePlayer(player, language[848]);
2980 	if ( item->beatitude >= 0 )
2981 	{
2982 		messagePlayer(player, language[865]);
2983 		dropItem(newItem(FOOD_FISH, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2984 		dropItem(newItem(FOOD_BREAD, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2985 		dropItem(newItem(FOOD_APPLE, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2986 		dropItem(newItem(FOOD_CHEESE, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2987 		dropItem(newItem(FOOD_MEAT, EXCELLENT, item->beatitude, 1, rand(), true, &stats[player]->inventory), player);
2988 		return;
2989 	}
2990 	else
2991 	{
2992 		for ( node = stats[player]->inventory.first; node != NULL; node = nextnode )
2993 		{
2994 			nextnode = node->next;
2995 			target = (Item*)node->element;
2996 			if ( itemCategory(target) == FOOD )
2997 			{
2998 				if ( rand() % 2 == 0 )   // 50% chance of destroying that food item
2999 				{
3000 					consumeItem(target, player);
3001 				}
3002 				foundfood = 1;
3003 			}
3004 		}
3005 	}
3006 	if ( foundfood == 0 )
3007 	{
3008 		messagePlayer(player, language[866]);
3009 	}
3010 	else
3011 	{
3012 		messagePlayer(player, language[867]);
3013 	}
3014 }
3015 
item_ScrollConjureArrow(Item * item,int player)3016 void item_ScrollConjureArrow(Item* item, int player)
3017 {
3018 	if ( players[player] == nullptr || players[player]->entity == nullptr )
3019 	{
3020 		return;
3021 	}
3022 
3023 	// this is a CLIENT function
3024 	if ( player != clientnum )
3025 	{
3026 		return;
3027 	}
3028 
3029 	if ( players[player]->entity->isBlind() )
3030 	{
3031 		messagePlayer(player, language[775]);
3032 		return;
3033 	}
3034 
3035 	if ( player == clientnum )
3036 	{
3037 		conductIlliterate = false;
3038 	}
3039 	item->identified = 1;
3040 	messagePlayer(player, language[848]);
3041 	messagePlayer(player, language[3762]);
3042 	ItemType type = static_cast<ItemType>(QUIVER_SILVER + rand() % 7);
3043 
3044 	int amount = 20 + rand() % 6;
3045 	if ( item->beatitude < 0 )
3046 	{
3047 		amount -= (15  + rand() % 6);
3048 	}
3049 	else if ( item->beatitude > 0 )
3050 	{
3051 		amount += 20 + rand() % 6;
3052 	}
3053 	dropItem(newItem(type, SERVICABLE, item->beatitude, amount, ITEM_GENERATED_QUIVER_APPEARANCE, false, &stats[player]->inventory), player, false);
3054 	if ( item->beatitude >= 2 )
3055 	{
3056 		// re-roll!
3057 		type = static_cast<ItemType>(QUIVER_SILVER + rand() % 7);
3058 		amount = 40 + rand() % 11;
3059 		dropItem(newItem(type, SERVICABLE, item->beatitude, amount, ITEM_GENERATED_QUIVER_APPEARANCE, false, &stats[player]->inventory), player, false);
3060 	}
3061 }
3062 
item_ScrollMagicMapping(Item * item,int player)3063 void item_ScrollMagicMapping(Item* item, int player)
3064 {
3065 	int x, y;
3066 
3067 	if (players[player] == nullptr || players[player]->entity == nullptr)
3068 	{
3069 		return;
3070 	}
3071 
3072 	// this is a CLIENT function
3073 	if (multiplayer == SERVER && player > 0)
3074 	{
3075 		return;
3076 	}
3077 
3078 	if (players[player]->entity->isBlind())
3079 	{
3080 		messagePlayer(player, language[775]);
3081 		return;
3082 	}
3083 
3084 	if ( player == clientnum )
3085 	{
3086 		conductIlliterate = false;
3087 	}
3088 	item->identified = 1;
3089 	messagePlayer(player, language[848]);
3090 	if ( item->beatitude >= 0 )
3091 	{
3092 		messagePlayer(player, language[868]);
3093 		mapLevel(player);
3094 	}
3095 	else
3096 	{
3097 		messagePlayer(player, language[869]);
3098 		for ( y = 0; y < map.height; y++ )
3099 		{
3100 			for ( x = 0; x < map.width; x++ )
3101 			{
3102 				minimap[y][x] = 0;
3103 			}
3104 		}
3105 	}
3106 }
3107 
item_ScrollRepair(Item * item,int player)3108 void item_ScrollRepair(Item* item, int player)
3109 {
3110 	Item* armor = nullptr;
3111 	if (players[player] == nullptr || players[player]->entity == nullptr)
3112 	{
3113 		return;
3114 	}
3115 
3116 	// client function only
3117 	if ( player != clientnum )
3118 	{
3119 		consumeItem(item, player);
3120 		return;
3121 	}
3122 
3123 	if (players[player]->entity->isBlind())
3124 	{
3125 		messagePlayer(player, language[775]);
3126 		return;
3127 	}
3128 
3129 	conductIlliterate = false;
3130 	if ( item->identified && item->beatitude >= 0 )
3131 	{
3132 		// quickly check if we have any items available so we don't waste our scroll
3133 		bool foundRepairableItem = false;
3134 		for ( node_t* node = stats[player]->inventory.first; node != nullptr; node = node->next )
3135 		{
3136 			Item* inventoryItem = (Item*)node->element;
3137 			if ( GenericGUI.isItemRepairable(inventoryItem, item->type) )
3138 			{
3139 				foundRepairableItem = true;
3140 				break;
3141 			}
3142 		}
3143 		if ( !foundRepairableItem )
3144 		{
3145 			if ( item->type == SCROLL_REPAIR )
3146 			{
3147 				messagePlayer(player, language[3288]);
3148 			}
3149 			else if ( item->type == SCROLL_CHARGING )
3150 			{
3151 				messagePlayer(player, language[3731]);
3152 			}
3153 			return;
3154 		}
3155 	}
3156 
3157 	item->identified = true;
3158 	messagePlayer(player, language[848]);
3159 	if ( item->beatitude < 0 )
3160 	{
3161 		int tryIndex = rand() % 7;
3162 		int startIndex = tryIndex;
3163 		int armornum = 0;
3164 		bool breakloop = false;
3165 		// degrade random equipped item.
3166 		while ( !armor && !breakloop )
3167 		{
3168 			switch ( tryIndex )
3169 			{
3170 				// intentional fall throughs...
3171 				case 0:
3172 					if ( stats[player]->weapon != nullptr && itemCategory(stats[player]->weapon) != POTION )
3173 					{
3174 						armor = stats[player]->weapon;
3175 						armornum = 0;
3176 						break;
3177 					}
3178 				case 1:
3179 					if ( stats[player]->helmet != nullptr )
3180 					{
3181 						armor = stats[player]->helmet;
3182 						armornum = 1;
3183 						break;
3184 					}
3185 				case 2:
3186 					if ( stats[player]->breastplate != nullptr )
3187 					{
3188 						armor = stats[player]->breastplate;
3189 						armornum = 2;
3190 						break;
3191 					}
3192 				case 3:
3193 					if ( stats[player]->gloves != nullptr )
3194 					{
3195 						armor = stats[player]->gloves;
3196 						armornum = 3;
3197 						break;
3198 					}
3199 				case 4:
3200 					if ( stats[player]->shoes != nullptr )
3201 					{
3202 						armor = stats[player]->shoes;
3203 						armornum = 4;
3204 						break;
3205 					}
3206 				case 5:
3207 					if ( stats[player]->shield != nullptr )
3208 					{
3209 						armor = stats[player]->shield;
3210 						armornum = 5;
3211 						break;
3212 					}
3213 				case 6:
3214 					if ( stats[player]->cloak != nullptr )
3215 					{
3216 						armor = stats[player]->cloak;
3217 						armornum = 6;
3218 						break;
3219 					}
3220 					++tryIndex;
3221 					if ( tryIndex > 6 )
3222 					{
3223 						// loop back around.
3224 						tryIndex = 0;
3225 					}
3226 					if ( tryIndex == startIndex )
3227 					{
3228 						// couldn't find a piece of armor, break.
3229 						breakloop = true;
3230 						armor = nullptr;
3231 						break;
3232 					}
3233 				default:
3234 					break;
3235 			}
3236 		}
3237 		if ( armor == nullptr )
3238 		{
3239 			messagePlayer(player, language[870]); // you feel a tingling sensation
3240 		}
3241 		else if ( armor != nullptr )
3242 		{
3243 			messagePlayer(player, language[871], armor->getName());
3244 			if ( item->type == SCROLL_CHARGING )
3245 			{
3246 				armor->status = BROKEN;
3247 			}
3248 			else
3249 			{
3250 				armor->status = static_cast<Status>(std::max(armor->status - 2, static_cast<int>(BROKEN)));
3251 			}
3252 			if ( multiplayer == CLIENT )
3253 			{
3254 				strcpy((char*)net_packet->data, "REPA");
3255 				net_packet->data[4] = clientnum;
3256 				net_packet->data[5] = armornum;
3257 				net_packet->data[6] = armor->status;
3258 				net_packet->address.host = net_server.host;
3259 				net_packet->address.port = net_server.port;
3260 				net_packet->len = 7;
3261 				sendPacketSafe(net_sock, -1, net_packet, 0);
3262 
3263 				//messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
3264 			}
3265 			if ( armor->status > BROKEN )
3266 			{
3267 				if ( armor->type == TOOL_CRYSTALSHARD )
3268 				{
3269 					messagePlayer(player, language[2350], armor->getName());
3270 				}
3271 				else
3272 				{
3273 					messagePlayer(player, language[681], armor->getName());
3274 				}
3275 			}
3276 			else
3277 			{
3278 				if ( armor->type == TOOL_CRYSTALSHARD )
3279 				{
3280 					playSoundPlayer(player, 162, 64);
3281 					messagePlayer(player, language[2351], armor->getName());
3282 				}
3283 				else
3284 				{
3285 					playSoundPlayer(player, 76, 64);
3286 					messagePlayer(player, language[682], armor->getName());
3287 				}
3288 			}
3289 		}
3290 	}
3291 	else
3292 	{
3293 		// Repair an item
3294 		GenericGUI.openGUI(GUI_TYPE_REPAIR, item->beatitude, item->type);
3295 	}
3296 	consumeItem(item, player);
3297 }
3298 
item_ScrollDestroyArmor(Item * item,int player)3299 void item_ScrollDestroyArmor(Item* item, int player)
3300 {
3301 	Item* armor = nullptr;
3302 	if (players[player] == nullptr || players[player]->entity == nullptr)
3303 	{
3304 		return;
3305 	}
3306 
3307 	// client function only
3308 	if ( player != clientnum )
3309 	{
3310 		consumeItem(item, player);
3311 		return;
3312 	}
3313 
3314 	if (players[player]->entity->isBlind())
3315 	{
3316 		messagePlayer(player, language[775]);
3317 		return;
3318 	}
3319 
3320 	conductIlliterate = false;
3321 	item->identified = 1;
3322 
3323 	messagePlayer(player, language[848]);
3324 
3325 	int armornum = 0;
3326 	int tryIndex = 1 + rand() % 6;
3327 	int startIndex = tryIndex;
3328 	bool breakloop = false;
3329 	while ( !armor && !breakloop )
3330 	{
3331 		switch ( tryIndex )
3332 		{
3333 			// intentional fall throughs...
3334 			case 0:
3335 				// shouldn't occur
3336 				/*if ( stats[player]->weapon != nullptr )
3337 				{
3338 					armor = stats[player]->weapon;
3339 					armornum = 0;
3340 					break;
3341 				}*/
3342 			case 1:
3343 				if ( stats[player]->helmet != nullptr )
3344 				{
3345 					armor = stats[player]->helmet;
3346 					armornum = 1;
3347 					break;
3348 				}
3349 			case 2:
3350 				if ( stats[player]->breastplate != nullptr )
3351 				{
3352 					armor = stats[player]->breastplate;
3353 					armornum = 2;
3354 					break;
3355 				}
3356 			case 3:
3357 				if ( stats[player]->gloves != nullptr )
3358 				{
3359 					armor = stats[player]->gloves;
3360 					armornum = 3;
3361 					break;
3362 				}
3363 			case 4:
3364 				if ( stats[player]->shoes != nullptr )
3365 				{
3366 					armor = stats[player]->shoes;
3367 					armornum = 4;
3368 					break;
3369 				}
3370 			case 5:
3371 				if ( stats[player]->shield != nullptr )
3372 				{
3373 					armor = stats[player]->shield;
3374 					armornum = 5;
3375 					break;
3376 				}
3377 			case 6:
3378 				if ( stats[player]->cloak != nullptr )
3379 				{
3380 					armor = stats[player]->cloak;
3381 					armornum = 6;
3382 					break;
3383 				}
3384 				++tryIndex;
3385 				if ( tryIndex > 6 )
3386 				{
3387 					// loop back around.
3388 					tryIndex = 1;
3389 				}
3390 				if ( tryIndex == startIndex )
3391 				{
3392 					// couldn't find a piece of armor, break.
3393 					breakloop = true;
3394 					armor = nullptr;
3395 					break;
3396 				}
3397 			default:
3398 				break;
3399 		}
3400 	}
3401 
3402 	if ( armor == nullptr )
3403 	{
3404 		messagePlayer(player, language[873]);
3405 	}
3406 	else if ( armor != nullptr )
3407 	{
3408 		if ( item->beatitude < 0 )
3409 		{
3410 			messagePlayer(player, language[874], armor->getName());
3411 		}
3412 		else
3413 		{
3414 			messagePlayer(player, language[875], armor->getName());
3415 
3416 			armor->status = static_cast<Status>(0);
3417 
3418 			if ( multiplayer == CLIENT )
3419 			{
3420 				strcpy((char*)net_packet->data, "REPA");
3421 				net_packet->data[4] = clientnum;
3422 				net_packet->data[5] = armornum;
3423 				net_packet->data[6] = armor->status;
3424 				net_packet->address.host = net_server.host;
3425 				net_packet->address.port = net_server.port;
3426 				net_packet->len = 7;
3427 				sendPacketSafe(net_sock, -1, net_packet, 0);
3428 
3429 				//messagePlayer(clientnum, "sent server: %d, %d, %d", net_packet->data[4], net_packet->data[5], net_packet->data[6]);
3430 			}
3431 
3432 			if ( armor->status == BROKEN )
3433 			{
3434 				if ( armor->type == TOOL_CRYSTALSHARD )
3435 				{
3436 					playSoundPlayer(player, 162, 64);
3437 					messagePlayer(player, language[2351], armor->getName());
3438 				}
3439 				else
3440 				{
3441 					playSoundPlayer(player, 76, 64);
3442 					messagePlayer(player, language[682], armor->getName());
3443 				}
3444 			}
3445 		}
3446 	}
3447 	consumeItem(item, player);
3448 }
3449 
item_ScrollTeleportation(Item * item,int player)3450 void item_ScrollTeleportation(Item* item, int player)
3451 {
3452 	// server only function
3453 	if (players[player] == nullptr || players[player]->entity == nullptr)
3454 	{
3455 		return;
3456 	}
3457 	if (multiplayer == CLIENT)
3458 	{
3459 		return;
3460 	}
3461 
3462 	if (players[player]->entity->isBlind())
3463 	{
3464 		if (player == clientnum)
3465 		{
3466 			messagePlayer(player, language[775]);
3467 		}
3468 		return;
3469 	}
3470 
3471 	if (player == clientnum)
3472 	{
3473 		conductIlliterate = false;
3474 	}
3475 	item->identified = 1;
3476 	messagePlayer(player, language[848]);
3477 	if (item->beatitude < 0 && rand() % 2)
3478 	{
3479 		messagePlayer(player, language[876]);
3480 		return;
3481 	}
3482 
3483 	players[player]->entity->teleportRandom();
3484 }
3485 
item_ScrollSummon(Item * item,int player)3486 void item_ScrollSummon(Item* item, int player)
3487 {
3488 	// server only function
3489 	if (players[player] == nullptr || players[player]->entity == nullptr)
3490 	{
3491 		return;
3492 	}
3493 	if (multiplayer == CLIENT)
3494 	{
3495 		return;
3496 	}
3497 
3498 	if (players[player]->entity->isBlind())
3499 	{
3500 		if (player == clientnum)
3501 		{
3502 			messagePlayer(player, language[775]);
3503 		}
3504 		return;
3505 	}
3506 
3507 	if ( player == clientnum )
3508 	{
3509 		conductIlliterate = false;
3510 	}
3511 	item->identified = 1;
3512 	messagePlayer(player, language[848]);
3513 
3514 	playSoundEntity(players[player]->entity, 153, 64);
3515 	Uint32 numCreatures = 1;
3516 	Monster creature = RAT;
3517 
3518 	if (item->beatitude <= -2)
3519 	{
3520 		// spawn something really nasty
3521 		numCreatures = 1;
3522 		switch (rand() % 4)
3523 		{
3524 			case 0:
3525 				creature = MINOTAUR;
3526 				break;
3527 			case 1:
3528 				creature = DEMON;
3529 				break;
3530 			case 2:
3531 				creature = CREATURE_IMP;
3532 				break;
3533 			case 3:
3534 				creature = TROLL;
3535 				break;
3536 		}
3537 	}
3538 	else if (item->beatitude == -1)
3539 	{
3540 		// spawn moderately nasty things
3541 		switch (rand() % 6)
3542 		{
3543 			case 0:
3544 				creature = GNOME;
3545 				numCreatures = rand() % 3 + 1;
3546 				break;
3547 			case 1:
3548 				creature = SPIDER;
3549 				numCreatures = rand() % 2 + 1;
3550 				break;
3551 			case 2:
3552 				creature = SUCCUBUS;
3553 				numCreatures = rand() % 2 + 1;
3554 				break;
3555 			case 3:
3556 				creature = SCORPION;
3557 				numCreatures = rand() % 2 + 1;
3558 				break;
3559 			case 4:
3560 				creature = GHOUL;
3561 				numCreatures = rand() % 2 + 1;
3562 				break;
3563 			case 5:
3564 				creature = GOBLIN;
3565 				numCreatures = rand() % 2 + 1;
3566 				break;
3567 		}
3568 	}
3569 	else if (item->beatitude == 0)
3570 	{
3571 		// spawn weak monster ally
3572 		switch (rand() % 3)
3573 		{
3574 			case 0:
3575 				creature = RAT;
3576 				numCreatures = rand() % 3 + 1;
3577 				break;
3578 			case 1:
3579 				creature = GHOUL;
3580 				numCreatures = 1;
3581 				break;
3582 			case 2:
3583 				creature = SLIME;
3584 				numCreatures = rand() % 2 + 1;
3585 				break;
3586 		}
3587 	}
3588 	else if (item->beatitude == 1)
3589 	{
3590 		// spawn humans
3591 		creature = HUMAN;
3592 		numCreatures = rand() % 3 + 1;
3593 	}
3594 	else if (item->beatitude >= 2)
3595 	{
3596 		//Spawn many/neat allies
3597 		switch (rand() % 2)
3598 		{
3599 			case 0:
3600 				// summon zap brigadiers
3601 				numCreatures = rand() % 2 + 4;
3602 				creature = HUMAN;
3603 				break;
3604 			case 1:
3605 				// summon demons
3606 				numCreatures = rand() % 2 + 4;
3607 				creature = DEMON;
3608 				break;
3609 		}
3610 	}
3611 
3612 	int i;
3613 	bool spawnedMonster = false;
3614 	for (i = 0; i < numCreatures; ++i)
3615 	{
3616 		Entity* monster = summonMonster(creature, floor(players[player]->entity->x / 16) * 16 + 8, floor(players[player]->entity->y / 16) * 16 + 8);
3617 		if ( monster )
3618 		{
3619 			spawnedMonster = true;
3620 			if ( item->beatitude >= 2 && creature == HUMAN )
3621 			{
3622 				monster->skill[29] = 1; // zap brigadier
3623 			}
3624 			Stat* monsterStats = monster->getStats();
3625 			if ( item->beatitude >= 0 && monsterStats )
3626 			{
3627 				monsterStats->leader_uid = players[player]->entity->getUID();
3628 				monster->flags[USERFLAG2] = true;
3629 				/*if ( !monsterally[HUMAN][monsterStats->type] )
3630 				{
3631 				}*/
3632 				monster->monsterAllyIndex = player;
3633 				if ( multiplayer == SERVER )
3634 				{
3635 					serverUpdateEntitySkill(monster, 42); // update monsterAllyIndex for clients.
3636 				}
3637 
3638 				// update followers for this player
3639 				node_t* newNode = list_AddNodeLast(&stats[player]->FOLLOWERS);
3640 				newNode->deconstructor = &defaultDeconstructor;
3641 				Uint32* myuid = (Uint32*) malloc(sizeof(Uint32));
3642 				newNode->element = myuid;
3643 				*myuid = monster->getUID();
3644 
3645 				// update client followers
3646 				if ( player > 0 && multiplayer == SERVER )
3647 				{
3648 					strcpy((char*)net_packet->data, "LEAD");
3649 					SDLNet_Write32((Uint32)monster->getUID(), &net_packet->data[4]);
3650 					strcpy((char*)(&net_packet->data[8]), monsterStats->name);
3651 					net_packet->data[8 + strlen(monsterStats->name)] = 0;
3652 					net_packet->address.host = net_clients[player - 1].host;
3653 					net_packet->address.port = net_clients[player - 1].port;
3654 					net_packet->len = 8 + strlen(monsterStats->name) + 1;
3655 					sendPacketSafe(net_sock, -1, net_packet, player - 1);
3656 
3657 					serverUpdateAllyStat(player, monster->getUID(), monsterStats->LVL, monsterStats->HP, monsterStats->MAXHP, monsterStats->type);
3658 				}
3659 
3660 				if ( !FollowerMenu.recentEntity && player == clientnum )
3661 				{
3662 					FollowerMenu.recentEntity = monster;
3663 				}
3664 			}
3665 		}
3666 	}
3667 	if ( spawnedMonster )
3668 	{
3669 		if ( item->beatitude < 0 )
3670 		{
3671 			if ( numCreatures <= 1 )
3672 			{
3673 				if ( creature < KOBOLD ) //Original monster count
3674 				{
3675 					messagePlayer(player, language[877], language[90 + creature]);
3676 
3677 				}
3678 				else if ( creature >= KOBOLD ) //New monsters
3679 				{
3680 					messagePlayer(player, language[877], language[2000 + (creature - KOBOLD)]);
3681 				}
3682 			}
3683 			else
3684 			{
3685 				if ( creature < KOBOLD ) //Original monster count
3686 				{
3687 					messagePlayer(player, language[878], language[111 + creature]);
3688 
3689 				}
3690 				else if ( creature >= KOBOLD ) //New monsters
3691 				{
3692 					messagePlayer(player, language[878], language[2050 + (creature - KOBOLD)]);
3693 				}
3694 			}
3695 		}
3696 		else
3697 		{
3698 			if ( numCreatures <= 1 )
3699 			{
3700 				if ( creature < KOBOLD ) //Original monster count
3701 				{
3702 					messagePlayer(player, language[879], language[90 + creature]);
3703 
3704 				}
3705 				else if ( creature >= KOBOLD ) //New monsters
3706 				{
3707 					messagePlayer(player, language[879], language[2000 + (creature - KOBOLD)]);
3708 				}
3709 				if ( item->beatitude >= 2 )
3710 				{
3711 					messagePlayer(player, language[880]);
3712 				}
3713 			}
3714 			else
3715 			{
3716 				if ( creature < KOBOLD ) //Original monster count
3717 				{
3718 					messagePlayer(player, language[881], language[111 + creature]);
3719 
3720 				}
3721 				else if ( creature >= KOBOLD ) //New monsters
3722 				{
3723 					messagePlayer(player, language[881], language[2050 + (creature - KOBOLD)]);
3724 				}
3725 				if ( item->beatitude >= 2 )
3726 				{
3727 					messagePlayer(player, language[882]);
3728 				}
3729 			}
3730 		}
3731 	}
3732 }
3733 
item_ToolTowel(Item * & item,int player)3734 void item_ToolTowel(Item*& item, int player)
3735 {
3736 	if ( player == clientnum )
3737 	{
3738 		messagePlayer(player, language[883]);
3739 	}
3740 	if ( multiplayer != CLIENT )
3741 	{
3742 		if ( stats[player]->EFFECTS[EFF_GREASY]
3743 			|| stats[player]->EFFECTS[EFF_MESSY]
3744 			|| stats[player]->EFFECTS[EFF_BLEEDING] )
3745 		{
3746 			steamAchievementClient(player, "BARONY_ACH_BRING_A_TOWEL");
3747 		}
3748 		stats[player]->EFFECTS[EFF_GREASY] = false;
3749 		stats[player]->EFFECTS[EFF_MESSY] = false;
3750 	}
3751 
3752 	// stop bleeding
3753 	if ( stats[player]->EFFECTS[EFF_BLEEDING] )
3754 	{
3755 		if ( player == clientnum )
3756 		{
3757 			messagePlayer(player, language[884]);
3758 			messagePlayer(player, language[885]);
3759 		}
3760 		if ( multiplayer != CLIENT )
3761 		{
3762 			stats[player]->EFFECTS[EFF_BLEEDING] = false;
3763 			stats[player]->EFFECTS_TIMERS[EFF_BLEEDING] = 0;
3764 		}
3765 		consumeItem(item, player);
3766 	}
3767 
3768 	if ( multiplayer != CLIENT )
3769 	{
3770 		serverUpdateEffects(player);
3771 	}
3772 }
3773 
item_ToolTinOpener(Item * item,int player)3774 void item_ToolTinOpener(Item* item, int player)
3775 {
3776 	if (multiplayer == CLIENT)
3777 	{
3778 		return;
3779 	}
3780 
3781 	messagePlayer(player, language[886]);
3782 }
3783 
item_ToolMirror(Item * & item,int player)3784 void item_ToolMirror(Item*& item, int player)
3785 {
3786 	if (players[player] == nullptr || players[player]->entity == nullptr)
3787 	{
3788 		return;
3789 	}
3790 
3791 	if ( player == clientnum )
3792 	{
3793 		messagePlayer(player, language[889]);
3794 	}
3795 	if ( players[player]->entity->isInvisible() || (stats[player] && stats[player]->type == VAMPIRE) )
3796 	{
3797 		if ( player == clientnum )
3798 		{
3799 			messagePlayer(player, language[893]);
3800 		}
3801 		return;
3802 	}
3803 	else if ( stats[player] && stats[player]->type == AUTOMATON )
3804 	{
3805 		messagePlayer(player, language[3698]);
3806 	}
3807 
3808 	if (item->beatitude > 0 && !stats[player]->EFFECTS[EFF_GREASY])
3809 	{
3810 		if (multiplayer != CLIENT)
3811 		{
3812 			players[player]->entity->teleportRandom();
3813 		}
3814 	}
3815 	if (player != clientnum)   //TODO: Hotseat? (player != clientnum || !players[player]->hotseat
3816 	{
3817 		return;
3818 	}
3819 
3820 	if ( stats[player]->EFFECTS[EFF_GREASY] )
3821 	{
3822 		messagePlayer(player, language[887]);
3823 		messagePlayer(player, language[888]);
3824 		consumeItem(item, player);
3825 		return;
3826 	}
3827 	if ( stats[player]->EFFECTS[EFF_BLIND] )
3828 	{
3829 		messagePlayer(player, language[892]);
3830 		return;
3831 	}
3832 	if ( item->beatitude > 0 )
3833 	{
3834 		messagePlayer(player, language[890]);
3835 		return;
3836 	}
3837 	else if ( item->beatitude < 0 )
3838 	{
3839 		if ( stats[player]->EFFECTS[EFF_BLIND] )
3840 		{
3841 			messagePlayer(player, language[892]);
3842 		}
3843 		else
3844 		{
3845 			messagePlayer(player, language[891]);
3846 		}
3847 		consumeItem(item, player);
3848 		return;
3849 	}
3850 	if ( stats[player]->EFFECTS[EFF_DRUNK] )
3851 	{
3852 		if ( stats[player]->sex == MALE )
3853 		{
3854 			messagePlayer(player, language[894]);
3855 		}
3856 		else
3857 		{
3858 			messagePlayer(player, language[895]);
3859 		}
3860 		return;
3861 	}
3862 	if ( stats[player]->EFFECTS[EFF_CONFUSED] )
3863 	{
3864 		messagePlayer(player, language[896]);
3865 		return;
3866 	}
3867 	if ( stats[player]->EFFECTS[EFF_POISONED] )
3868 	{
3869 		messagePlayer(player, language[897]);
3870 		return;
3871 	}
3872 	if ( stats[player]->EFFECTS[EFF_VOMITING] )
3873 	{
3874 		messagePlayer(player, language[898]);
3875 		return;
3876 	}
3877 	if ( stats[player]->EFFECTS[EFF_MESSY] )
3878 	{
3879 		messagePlayer(player, language[899]);
3880 		return;
3881 	}
3882 	if ( stats[player]->HUNGER < 200 )
3883 	{
3884 		messagePlayer(player, language[900]);
3885 		return;
3886 	}
3887 	if ( stats[player]->HUNGER < 500 )
3888 	{
3889 		messagePlayer(player, language[901]);
3890 		return;
3891 	}
3892 
3893 	if ( stats[player]->CHR < 2 )
3894 	{
3895 		messagePlayer(player, language[902]);
3896 		return;
3897 	}
3898 	else
3899 	{
3900 		if ( stats[player]->sex == MALE )
3901 		{
3902 			messagePlayer(player, language[903]);
3903 		}
3904 		else
3905 		{
3906 			messagePlayer(player, language[904]);
3907 		}
3908 		return;
3909 	}
3910 }
3911 
item_ToolBeartrap(Item * & item,int player)3912 void item_ToolBeartrap(Item*& item, int player)
3913 {
3914 	Entity* entity;
3915 
3916 	int u, v;
3917 	if ( players[player] && players[player]->entity )
3918 	{
3919 		int x = std::min(std::max<unsigned int>(1, players[player]->entity->x / 16), map.width - 2);
3920 		int y = std::min(std::max<unsigned int>(1, players[player]->entity->y / 16), map.height - 2);
3921 		for ( u = x - 1; u <= x + 1; u++ )
3922 		{
3923 			for ( v = y - 1; v <= y + 1; v++ )
3924 			{
3925 				if ( entityInsideTile(players[player]->entity, u, v, 0) )   // no floor
3926 				{
3927 					if ( multiplayer != CLIENT )
3928 					{
3929 						messagePlayer(player, language[3035]);
3930 					}
3931 					return;
3932 				}
3933 			}
3934 		}
3935 	}
3936 
3937 	if ( multiplayer == CLIENT )
3938 	{
3939 		consumeItem(item, player);
3940 		return;
3941 	}
3942 	bool failed = false;
3943 	switch ( item->status )
3944 	{
3945 		case SERVICABLE:
3946 			if ( rand() % 25 == 0 )
3947 			{
3948 				failed = true;
3949 			}
3950 			break;
3951 		case WORN:
3952 			if ( rand() % 10 == 0 )
3953 			{
3954 				failed = true;
3955 			}
3956 			break;
3957 		case DECREPIT:
3958 			if ( rand() % 4 == 0 )
3959 			{
3960 				failed = true;
3961 			}
3962 			break;
3963 		default:
3964 			break;
3965 	}
3966 	if (item->beatitude < 0 || failed)
3967 	{
3968 		if (player == clientnum)
3969 		{
3970 			messagePlayer(player, language[905]);
3971 		}
3972 		if (multiplayer != CLIENT)
3973 		{
3974 			playSoundEntity(players[player]->entity, 76, 64);
3975 		}
3976 		consumeItem(item, player);
3977 		return;
3978 	}
3979 	if ( multiplayer != CLIENT )
3980 	{
3981 		playSoundEntity(players[player]->entity, 253, 64);
3982 	}
3983 	entity = newEntity(668, 1, map.entities, nullptr); //Beartrap entity.
3984 	entity->behavior = &actBeartrap;
3985 	entity->flags[PASSABLE] = true;
3986 	entity->flags[UPDATENEEDED] = true;
3987 	entity->x = players[player]->entity->x;
3988 	entity->y = players[player]->entity->y;
3989 	entity->z = 6.75;
3990 	entity->yaw = players[player]->entity->yaw;
3991 	entity->roll = -PI / 2; // flip the model
3992 	entity->parent = players[player]->entity->getUID();
3993 	entity->sizex = 4;
3994 	entity->sizey = 4;
3995 	entity->skill[11] = item->status;
3996 	entity->skill[12] = item->beatitude;
3997 	entity->skill[14] = item->appearance;
3998 	entity->skill[15] = item->identified;
3999 	entity->skill[17] = players[player]->entity->skill[2];
4000 	messagePlayer(player, language[906]);
4001 	consumeItem(item, player);
4002 	return;
4003 }
4004 
item_Food(Item * & item,int player)4005 void item_Food(Item*& item, int player)
4006 {
4007 	int oldcount;
4008 	int pukeChance;
4009 
4010 	if ( !stats[player] )
4011 	{
4012 		return;
4013 	}
4014 
4015 	if ( player >= 0 && stats[player]->type == AUTOMATON )
4016 	{
4017 		if ( players[player] && players[player]->entity )
4018 		{
4019 			item_FoodAutomaton(item, player);
4020 		}
4021 		return;
4022 	}
4023 
4024 	if ( player >= 0 && stats[player]->type != HUMAN && (svFlags & SV_FLAG_HUNGER) ) // hunger on
4025 	{
4026 		if ( stats[player]->type == SKELETON )
4027 		{
4028 			if ( player == clientnum )
4029 			{
4030 				steamAchievement("BARONY_ACH_BONEHEADED");
4031 				dropItem(item, player); // client drop item
4032 				messagePlayer(clientnum, language[3179]);
4033 			}
4034 			return;
4035 		}
4036 	}
4037 
4038 	if ( stats[player]->amulet != NULL )
4039 	{
4040 		if ( stats[player]->amulet->type == AMULET_STRANGULATION )
4041 		{
4042 			if ( player == clientnum )
4043 			{
4044 				messagePlayer(player, language[756]);
4045 			}
4046 			return;
4047 		}
4048 	}
4049 
4050 	// can't eat while vomiting
4051 	if ( stats[player]->EFFECTS[EFF_VOMITING] )
4052 	{
4053 		if ( player == clientnum )
4054 		{
4055 			messagePlayer(player, language[757]);
4056 		}
4057 		return;
4058 	}
4059 
4060 	if ( player == clientnum )
4061 	{
4062 		conductFoodless = false;
4063 		if ( item->type == FOOD_MEAT || item->type == FOOD_FISH || item->type == FOOD_TOMALLEY || item->type == FOOD_BLOOD )
4064 		{
4065 			conductVegetarian = false;
4066 		}
4067 		if ( stats[player]->playerRace == RACE_SKELETON && stats[player]->appearance == 0
4068 			&& players[player] && players[player]->entity->effectPolymorph > NUMMONSTERS )
4069 		{
4070 			steamAchievement("BARONY_ACH_MUSCLE_MEMORY");
4071 		}
4072 	}
4073 
4074 	if ( multiplayer == CLIENT )
4075 	{
4076 		consumeItem(item, player);
4077 		return;
4078 	}
4079 
4080 	// consumption message
4081 	oldcount = item->count;
4082 	item->count = 1;
4083 	messagePlayer(player, language[907], item->description());
4084 	item->count = oldcount;
4085 
4086 	// eating sound
4087 	if ( item->type == FOOD_BLOOD )
4088 	{
4089 		// play drink sound
4090 		playSoundEntity(players[player]->entity, 52, 64);
4091 	}
4092 	else
4093 	{
4094 		playSoundEntity(players[player]->entity, 50 + rand() % 2, 64);
4095 	}
4096 
4097 	// chance of rottenness
4098 	switch ( item->status )
4099 	{
4100 		case EXCELLENT:
4101 			pukeChance = 100;
4102 			break;
4103 		case SERVICABLE:
4104 			pukeChance = 25;
4105 			break;
4106 		case WORN:
4107 			pukeChance = 10;
4108 			break;
4109 		case DECREPIT:
4110 			pukeChance = 4;
4111 			break;
4112 		default:
4113 			pukeChance = 100;
4114 			break;
4115 	}
4116 
4117 	if ( players[player]
4118 		&& players[player]->entity && players[player]->entity->playerRequiresBloodToSustain() )
4119 	{
4120 		if ( item->type == FOOD_BLOOD )
4121 		{
4122 			pukeChance = 100;
4123 		}
4124 		else if ( item->type != FOOD_BLOOD )
4125 		{
4126 			if ( stats[player]->type == VAMPIRE )
4127 			{
4128 				pukeChance = 1;
4129 			}
4130 		}
4131 	}
4132 	else if ( item->type == FOOD_BLOOD )
4133 	{
4134 		pukeChance = 1;
4135 	}
4136 
4137 	if ( players[player] && players[player]->entity && players[player]->entity->effectShapeshift != NOTHING )
4138 	{
4139 		pukeChance = 100; // shapeshifted players don't puke
4140 	}
4141 	if ( player >= 0 && stats[player]->type == INSECTOID )
4142 	{
4143 		pukeChance = 100; // insectoids can eat anything.
4144 	}
4145 
4146 	if (((item->beatitude < 0 && item->type != FOOD_CREAMPIE) || (rand() % pukeChance == 0)) && pukeChance < 100)
4147 	{
4148 		if (players[player] && players[player]->entity && !(svFlags & SV_FLAG_HUNGER))
4149 		{
4150 			playSoundEntity(players[player]->entity, 28, 64);
4151 			players[player]->entity->modHP(-5);
4152 		}
4153 		if ( stats[player]->type == VAMPIRE )
4154 		{
4155 			messagePlayer(player, language[3201]);
4156 		}
4157 		else if ( item->type == FOOD_BLOOD )
4158 		{
4159 			messagePlayer(player, language[3203]);
4160 		}
4161 		else
4162 		{
4163 			messagePlayer(player, language[908]);
4164 		}
4165 		if ( stats[player] && players[player] && players[player]->entity )
4166 		{
4167 			if ( stats[player]->type != SKELETON
4168 				&& players[player]->entity->effectShapeshift == NOTHING
4169 				&& stats[player]->type != AUTOMATON )
4170 			{
4171 				players[player]->entity->skill[26] = 40 + rand() % 10;
4172 			}
4173 		}
4174 		consumeItem(item, player);
4175 		return;
4176 	}
4177 	if ( item->beatitude < 0 && item->type == FOOD_CREAMPIE )
4178 	{
4179 		messagePlayer(player, language[909]);
4180 		messagePlayer(player, language[910]);
4181 		stats[player]->EFFECTS[EFF_MESSY] = true;
4182 		stats[player]->EFFECTS_TIMERS[EFF_MESSY] = 600; // ten seconds
4183 		serverUpdateEffects(player);
4184 		consumeItem(item, player);
4185 		return;
4186 	}
4187 
4188 	// replenish nutrition points
4189 	if ( svFlags & SV_FLAG_HUNGER )
4190 	{
4191 		int hungerIncrease = 10;
4192 		switch ( item->type )
4193 		{
4194 			case FOOD_BREAD:
4195 				hungerIncrease = 400;
4196 				break;
4197 			case FOOD_CREAMPIE:
4198 				hungerIncrease = 200;
4199 				break;
4200 			case FOOD_CHEESE:
4201 				hungerIncrease = 100;
4202 				break;
4203 			case FOOD_APPLE:
4204 				hungerIncrease = 200;
4205 				break;
4206 			case FOOD_MEAT:
4207 				hungerIncrease = 600;
4208 				break;
4209 			case FOOD_FISH:
4210 				hungerIncrease = 500;
4211 				break;
4212 			case FOOD_TOMALLEY:
4213 				hungerIncrease = 400;
4214 				break;
4215 			case FOOD_BLOOD:
4216 				if ( players[player] && players[player]->entity
4217 					&& players[player]->entity->playerRequiresBloodToSustain() )
4218 				{
4219 					hungerIncrease = 250;
4220 				}
4221 				else
4222 				{
4223 					hungerIncrease = 10;
4224 				}
4225 				break;
4226 			default:
4227 				hungerIncrease = 10;
4228 				break;
4229 		}
4230 		stats[player]->HUNGER += hungerIncrease;
4231 	}
4232 	else
4233 	{
4234 		if (players[player] && players[player]->entity)
4235 		{
4236 			players[player]->entity->modHP(5);
4237 			messagePlayer(player, language[911]);
4238 
4239 
4240 			if ( stats[player]->playerRace == RACE_INSECTOID && stats[player]->appearance == 0 )
4241 			{
4242 				real_t manaRegenPercent = 0.f;
4243 				switch ( item->type )
4244 				{
4245 					case FOOD_BREAD:
4246 					case FOOD_TOMALLEY:
4247 						manaRegenPercent = 0.4;
4248 						break;
4249 					case FOOD_CREAMPIE:
4250 						manaRegenPercent = 0.2;
4251 						break;
4252 					case FOOD_CHEESE:
4253 						manaRegenPercent = 0.1;
4254 						break;
4255 					case FOOD_APPLE:
4256 						manaRegenPercent = 0.2;
4257 						break;
4258 					case FOOD_MEAT:
4259 					case FOOD_FISH:
4260 						manaRegenPercent = 0.5;
4261 						break;
4262 					case FOOD_BLOOD:
4263 						if ( players[player] && players[player]->entity
4264 							&& players[player]->entity->playerRequiresBloodToSustain() )
4265 						{
4266 							manaRegenPercent = 0.25;
4267 						}
4268 						else
4269 						{
4270 							manaRegenPercent = 0.1;
4271 						}
4272 						break;
4273 					default:
4274 						break;
4275 				}
4276 				int manaAmount = stats[player]->MAXMP * manaRegenPercent;
4277 				players[player]->entity->modMP(manaAmount);
4278 			}
4279 		}
4280 	}
4281 
4282 	if ( item->type == FOOD_TOMALLEY )
4283 	{
4284 		serverUpdatePlayerGameplayStats(player, STATISTICS_TEMPT_FATE, 1);
4285 	}
4286 
4287 	// results of eating
4288 	if ( players[player] )
4289 	{
4290 		updateHungerMessages(players[player]->entity, stats[player], item);
4291 	}
4292 	consumeItem(item, player);
4293 }
4294 
item_FoodTin(Item * & item,int player)4295 void item_FoodTin(Item*& item, int player)
4296 {
4297 	int oldcount;
4298 	int pukeChance;
4299 	bool slippery = false;
4300 
4301 	if ( player >= 0 && stats[player]->type == AUTOMATON )
4302 	{
4303 		if ( players[player] && players[player]->entity )
4304 		{
4305 			item_FoodAutomaton(item, player);
4306 		}
4307 		return;
4308 	}
4309 
4310 	if ( player >= 0 && stats[player]->type != HUMAN && (svFlags & SV_FLAG_HUNGER) ) // hunger on
4311 	{
4312 		if ( stats[player]->type == SKELETON )
4313 		{
4314 			if ( player == clientnum )
4315 			{
4316 				steamAchievement("BARONY_ACH_BONEHEADED");
4317 				dropItem(item, player); // client drop item
4318 				messagePlayer(clientnum, language[3179]);
4319 			}
4320 			return;
4321 		}
4322 	}
4323 
4324 	if ( stats[player]->amulet != NULL )
4325 	{
4326 		if ( stats[player]->amulet->type == AMULET_STRANGULATION )
4327 		{
4328 			if ( player == clientnum )
4329 			{
4330 				messagePlayer(player, language[756]);
4331 			}
4332 			return;
4333 		}
4334 	}
4335 
4336 	// can't eat while vomiting
4337 	if ( stats[player]->EFFECTS[EFF_VOMITING] )
4338 	{
4339 		if ( player == clientnum )
4340 		{
4341 			messagePlayer(player, language[757]);
4342 		}
4343 		return;
4344 	}
4345 
4346 	if ( player == clientnum )
4347 	{
4348 		conductFoodless = false;
4349 		conductVegetarian = false;
4350 		if ( stats[player]->playerRace == RACE_SKELETON && stats[player]->appearance == 0
4351 			&& players[player] && players[player]->entity->effectPolymorph > NUMMONSTERS )
4352 		{
4353 			steamAchievement("BARONY_ACH_MUSCLE_MEMORY");
4354 		}
4355 		if ( stats[player]->type == GOATMAN )
4356 		{
4357 			steamStatisticUpdate(STEAM_STAT_IRON_GUT, STEAM_STAT_INT, 1);
4358 		}
4359 	}
4360 
4361 	if ( multiplayer == CLIENT )
4362 	{
4363 		consumeItem(item, player);
4364 		return;
4365 	}
4366 
4367 	// consumption message
4368 	char tempstr[128] = { 0 };
4369 	oldcount = item->count;
4370 	item->count = 1;
4371 
4372 	bool hpBuff = false;
4373 	bool mpBuff = false;
4374 
4375 	// first word
4376 	int word = rand() % 16;
4377 	strcpy(tempstr, language[918 + word]);
4378 	if ( word == 6 || word == 15 )
4379 	{
4380 		slippery = true;
4381 	}
4382 	if ( word < 8 )
4383 	{
4384 		hpBuff = true;
4385 	}
4386 
4387 	// second word
4388 	word = rand() % 16;
4389 	strcat(tempstr, language[934 + word]);
4390 	if ( word == 1 || word == 7 || word == 8 || word == 12 )
4391 	{
4392 		slippery = true;
4393 	}
4394 	if ( word >= 8 )
4395 	{
4396 		mpBuff = true;
4397 	}
4398 
4399 	// third word
4400 	word = rand() % 16;
4401 	strcat(tempstr, language[950 + word]);
4402 	if ( word == 1 || word == 8 )
4403 	{
4404 		slippery = true;
4405 	}
4406 	if ( word == 8 )
4407 	{
4408 		hpBuff = true;
4409 		mpBuff = true;
4410 	}
4411 
4412 	if ( stats[player]->type == GOATMAN )
4413 	{
4414 		messagePlayer(player, language[3220], tempstr);
4415 	}
4416 	else
4417 	{
4418 		messagePlayer(player, language[764], tempstr);
4419 	}
4420 	item->count = oldcount;
4421 
4422 	// eating sound
4423 	playSoundEntity(players[player]->entity, 50 + rand() % 2, 64);
4424 
4425 	serverUpdatePlayerGameplayStats(player, STATISTICS_YES_WE_CAN, 1);
4426 
4427 	// chance of rottenness
4428 	switch ( item->status )
4429 	{
4430 		case EXCELLENT:
4431 			pukeChance = 100;
4432 			break;
4433 		case SERVICABLE:
4434 			pukeChance = 25;
4435 			break;
4436 		case WORN:
4437 			pukeChance = 10;
4438 			break;
4439 		case DECREPIT:
4440 			pukeChance = 3;
4441 			break;
4442 		default:
4443 			pukeChance = 100;
4444 			break;
4445 	}
4446 
4447 	if ( stats[player]->type == VAMPIRE )
4448 	{
4449 		pukeChance = 1;
4450 	}
4451 	else if ( stats[player]->type == INSECTOID )
4452 	{
4453 		pukeChance = 100; // insectoids can eat anything.
4454 	}
4455 
4456 	if ((item->beatitude < 0 || rand() % pukeChance == 0) && pukeChance < 100)
4457 	{
4458 		if (players[player] && players[player]->entity && !(svFlags & SV_FLAG_HUNGER))
4459 		{
4460 			players[player]->entity->modHP(-5);
4461 		}
4462 		if ( stats[player]->type == VAMPIRE )
4463 		{
4464 			messagePlayer(player, language[3201]);
4465 		}
4466 		else
4467 		{
4468 			messagePlayer(player, language[908]);
4469 		}
4470 
4471 		if ( stats[player] && players[player] && players[player]->entity )
4472 		{
4473 			if ( stats[player]->type != SKELETON
4474 				&& players[player]->entity->effectShapeshift == NOTHING
4475 				&& stats[player]->type != AUTOMATON )
4476 			{
4477 				players[player]->entity->skill[26] = 40 + rand() % 10;
4478 			}
4479 		}
4480 		consumeItem(item, player);
4481 		return;
4482 	}
4483 
4484 	int buffDuration = item->status * TICKS_PER_SECOND * 4; // (4 - 16 seconds)
4485 	if ( item->status > WORN )
4486 	{
4487 		buffDuration -= rand() % ((buffDuration / 2) + 1); // 50-100% duration
4488 	}
4489 	else
4490 	{
4491 		buffDuration -= rand() % ((buffDuration / 4) + 1); // 75-100% duration
4492 	}
4493 
4494 	// replenish nutrition points
4495 	if (svFlags & SV_FLAG_HUNGER)
4496 	{
4497 		stats[player]->HUNGER += 600;
4498 		stats[player]->EFFECTS[EFF_HP_REGEN] = hpBuff;
4499 		stats[player]->EFFECTS[EFF_MP_REGEN] = mpBuff;
4500 		stats[player]->EFFECTS_TIMERS[EFF_HP_REGEN] = buffDuration;
4501 		stats[player]->EFFECTS_TIMERS[EFF_MP_REGEN] = buffDuration;
4502 	}
4503 	else
4504 	{
4505 		if (players[player] && players[player]->entity)
4506 		{
4507 			players[player]->entity->modHP(5);
4508 		}
4509 		messagePlayer(player, language[911]);
4510 		if ( stats[player]->playerRace == RACE_INSECTOID && stats[player]->appearance == 0 )
4511 		{
4512 			real_t manaRegenPercent = 0.6;
4513 			int manaAmount = stats[player]->MAXMP * manaRegenPercent;
4514 			players[player]->entity->modMP(manaAmount);
4515 		}
4516 	}
4517 
4518 	// greasy fingers
4519 	if ( slippery )
4520 	{
4521 		messagePlayer(player, language[966]);
4522 		stats[player]->EFFECTS[EFF_GREASY] = true;
4523 		stats[player]->EFFECTS_TIMERS[EFF_GREASY] = TICKS_PER_SECOND * (60 + rand() % 60); // 1-2 minutes of greasy
4524 		serverUpdateEffects(player);
4525 	}
4526 
4527 	// results of eating
4528 	if ( players[player] )
4529 	{
4530 		updateHungerMessages(players[player]->entity, stats[player], item);
4531 	}
4532 
4533 	if ( (hpBuff || mpBuff) && (svFlags & SV_FLAG_HUNGER) )
4534 	{
4535 		messagePlayer(player, language[911]);
4536 	}
4537 
4538 	consumeItem(item, player);
4539 }
4540 
item_AmuletSexChange(Item * item,int player)4541 void item_AmuletSexChange(Item* item, int player)
4542 {
4543 	if ( stats[player]->amulet != NULL )
4544 	{
4545 		if ( !stats[player]->amulet->canUnequip(stats[player]) )
4546 		{
4547 			if ( player == clientnum )
4548 			{
4549 				if ( shouldInvertEquipmentBeatitude(stats[player]) && item->beatitude > 0 )
4550 				{
4551 					messagePlayer(player, language[3218]);
4552 				}
4553 				else
4554 				{
4555 					messagePlayer(player, language[1087]);
4556 				}
4557 			}
4558 			return;
4559 		}
4560 	}
4561 	stats[player]->amulet = NULL;
4562 	stats[player]->sex = static_cast<sex_t>((stats[player]->sex == 0));
4563 
4564 	if ( player != clientnum )
4565 	{
4566 		return;
4567 	}
4568 	if ( stats[player]->sex == MALE )
4569 	{
4570 		messagePlayer(player, language[967]);
4571 	}
4572 	else
4573 	{
4574 		messagePlayer(player, language[968]);
4575 	}
4576 	messagePlayer(player, language[969]);
4577 }
4578 
item_Spellbook(Item * & item,int player)4579 void item_Spellbook(Item*& item, int player)
4580 {
4581 	node_t* node, *nextnode;
4582 
4583 	item->identified = true;
4584 	if (player != clientnum)
4585 	{
4586 		return;
4587 	}
4588 
4589 	if (players[player]->entity->isBlind())
4590 	{
4591 		messagePlayer(player, language[970]);
4592 		return;
4593 	}
4594 	if ( itemIsEquipped(item, clientnum) )
4595 	{
4596 		messagePlayer(player, language[3460]);
4597 		return;
4598 	}
4599 
4600 	if ( players[player] && players[player]->entity )
4601 	{
4602 		if ( players[player]->entity->effectShapeshift != NOTHING )
4603 		{
4604 			messagePlayer(player, language[3445]);
4605 			return;
4606 		}
4607 		else if ( stats[player] && (stats[player]->type == GOBLIN || (stats[player]->playerRace == RACE_GOBLIN && stats[player]->appearance == 0)) )
4608 		{
4609 			messagePlayer(player, language[3444]);
4610 			return;
4611 		}
4612 	}
4613 
4614 	conductIlliterate = false;
4615 
4616 	if ( item->beatitude < 0 && !shouldInvertEquipmentBeatitude(stats[player]) )
4617 	{
4618 		messagePlayer(clientnum, language[971]);
4619 		if ( list_Size(&spellList) > 0 && stats[player]->type != AUTOMATON )
4620 		{
4621 			// randomly delete a spell
4622 			int spellToDelete = rand() % list_Size(&spellList);
4623 			node = list_Node(&spellList, spellToDelete);
4624 			spell_t* spell = (spell_t*)node->element;
4625 			int spellID = spell->ID;
4626 			bool deleted = false;
4627 			bool rerollSpell = false;
4628 
4629 			// delete its accompanying spell item(s)
4630 
4631 			if ( client_classes[clientnum] == CLASS_SHAMAN )
4632 			{
4633 				// don't forget your racial spells otherwise borked.
4634 				// special roll checking.
4635 				if ( list_Size(&spellList) <= CLASS_SHAMAN_NUM_STARTING_SPELLS )
4636 				{
4637 					// no spells to delete. return early.
4638 					messagePlayer(clientnum, language[973]);
4639 					consumeItem(item, player);
4640 					return;
4641 				}
4642 				spellToDelete = rand() % (list_Size(&spellList) - CLASS_SHAMAN_NUM_STARTING_SPELLS);
4643 				spellToDelete += CLASS_SHAMAN_NUM_STARTING_SPELLS; // e.g 16 spells is 0 + 15, 15th index.
4644 				node = list_Node(&spellList, spellToDelete);
4645 				spell = (spell_t*)node->element;
4646 				spellID = spell->ID;
4647 			}
4648 
4649 			for ( node_t* node2 = stats[player]->inventory.first; node2 != NULL; node2 = nextnode )
4650 			{
4651 				nextnode = node2->next;
4652 				Item* itemInventory = (Item*)node2->element;
4653 				if ( itemInventory && itemInventory->type == SPELL_ITEM )
4654 				{
4655 					if ( rerollSpell )
4656 					{
4657 						// Unused. But if ever shapeshift form spells get added to general classes then will need this checking.
4658 						//if ( itemInventory->appearance < 1000 )
4659 						//{
4660 						//	// can delete non-shapeshift spells. let's delete this one.
4661 						//	spell = getSpellFromItem(itemInventory);
4662 						//	if ( spell )
4663 						//	{
4664 						//		spellID = spell->ID;
4665 						//		if ( spellID == SPELL_RAT_FORM || spellID == SPELL_SPIDER_FORM
4666 						//			|| spellID == SPELL_TROLL_FORM || spellID == SPELL_IMP_FORM
4667 						//			|| spellID == SPELL_REVERT_FORM )
4668 						//		{
4669 						//			continue;
4670 						//		}
4671 						//		// find the node in spellList for the ID
4672 						//		spellToDelete = 0;
4673 						//		for ( node_t* tmpNode = spellList.first; tmpNode != nullptr; tmpNode = tmpNode->next )
4674 						//		{
4675 						//			if ( tmpNode->element )
4676 						//			{
4677 						//				spell_t* tmpSpell = (spell_t*)tmpNode->element;
4678 						//				if ( tmpSpell && tmpSpell->ID == spellID )
4679 						//				{
4680 						//					// found the node in the list, delete this one.
4681 						//					node = list_Node(&spellList, spellToDelete);
4682 						//					list_RemoveNode(node2); // delete inventory spell.
4683 						//					deleted = true;
4684 						//					break;
4685 						//				}
4686 						//			}
4687 						//			++spellToDelete;
4688 						//		}
4689 						//		if ( deleted )
4690 						//		{
4691 						//			break;
4692 						//		}
4693 						//	}
4694 						//}
4695 					}
4696 					else if ( itemInventory->appearance == spellID )
4697 					{
4698 						list_RemoveNode(node2); // delete inventory spell.
4699 						deleted = true;
4700 						break;
4701 					}
4702 				}
4703 			}
4704 
4705 			//messagePlayer(0, "%d, %d %d", rerollSpell, spellToDelete, deleted);
4706 
4707 			if ( !deleted )
4708 			{
4709 				// maybe we've got an inventory full of shapeshift spells?
4710 				messagePlayer(clientnum, language[973]);
4711 				consumeItem(item, player);
4712 				return;
4713 			}
4714 			else if ( deleted )
4715 			{
4716 				messagePlayer(clientnum, language[972]);
4717 				if ( spell == selected_spell )
4718 				{
4719 					selected_spell = nullptr;
4720 				}
4721 				for ( int i = 0; i < NUM_HOTBAR_ALTERNATES; ++i )
4722 				{
4723 					if ( selected_spell_alternate[i] == spell )
4724 					{
4725 						selected_spell_alternate[i] = nullptr;
4726 					}
4727 				}
4728 				list_RemoveNode(node);
4729 			}
4730 		}
4731 		else
4732 		{
4733 			messagePlayer(clientnum, language[973]);
4734 		}
4735 		consumeItem(item, player);
4736 		return;
4737 	}
4738 	else
4739 	{
4740 		bool learned = false;
4741 		switch ( item->type )
4742 		{
4743 			case SPELLBOOK_FORCEBOLT:
4744 				learned = addSpell(SPELL_FORCEBOLT, player);
4745 				break;
4746 			case SPELLBOOK_MAGICMISSILE:
4747 				learned = addSpell(SPELL_MAGICMISSILE, player);
4748 				break;
4749 			case SPELLBOOK_COLD:
4750 				learned = addSpell(SPELL_COLD, player);
4751 				break;
4752 			case SPELLBOOK_FIREBALL:
4753 				learned = addSpell(SPELL_FIREBALL, player);
4754 				break;
4755 			case SPELLBOOK_LIGHTNING:
4756 				learned = addSpell(SPELL_LIGHTNING, player);
4757 				break;
4758 			case SPELLBOOK_REMOVECURSE:
4759 				learned = addSpell(SPELL_REMOVECURSE, player);
4760 				break;
4761 			case SPELLBOOK_LIGHT:
4762 				learned = addSpell(SPELL_LIGHT, player);
4763 				break;
4764 			case SPELLBOOK_IDENTIFY:
4765 				learned = addSpell(SPELL_IDENTIFY, player);
4766 				break;
4767 			case SPELLBOOK_MAGICMAPPING:
4768 				learned = addSpell(SPELL_MAGICMAPPING, player);
4769 				break;
4770 			case SPELLBOOK_SLEEP:
4771 				learned = addSpell(SPELL_SLEEP, player);
4772 				break;
4773 			case SPELLBOOK_CONFUSE:
4774 				learned = addSpell(SPELL_CONFUSE, player);
4775 				break;
4776 			case SPELLBOOK_SLOW:
4777 				learned = addSpell(SPELL_SLOW, player);
4778 				break;
4779 			case SPELLBOOK_OPENING:
4780 				learned = addSpell(SPELL_OPENING, player);
4781 				break;
4782 			case SPELLBOOK_LOCKING:
4783 				learned = addSpell(SPELL_LOCKING, player);
4784 				break;
4785 			case SPELLBOOK_LEVITATION:
4786 				learned = addSpell(SPELL_LEVITATION, player);
4787 				break;
4788 			case SPELLBOOK_INVISIBILITY:
4789 				learned = addSpell(SPELL_INVISIBILITY, player);
4790 				break;
4791 			case SPELLBOOK_TELEPORTATION:
4792 				learned = addSpell(SPELL_TELEPORTATION, player);
4793 				break;
4794 			case SPELLBOOK_HEALING:
4795 				learned = addSpell(SPELL_HEALING, player);
4796 				break;
4797 			case SPELLBOOK_EXTRAHEALING:
4798 				learned = addSpell(SPELL_EXTRAHEALING, player);
4799 				break;
4800 			case SPELLBOOK_CUREAILMENT:
4801 				learned = addSpell(SPELL_CUREAILMENT, player);
4802 				break;
4803 			case SPELLBOOK_DIG:
4804 				learned = addSpell(SPELL_DIG, player);
4805 				break;
4806 			case SPELLBOOK_SUMMON:
4807 				learned = addSpell(SPELL_SUMMON, player);
4808 				break;
4809 			case SPELLBOOK_STONEBLOOD:
4810 				learned = addSpell(SPELL_STONEBLOOD, player);
4811 				break;
4812 			case SPELLBOOK_BLEED:
4813 				learned = addSpell(SPELL_BLEED, player);
4814 				break;
4815 			case SPELLBOOK_REFLECT_MAGIC:
4816 				learned = addSpell(SPELL_REFLECT_MAGIC, player);
4817 				break;
4818 			case SPELLBOOK_ACID_SPRAY:
4819 				learned = addSpell(SPELL_ACID_SPRAY, player);
4820 				break;
4821 			case SPELLBOOK_STEAL_WEAPON:
4822 				learned = addSpell(SPELL_STEAL_WEAPON, player);
4823 				break;
4824 			case SPELLBOOK_DRAIN_SOUL:
4825 				learned = addSpell(SPELL_DRAIN_SOUL, player);
4826 				break;
4827 			case SPELLBOOK_VAMPIRIC_AURA:
4828 				learned = addSpell(SPELL_VAMPIRIC_AURA, player);
4829 				break;
4830 			case SPELLBOOK_CHARM_MONSTER:
4831 				learned = addSpell(SPELL_CHARM_MONSTER, player);
4832 				break;
4833 			case SPELLBOOK_REVERT_FORM:
4834 				learned = addSpell(SPELL_REVERT_FORM, player);
4835 				break;
4836 			case SPELLBOOK_RAT_FORM:
4837 				learned = addSpell(SPELL_RAT_FORM, player);
4838 				break;
4839 			case SPELLBOOK_SPIDER_FORM:
4840 				learned = addSpell(SPELL_SPIDER_FORM, player);
4841 				break;
4842 			case SPELLBOOK_TROLL_FORM:
4843 				learned = addSpell(SPELL_TROLL_FORM, player);
4844 				break;
4845 			case SPELLBOOK_IMP_FORM:
4846 				learned = addSpell(SPELL_IMP_FORM, player);
4847 				break;
4848 			case SPELLBOOK_SPRAY_WEB:
4849 				learned = addSpell(SPELL_SPRAY_WEB, player);
4850 				break;
4851 			case SPELLBOOK_POISON:
4852 				learned = addSpell(SPELL_POISON, player);
4853 				break;
4854 			case SPELLBOOK_SPEED:
4855 				learned = addSpell(SPELL_SPEED, player);
4856 				break;
4857 			case SPELLBOOK_FEAR:
4858 				learned = addSpell(SPELL_FEAR, player);
4859 				break;
4860 			case SPELLBOOK_STRIKE:
4861 				learned = addSpell(SPELL_STRIKE, player);
4862 				break;
4863 			case SPELLBOOK_DETECT_FOOD:
4864 				learned = addSpell(SPELL_DETECT_FOOD, player);
4865 				break;
4866 			case SPELLBOOK_WEAKNESS:
4867 				learned = addSpell(SPELL_WEAKNESS, player);
4868 				break;
4869 			case SPELLBOOK_AMPLIFY_MAGIC:
4870 				learned = addSpell(SPELL_AMPLIFY_MAGIC, player);
4871 				break;
4872 			case SPELLBOOK_SHADOW_TAG:
4873 				learned = addSpell(SPELL_SHADOW_TAG, player);
4874 				break;
4875 			case SPELLBOOK_TELEPULL:
4876 				learned = addSpell(SPELL_TELEPULL, player);
4877 				break;
4878 			case SPELLBOOK_DEMON_ILLU:
4879 				learned = addSpell(SPELL_DEMON_ILLUSION, player);
4880 				break;
4881 			case SPELLBOOK_TROLLS_BLOOD:
4882 				learned = addSpell(SPELL_TROLLS_BLOOD, player);
4883 				break;
4884 			case SPELLBOOK_SALVAGE:
4885 				learned = addSpell(SPELL_SALVAGE, player);
4886 				break;
4887 			case SPELLBOOK_FLUTTER:
4888 				learned = addSpell(SPELL_FLUTTER, player);
4889 				break;
4890 			case SPELLBOOK_DASH:
4891 				learned = addSpell(SPELL_DASH, player);
4892 				break;
4893 			case SPELLBOOK_SELF_POLYMORPH:
4894 				learned = addSpell(SPELL_SELF_POLYMORPH, player);
4895 				break;
4896 			case SPELLBOOK_9:
4897 				learned = addSpell(SPELL_9, player);
4898 				break;
4899 			case SPELLBOOK_10:
4900 				learned = addSpell(SPELL_10, player);
4901 				break;
4902 			default:
4903 				learned = addSpell(SPELL_FORCEBOLT, player);
4904 				break;
4905 		}
4906 
4907 		if ( learned )
4908 		{
4909 			if ( item->type >= SPELLBOOK_RAT_FORM && item->type <= SPELLBOOK_IMP_FORM )
4910 			{
4911 				ItemType originalSpellbook = item->type;
4912 				item->type = SPELLBOOK_REVERT_FORM;
4913 				if ( !playerLearnedSpellbook(item) ) // have we learnt "revert form"?
4914 				{
4915 					addSpell(SPELL_REVERT_FORM, player, true); // add it.
4916 				}
4917 				item->type = originalSpellbook;
4918 			}
4919 			item->status = static_cast<Status>(item->status - 1);
4920 			if ( item->status != BROKEN )
4921 			{
4922 				messagePlayer(player, language[2595]);
4923 			}
4924 			else
4925 			{
4926 				messagePlayer(player, language[2596]);
4927 				consumeItem(item, player);
4928 			}
4929 
4930 			if ( stats[player] && stats[player]->playerRace == RACE_INSECTOID && stats[player]->appearance == 0 )
4931 			{
4932 				steamStatisticUpdate(STEAM_STAT_BOOKWORM, STEAM_STAT_INT, 1);
4933 			}
4934 			if ( list_Size(&spellList) >= 20 )
4935 			{
4936 				steamAchievement("BARONY_ACH_MAGIC_MASTERY");
4937 			}
4938 		}
4939 	}
4940 }
4941 
item_FoodAutomaton(Item * & item,int player)4942 void item_FoodAutomaton(Item*& item, int player)
4943 {
4944 	if ( !stats[player] || !players[player] || !players[player]->entity )
4945 	{
4946 		return;
4947 	}
4948 
4949 	if ( player >= 0 && stats[player]->type != AUTOMATON )
4950 	{
4951 		//messagePlayer(player, "Err: You are not an Automaton!");
4952 		return;
4953 	}
4954 
4955 	if ( !itemIsConsumableByAutomaton(*item)
4956 		&& item->type != POTION_FIRESTORM )
4957 	{
4958 		return;
4959 	}
4960 
4961 	if ( multiplayer == CLIENT )
4962 	{
4963 		consumeItem(item, player);
4964 		return;
4965 	}
4966 
4967 	// consumption message
4968 	if ( item->type != TOOL_MAGIC_SCRAP && item->type != TOOL_METAL_SCRAP )
4969 	{
4970 		int oldcount = item->count;
4971 		item->count = 1;
4972 		messagePlayer(player, language[907], item->description());
4973 		item->count = oldcount;
4974 	}
4975 
4976 	// eating sound
4977 	if ( item->type == FOOD_BLOOD || item->type == POTION_FIRESTORM )
4978 	{
4979 		// play drink sound
4980 		playSoundEntity(players[player]->entity, 52, 64);
4981 	}
4982 	else
4983 	{
4984 		playSoundEntity(players[player]->entity, 50 + rand() % 2, 64);
4985 	}
4986 
4987 	if ( item->beatitude < 0 && item->type == FOOD_CREAMPIE )
4988 	{
4989 		messagePlayer(player, language[909]);
4990 		messagePlayer(player, language[910]);
4991 		stats[player]->EFFECTS[EFF_MESSY] = true;
4992 		stats[player]->EFFECTS_TIMERS[EFF_MESSY] = 600; // ten seconds
4993 		serverUpdateEffects(player);
4994 		consumeItem(item, player);
4995 		return;
4996 	}
4997 
4998 	// automaton hunger/combustion tick is every 0.6 seconds.
4999 	// 600 hunger = 6 minutes
5000 	// 200 hunger = 2 minutes
5001 	// 100 hunger = 60 seconds.
5002 	// 80 hunger = 48 seconds
5003 	// 50 hunger = 30 seconds
5004 	// 40 hunger = 24 seconds
5005 	// 20 hunger = 12 seconds
5006 	int oldHunger = stats[player]->HUNGER;
5007 	Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
5008 
5009 	// replenish nutrition points
5010 	// automaton hunger is always in effect
5011 	// hunger disabled will simply add 5 HP and still add fuel to the fire.
5012 	switch ( item->type )
5013 	{
5014 		case FOOD_BREAD:
5015 		case FOOD_CREAMPIE:
5016 		case FOOD_BLOOD:
5017 		case FOOD_CHEESE:
5018 		case FOOD_APPLE:
5019 		case FOOD_TOMALLEY:
5020 		case FOOD_MEAT:
5021 		case FOOD_FISH:
5022 		case FOOD_TIN:
5023 			if ( svFlags & SV_FLAG_HUNGER )
5024 			{
5025 				messagePlayer(player, language[3697]); // no effect.
5026 				consumeItem(item, player);
5027 				return;
5028 			}
5029 			break;
5030 		case GEM_ROCK:
5031 		case GEM_GLASS:
5032 			stats[player]->HUNGER += 50;
5033 			break;
5034 		case GEM_LUCK:
5035 		case GEM_GARNET:
5036 		case GEM_RUBY:
5037 		case GEM_JACINTH:
5038 		case GEM_AMBER:
5039 		case GEM_CITRINE:
5040 		case GEM_JADE:
5041 		case GEM_EMERALD:
5042 		case GEM_SAPPHIRE:
5043 		case GEM_AQUAMARINE:
5044 		case GEM_AMETHYST:
5045 		case GEM_FLUORITE:
5046 		case GEM_OPAL:
5047 		case GEM_DIAMOND:
5048 		case GEM_JETSTONE:
5049 		case GEM_OBSIDIAN:
5050 			stats[player]->HUNGER += 1000;
5051 			players[player]->entity->modMP(10);
5052 			break;
5053 		case READABLE_BOOK:
5054 			stats[player]->HUNGER += 400;
5055 			if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5056 			{
5057 				steamStatisticUpdateClient(player, STEAM_STAT_FASCIST, STEAM_STAT_INT, 1);
5058 			}
5059 			break;
5060 		case SCROLL_MAIL:
5061 		case SCROLL_BLANK:
5062 			stats[player]->HUNGER += 200;
5063 			break;
5064 		case SCROLL_IDENTIFY:
5065 		case SCROLL_LIGHT:
5066 		case SCROLL_REMOVECURSE:
5067 		case SCROLL_FOOD:
5068 		case SCROLL_MAGICMAPPING:
5069 		case SCROLL_REPAIR:
5070 		case SCROLL_DESTROYARMOR:
5071 		case SCROLL_TELEPORTATION:
5072 		case SCROLL_SUMMON:
5073 		case SCROLL_CONJUREARROW:
5074 		case SCROLL_CHARGING:
5075 			players[player]->entity->modMP(20);
5076 			stats[player]->HUNGER += 600;
5077 			break;
5078 		case SCROLL_ENCHANTWEAPON:
5079 		case SCROLL_ENCHANTARMOR:
5080 			players[player]->entity->modMP(40);
5081 			stats[player]->HUNGER += 600;
5082 			break;
5083 		case SCROLL_FIRE:
5084 		{
5085 			stats[player]->HUNGER += 1500;
5086 			players[player]->entity->modMP(stats[player]->MAXMP);
5087 			messagePlayerColor(player, color, language[3699]); // superheats
5088 			if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5089 			{
5090 				steamStatisticUpdateClient(player, STEAM_STAT_SPICY, STEAM_STAT_INT, 1);
5091 			}
5092 
5093 			playSoundEntity(players[player]->entity, 153, 128); // "FireballExplode.ogg"
5094 			for ( int c = 0; c < 100; c++ )
5095 			{
5096 				Entity* entity = spawnFlame(players[player]->entity, SPRITE_FLAME);
5097 				entity->sprite = 16;
5098 				double vel = rand() % 10;
5099 				entity->vel_x = vel * cos(entity->yaw) * cos(entity->pitch) * .1;
5100 				entity->vel_y = vel * sin(entity->yaw) * cos(entity->pitch) * .1;
5101 				entity->vel_z = vel * sin(entity->pitch) * .2;
5102 				entity->skill[0] = 5 + rand() % 10;
5103 			}
5104 			break;
5105 		}
5106 		case TOOL_METAL_SCRAP:
5107 			if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5108 			{
5109 				achievementObserver.playerAchievements[player].trashCompactor += 1;
5110 			}
5111 			if ( stats[player]->HUNGER > 500 )
5112 			{
5113 				messagePlayer(player, language[3707]); // fails to add any more heat.
5114 				consumeItem(item, player);
5115 				return;
5116 			}
5117 			else
5118 			{
5119 				stats[player]->HUNGER += 50;
5120 				stats[player]->HUNGER = std::min(stats[player]->HUNGER, 550);
5121 			}
5122 			break;
5123 		case TOOL_MAGIC_SCRAP:
5124 			if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5125 			{
5126 				achievementObserver.playerAchievements[player].trashCompactor += 1;
5127 			}
5128 			if ( stats[player]->HUNGER > 1100 )
5129 			{
5130 				messagePlayer(player, language[3707]); // fails to add any more heat.
5131 				consumeItem(item, player);
5132 				return;
5133 			}
5134 			else
5135 			{
5136 				stats[player]->HUNGER += 100;
5137 				stats[player]->HUNGER = std::min(stats[player]->HUNGER, 1199);
5138 			}
5139 			break;
5140 		default:
5141 			messagePlayer(player, "Unknown food?");
5142 			break;
5143 	}
5144 
5145 	if ( itemCategory(item) == SCROLL )
5146 	{
5147 		if ( stats[player]->playerRace == RACE_AUTOMATON && stats[player]->appearance == 0 )
5148 		{
5149 			steamStatisticUpdateClient(player, STEAM_STAT_FASCIST, STEAM_STAT_INT, 1);
5150 		}
5151 	}
5152 
5153 	if ( !(svFlags & SV_FLAG_HUNGER) && oldHunger == stats[player]->HUNGER ) // ate food, hunger is disabled and did not gain heat (normal food items)
5154 	{
5155 		if ( players[player] && players[player]->entity )
5156 		{
5157 			if ( item->beatitude < 0 )
5158 			{
5159 				playSoundEntity(players[player]->entity, 28, 64);
5160 				players[player]->entity->modHP(-5);
5161 				messagePlayer(player, language[908]); // blecch! rotten food!
5162 				consumeItem(item, player);
5163 				return;
5164 			}
5165 
5166 			players[player]->entity->modHP(5);
5167 		}
5168 		messagePlayer(player, language[911]); // mmm, tasty!
5169 	}
5170 
5171 	stats[player]->HUNGER = std::min(stats[player]->HUNGER, 1500);
5172 	// results of eating
5173 	if ( stats[player]->HUNGER >= 1500 )
5174 	{
5175 		messagePlayerColor(player, color, language[3483]); // at capacity
5176 	}
5177 	else if ( stats[player]->HUNGER >= 1200 && oldHunger < 1200 )
5178 	{
5179 		messagePlayerColor(player, color, language[3484]);
5180 	}
5181 	else if ( stats[player]->HUNGER >= 600 && oldHunger < 600 )
5182 	{
5183 		messagePlayerColor(player, color, language[3696]);
5184 	}
5185 	else if ( stats[player]->HUNGER >= 300 && oldHunger < 300 )
5186 	{
5187 		messagePlayerColor(player, color, language[3485]);
5188 	}
5189 	else if ( stats[player]->HUNGER <= 300 )
5190 	{
5191 		messagePlayerColor(player, color, language[3486]);
5192 	}
5193 	else if ( oldHunger < stats[player]->HUNGER )
5194 	{
5195 		messagePlayer(player, language[3704]);
5196 	}
5197 
5198 	serverUpdateHunger(player);
5199 	consumeItem(item, player);
5200 }
5201 
itemIsConsumableByAutomaton(const Item & item)5202 bool itemIsConsumableByAutomaton(const Item& item)
5203 {
5204 	switch ( item.type )
5205 	{
5206 		case FOOD_BREAD:
5207 		case FOOD_CREAMPIE:
5208 		case FOOD_BLOOD:
5209 		case FOOD_CHEESE:
5210 		case FOOD_APPLE:
5211 		case FOOD_TOMALLEY:
5212 		case FOOD_MEAT:
5213 		case FOOD_FISH:
5214 		case FOOD_TIN:
5215 
5216 		case GEM_ROCK:
5217 		case GEM_GLASS:
5218 		case GEM_LUCK:
5219 		case GEM_GARNET:
5220 		case GEM_RUBY:
5221 		case GEM_JACINTH:
5222 		case GEM_AMBER:
5223 		case GEM_CITRINE:
5224 		case GEM_JADE:
5225 		case GEM_EMERALD:
5226 		case GEM_SAPPHIRE:
5227 		case GEM_AQUAMARINE:
5228 		case GEM_AMETHYST:
5229 		case GEM_FLUORITE:
5230 		case GEM_OPAL:
5231 		case GEM_DIAMOND:
5232 		case GEM_JETSTONE:
5233 		case GEM_OBSIDIAN:
5234 
5235 		case READABLE_BOOK:
5236 
5237 		case SCROLL_MAIL:
5238 		case SCROLL_BLANK:
5239 		case SCROLL_IDENTIFY:
5240 		case SCROLL_LIGHT:
5241 		case SCROLL_ENCHANTWEAPON:
5242 		case SCROLL_ENCHANTARMOR:
5243 		case SCROLL_REMOVECURSE:
5244 		case SCROLL_FOOD:
5245 		case SCROLL_MAGICMAPPING:
5246 		case SCROLL_REPAIR:
5247 		case SCROLL_DESTROYARMOR:
5248 		case SCROLL_TELEPORTATION:
5249 		case SCROLL_SUMMON:
5250 		case SCROLL_FIRE:
5251 		case SCROLL_CONJUREARROW:
5252 		case SCROLL_CHARGING:
5253 		case TOOL_MAGIC_SCRAP:
5254 		case TOOL_METAL_SCRAP:
5255 			return true;
5256 			break;
5257 		default:
5258 			return false;
5259 			break;
5260 	}
5261 	return false;
5262 }
5263 
updateHungerMessages(Entity * my,Stat * myStats,Item * eaten)5264 void updateHungerMessages(Entity* my, Stat* myStats, Item* eaten)
5265 {
5266 	if ( !myStats || !eaten || !my)
5267 	{
5268 		return;
5269 	}
5270 	if ( my->behavior != &actPlayer )
5271 	{
5272 		return;
5273 	}
5274 	if ( (svFlags & SV_FLAG_HUNGER) )
5275 	{
5276 		if ( myStats->HUNGER <= 250 )
5277 		{
5278 			messagePlayer(my->skill[2], language[912]);
5279 		}
5280 		else if ( myStats->HUNGER < 500 )
5281 		{
5282 			messagePlayer(my->skill[2], language[913]);
5283 		}
5284 		else if ( myStats->HUNGER < 1000 )
5285 		{
5286 			messagePlayer(my->skill[2], language[914], eaten->getName());
5287 		}
5288 		else if ( myStats->HUNGER < 1500 )
5289 		{
5290 			messagePlayer(my->skill[2], language[915]);
5291 		}
5292 		else if ( myStats->HUNGER >= 1500 )
5293 		{
5294 			if ( my->effectShapeshift != NOTHING )
5295 			{
5296 				messagePlayer(my->skill[2], language[916]); // shapeshifted players don't puke
5297 			}
5298 			else if ( rand() % 3 )
5299 			{
5300 				messagePlayer(my->skill[2], language[916]);
5301 			}
5302 			else
5303 			{
5304 				messagePlayer(my->skill[2], language[917]);
5305 				if ( myStats->type != SKELETON && myStats->type != AUTOMATON )
5306 				{
5307 					my->skill[26] = 40 + rand() % 10;
5308 				}
5309 			}
5310 		}
5311 	}
5312 
5313 	if ( myStats->type == INSECTOID )
5314 	{
5315 		myStats->HUNGER = std::min(myStats->HUNGER, 1000); // smaller hunger range.
5316 	}
5317 	else
5318 	{
5319 		myStats->HUNGER = std::min(myStats->HUNGER, 2000);
5320 	}
5321 	serverUpdateHunger(my->skill[2]);
5322 }